Skip to content

Commit 3c35061

Browse files
cpcloudclaude
andcommitted
feat(config): derive env var names from dotted config paths
Make the dotted TOML path the single source of truth for env var names: MICASA_ + UPPER(key with "." replaced by "_"). Users can now look at any config key and immediately know its env var without consulting a table. Remove all `env:"..."` struct tags and derive names at runtime via EnvVarName(). Refactor migrateRenamedEnvVars as a table-driven function returning an overrides map (no os.Setenv mutation). Rename extraction.max_extract_pages to extraction.max_pages. Env vars that changed (old names accepted with deprecation warnings): - MICASA_CURRENCY -> MICASA_LOCALE_CURRENCY - MICASA_MAX_DOCUMENT_SIZE -> MICASA_DOCUMENTS_MAX_FILE_SIZE - MICASA_CACHE_TTL -> MICASA_DOCUMENTS_CACHE_TTL - MICASA_CACHE_TTL_DAYS -> MICASA_DOCUMENTS_CACHE_TTL_DAYS - MICASA_FILE_PICKER_DIR -> MICASA_DOCUMENTS_FILE_PICKER_DIR - MICASA_MAX_EXTRACT_PAGES -> MICASA_EXTRACTION_MAX_PAGES - MICASA_TEXT_TIMEOUT -> MICASA_EXTRACTION_TEXT_TIMEOUT - MICASA_EXTRACTION_MAX_EXTRACT_PAGES -> MICASA_EXTRACTION_MAX_PAGES Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 3bc8003 commit 3c35061

10 files changed

Lines changed: 376 additions & 194 deletions

File tree

.claude/codebase/types.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,12 +120,12 @@ Col* (e.g., ColID = "id", ColName = "name", ColDeletedAt = "deleted_at")
120120
- LLM (provider, model, baseURL, apiKey, timeout, thinking, extraContext)
121121
- Chat/Extraction overrides (LLMChatOverride, LLMExtractionOverride)
122122
- Documents (MaxFileSize ByteSize, CacheTTL Duration)
123-
- Extraction (MaxExtractPages int, Enabled *bool, TextTimeout, LLMTimeout)
123+
- Extraction (MaxPages int, Enabled *bool, TextTimeout, LLMTimeout)
124124
- Locale (Currency string)
125125

126126
### Defaults
127127
- Provider: "ollama", Model: "qwen3", BaseURL: "http://localhost:11434"
128-
- MaxExtractPages: 20, CacheTTL: 30 days, TextTimeout: 30s, LLMTimeout: 5m
128+
- MaxPages: 20, CacheTTL: 30 days, TextTimeout: 30s, LLMTimeout: 5m
129129

130130
## LLM Types (internal/llm/)
131131

