|
7 | 7 | Each layer overrides the one below it. Unset fields inherit from the layer below: |
8 | 8 |
|
9 | 9 | ``` |
10 | | -1. ~/.odek/config.json ← Global defaults (shared across projects) |
11 | | -2. ./odek.json ← Project-specific overrides |
12 | | -3. ODEK_* env vars ← Runtime/environment overrides |
13 | | -4. CLI flags ← Explicit invocation (highest priority) |
| 10 | +0. ~/.odek/secrets.env ← Auto-loaded into process environment on startup |
| 11 | +1. ~/.odek/config.json ← Global defaults (shared across projects) |
| 12 | +2. ./odek.json ← Project-specific overrides |
| 13 | +3. ODEK_* env vars ← Runtime/environment overrides |
| 14 | +4. CLI flags ← Explicit invocation (highest priority) |
14 | 15 | ``` |
15 | 16 |
|
| 17 | +Layer 0 is unique: it does not hold config fields directly. Instead it injects |
| 18 | +`KEY=VALUE` pairs into the process environment so they're available for: |
| 19 | + |
| 20 | +- **Layer 1–2** `${VAR}` substitution in config files |
| 21 | +- **Layer 3** `ODEK_*` env var lookups (e.g. `ODEK_API_KEY`) |
| 22 | +- **Legacy fallbacks** like `DEEPSEEK_API_KEY` / `OPENAI_API_KEY` |
| 23 | + |
16 | 24 | ## Config files |
17 | 25 |
|
18 | 26 | ### Global defaults (`~/.odek/config.json`) |
@@ -48,6 +56,33 @@ Same schema as global. Only set the fields you want to override: |
48 | 56 |
|
49 | 57 | Both files are optional. Missing files are silently ignored. String values support `${VAR}` environment variable substitution — useful for API keys without plaintext storage. |
50 | 58 |
|
| 59 | +## Secrets file (`~/.odek/secrets.env`) |
| 60 | + |
| 61 | +Auto-loaded on every `odek` invocation before any config file or env var is read. |
| 62 | +Each `KEY=VALUE` line is injected into the process environment via `os.Setenv`. |
| 63 | + |
| 64 | +``` |
| 65 | +ODEK_API_KEY=sk-... |
| 66 | +GITHUB_TOKEN=ghp_... |
| 67 | +``` |
| 68 | + |
| 69 | +Rules: |
| 70 | +- **File format:** `KEY=VALUE` — one per line, no `export` keyword needed |
| 71 | +- **Blank lines and `#` comments** are skipped |
| 72 | +- **Existing env vars are NOT overwritten** — if `ODEK_API_KEY` is already in the environment, the file is ignored for that key |
| 73 | +- **Missing/unreadable file** is silently ignored (not an error) |
| 74 | +- **Permissions:** keep `0600` (`chmod 600 ~/.odek/secrets.env`) |
| 75 | + |
| 76 | +This lets you keep secrets out of config files entirely: |
| 77 | + |
| 78 | +```json |
| 79 | +// ~/.odek/config.json — no plaintext secrets |
| 80 | +{ |
| 81 | + "model": "deepseek-v4-flash", |
| 82 | + "api_key": "${ODEK_API_KEY}" // ← resolved from secrets.env at runtime |
| 83 | +} |
| 84 | +``` |
| 85 | + |
51 | 86 | ## Environment variables |
52 | 87 |
|
53 | 88 | Every config knob has a `ODEK_*` counterpart: |
@@ -241,8 +276,9 @@ odek init --force |
241 | 276 | ## Quick examples |
242 | 277 |
|
243 | 278 | ```bash |
244 | | -# Set API key via environment variable (recommended — keeps secrets out of config files) |
245 | | -export ODEK_API_KEY="sk-..." |
| 279 | +# Set API key via secrets.env (recommended — keeps secrets out of config files) |
| 280 | +echo 'ODEK_API_KEY="sk-..."' >> ~/.odek/secrets.env |
| 281 | +chmod 600 ~/.odek/secrets.env |
246 | 282 |
|
247 | 283 | # Global config (model and other settings only, no secrets) |
248 | 284 | echo '{"model": "deepseek-v4-flash"}' > ~/.odek/config.json |
|
0 commit comments