cmd/micasa/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ func (cmd *runCmd) Run() error {
160160

161161
exCfg := cfg.LLM.ExtractionConfig()
162162
extractors := extract.DefaultExtractors(
163-
cfg.Extraction.MaxExtractPages,
163+
cfg.Extraction.MaxPages,
164164
cfg.Extraction.TextTimeoutDuration(),
165165
)
166166
opts.SetExtraction(

docs/content/docs/reference/configuration.md

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ micasa backup --source /path/to/micasa.db ~/backups/snapshot.db
9292

9393
## Environment variables
9494

95+
Every config key has a corresponding environment variable derived
96+
mechanically from the dotted TOML path:
97+
98+
```
99+
MICASA_ + UPPER(dotted.path with "." replaced by "_")
100+
```
101+
102+
For example, `documents.max_file_size` becomes `MICASA_DOCUMENTS_MAX_FILE_SIZE`.
103+
You can always infer the env var name from the config key.
104+
95105
| Variable | Default | Config equivalent | Description |
96106
|----------|---------|-------------------|-------------|
97107
| `MICASA_DB_PATH` | [Platform default](#platform-data-directory) | -- | Database file path |
@@ -102,16 +112,39 @@ micasa backup --source /path/to/micasa.db ~/backups/snapshot.db
102112
| `MICASA_LLM_API_KEY` | (empty) | `llm.api_key` | LLM API key for cloud providers |
103113
| `MICASA_LLM_EXTRA_CONTEXT` | (empty) | `llm.extra_context` | Custom context appended to LLM system prompts |
104114
| `MICASA_LLM_TIMEOUT` | `5s` | `llm.timeout` | LLM operation timeout |
105-
| `MICASA_MAX_DOCUMENT_SIZE` | `50 MiB` | `documents.max_file_size` | Max document import size |
106-
| `MICASA_CACHE_TTL` | `30d` | `documents.cache_ttl` | Document cache lifetime |
107-
| `MICASA_CACHE_TTL_DAYS` | -- | `documents.cache_ttl_days` | Deprecated; use `MICASA_CACHE_TTL` |
115+
| `MICASA_LLM_THINKING` | (unset) | `llm.thinking` | Enable model thinking for chat |
116+
| `MICASA_DOCUMENTS_MAX_FILE_SIZE` | `50 MiB` | `documents.max_file_size` | Max document import size |
117+
| `MICASA_DOCUMENTS_CACHE_TTL` | `30d` | `documents.cache_ttl` | Document cache lifetime |
118+
| `MICASA_DOCUMENTS_CACHE_TTL_DAYS` | -- | `documents.cache_ttl_days` | Deprecated; use `MICASA_DOCUMENTS_CACHE_TTL` |
119+
| `MICASA_DOCUMENTS_FILE_PICKER_DIR` | (Downloads) | `documents.file_picker_dir` | Starting directory for the file picker |
108120
| `MICASA_EXTRACTION_MODEL` | (chat model) | `extraction.model` | LLM model for document extraction |
109121
| `MICASA_EXTRACTION_ENABLED` | `true` | `extraction.enabled` | Enable/disable LLM extraction |
110122
| `MICASA_EXTRACTION_THINKING` | `false` | `extraction.thinking` | Enable model thinking for extraction |
111-
| `MICASA_TEXT_TIMEOUT` | `30s` | `extraction.text_timeout` | pdftotext timeout |
112-
| `MICASA_MAX_EXTRACT_PAGES` | `0` | `extraction.max_extract_pages` | Max pages to OCR per document (0 = no limit) |
113-
| `MICASA_LLM_THINKING` | (unset) | `llm.thinking` | Enable model thinking for chat |
114-
| `MICASA_CURRENCY` | (auto-detect) | `locale.currency` | ISO 4217 currency code (e.g. `USD`, `EUR`, `GBP`) |
123+
| `MICASA_EXTRACTION_TEXT_TIMEOUT` | `30s` | `extraction.text_timeout` | pdftotext timeout |
124+
| `MICASA_EXTRACTION_MAX_PAGES` | `0` | `extraction.max_pages` | Max pages to OCR per document (0 = no limit) |
125+
| `MICASA_EXTRACTION_LLM_TIMEOUT` | `5m` | `extraction.llm_timeout` | LLM extraction timeout |
126+
| `MICASA_LOCALE_CURRENCY` | (auto-detect) | `locale.currency` | ISO 4217 currency code (e.g. `USD`, `EUR`, `GBP`) |
127+
128+
{{% details title="Deprecated env var names" closed="true" %}}
129+
130+
The following old env var names are still accepted but emit a deprecation
131+
warning. They will be removed in a future release.
132+
133+
| Old name | Replacement |
134+
|----------|-------------|
135+
| `MICASA_MAX_DOCUMENT_SIZE` | `MICASA_DOCUMENTS_MAX_FILE_SIZE` |
136+
| `MICASA_CACHE_TTL` | `MICASA_DOCUMENTS_CACHE_TTL` |
137+
| `MICASA_CACHE_TTL_DAYS` | `MICASA_DOCUMENTS_CACHE_TTL_DAYS` |
138+
| `MICASA_FILE_PICKER_DIR` | `MICASA_DOCUMENTS_FILE_PICKER_DIR` |
139+
| `MICASA_CURRENCY` | `MICASA_LOCALE_CURRENCY` |
140+
| `MICASA_EXTRACTION_MAX_EXTRACT_PAGES` | `MICASA_EXTRACTION_MAX_PAGES` |
141+
| `MICASA_MAX_EXTRACT_PAGES` | `MICASA_EXTRACTION_MAX_PAGES` |
142+
| `MICASA_TEXT_TIMEOUT` | `MICASA_EXTRACTION_TEXT_TIMEOUT` |
143+
| `MICASA_MAX_OCR_PAGES` | `MICASA_EXTRACTION_MAX_PAGES` |
144+
| `MICASA_EXTRACTION_MODEL` | `MICASA_LLM_EXTRACTION_MODEL` |
145+
| `MICASA_EXTRACTION_THINKING` | `MICASA_LLM_EXTRACTION_THINKING` |
146+
147+
{{% /details %}}
115148

116149
### `MICASA_DB_PATH`
117150

@@ -152,31 +185,31 @@ export MICASA_LLM_TIMEOUT=15s
152185
micasa # waits up to 15s for LLM server responses
153186
```
154187

155-
### `MICASA_MAX_DOCUMENT_SIZE`
188+
### `MICASA_DOCUMENTS_MAX_FILE_SIZE`
156189

157190
Sets the maximum file size for document imports, overriding the config file
158191
value. Accepts unitized strings or bare integers (bytes). Must be positive:
159192

160193
```sh
161-
export MICASA_MAX_DOCUMENT_SIZE="100 MiB"
194+
export MICASA_DOCUMENTS_MAX_FILE_SIZE="100 MiB"
162195
micasa # allows documents up to 100 MiB
163196
```
164197

165-
### `MICASA_CACHE_TTL`
198+
### `MICASA_DOCUMENTS_CACHE_TTL`
166199

167200
Sets the document cache lifetime, overriding the config file value. Accepts
168201
day-suffixed strings (`30d`), Go durations (`720h`), or bare integers
169202
(seconds). Set to `0` to disable eviction:
170203

171204
```sh
172-
export MICASA_CACHE_TTL=7d
205+
export MICASA_DOCUMENTS_CACHE_TTL=7d
173206
micasa # evicts cache entries older than 7 days
174207
```
175208

176-
### `MICASA_CACHE_TTL_DAYS`
209+
### `MICASA_DOCUMENTS_CACHE_TTL_DAYS`
177210

178-
Deprecated. Use `MICASA_CACHE_TTL` instead. Accepts a bare integer
179-
interpreted as days. Cannot be set alongside `MICASA_CACHE_TTL`.
211+
Deprecated. Use `MICASA_DOCUMENTS_CACHE_TTL` instead. Accepts a bare integer
212+
interpreted as days. Cannot be set alongside `MICASA_DOCUMENTS_CACHE_TTL`.
180213

181214
### Platform data directory
182215

@@ -274,7 +307,7 @@ model = "qwen3"
274307
# text_timeout = "30s"
275308

276309
# Maximum pages to OCR for scanned documents. 0 = no limit. Default: 0.
277-
# max_extract_pages = 0
310+
# max_pages = 0
278311

279312
# Set to false to disable LLM-powered extraction.
280313
# When disabled, no structured data is extracted from documents.
@@ -288,7 +321,7 @@ model = "qwen3"
288321
# run; after that the database value is authoritative (portable DB files keep
289322
# their currency even when opened on a machine with different locale settings).
290323
# Auto-detected from LC_MONETARY/LANG if not set. Default: USD.
291-
# Override with MICASA_CURRENCY env var.
324+
# Override with MICASA_LOCALE_CURRENCY env var.
292325
# currency = "USD"
293326
```
294327

@@ -359,7 +392,7 @@ dates, vendor matching) from uploaded documents.
359392
|-----|------|---------|-------------|
360393
| `model` | string | (chat model) | **Deprecated.** Use `[llm.extraction] model` instead. Falls back to `llm.model` if empty. |
361394
| `text_timeout` | string | `"30s"` | Max time for `pdftotext` to run. Go duration syntax, e.g. `"1m"`. Increase for very large PDFs. |
362-
| `max_extract_pages` | int | `0` | Maximum pages to OCR per scanned document. 0 means no limit. |
395+
| `max_pages` | int | `0` | Maximum pages to OCR per scanned document. 0 means no limit. |
363396
| `enabled` | bool | `true` | Set to `false` to disable LLM-powered extraction. When disabled, no structured data is extracted from documents. |
364397
| `thinking` | bool | `false` | **Deprecated.** Use `[llm.extraction] thinking` instead. |
365398

@@ -375,7 +408,7 @@ fields in the application.
375408
Currency resolution order (highest to lowest):
376409

377410
1. Database value (authoritative once set -- makes the DB file portable)
378-
2. `MICASA_CURRENCY` environment variable
411+
2. `MICASA_LOCALE_CURRENCY` environment variable
379412
3. `[locale] currency` config value
380413
4. Auto-detect from `LC_MONETARY` or `LANG` locale
381414
5. `USD` fallback
@@ -455,4 +488,4 @@ restarts. These are controlled through the UI rather than config files:
455488
|------------|---------|---------------|
456489
| Dashboard on startup | Shown | Press <kbd>D</kbd> to toggle; your choice is remembered |
457490
| LLM model | From config | Changed automatically when you switch models in the chat interface |
458-
| Currency | USD | Set via `[locale] currency` in config, `MICASA_CURRENCY` env var, or auto-detected from system locale. Persisted to the database on first use |
491+
| Currency | USD | Set via `[locale] currency` in config, `MICASA_LOCALE_CURRENCY` env var, or auto-detected from system locale. Persisted to the database on first use |

internal/app/currency_flow_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -954,8 +954,8 @@ func TestCurrencyFlow_DBPortability_DifferentLocale(t *testing.T) {
954954
}
955955

956956
func TestCurrencyFlow_EnvCurrency_FirstRun(t *testing.T) {
957-
// Simulate: MICASA_CURRENCY=GBP micasa (first run, no DB currency yet).
958-
t.Setenv("MICASA_CURRENCY", "GBP")
957+
// Simulate: MICASA_LOCALE_CURRENCY=GBP micasa (first run, no DB currency yet).
958+
t.Setenv("MICASA_LOCALE_CURRENCY", "GBP")
959959
t.Setenv("LC_MONETARY", "")
960960
t.Setenv("LC_ALL", "")
961961
t.Setenv("LANG", "en_GB.UTF-8")
@@ -966,7 +966,7 @@ func TestCurrencyFlow_EnvCurrency_FirstRun(t *testing.T) {
966966
require.NoError(t, err)
967967
t.Cleanup(func() { _ = store.Close() })
968968

969-
// ResolveCurrency with empty config should pick up MICASA_CURRENCY.
969+
// ResolveCurrency with empty config should pick up MICASA_LOCALE_CURRENCY.
970970
require.NoError(t, store.ResolveCurrency(""))
971971
assert.Equal(t, "GBP", store.Currency().Code())
972972
cur := store.Currency()

0 commit comments

Comments
 (0)