Skip to content

feat: layered config with always-current defaults file - #30

Merged
joshuagruenstein merged 2 commits into
mainfrom
feat-layered-config
Jul 12, 2026
Merged

feat: layered config with always-current defaults file#30
joshuagruenstein merged 2 commits into
mainfrom
feat-layered-config

Conversation

@joshuagruenstein

Copy link
Copy Markdown
Member

What

Solves the stale-config problem: the old single literate config.toml was a snapshot of the defaults at install time, so shipped improvements (new sections, new vocabulary words) never reached existing installs.

Now two files in App Support (Sublime-style layering):

  • default-config.toml — full literate defaults, rewritten by the app on every launch so it always documents the running version. A mirror, not a source: the app parses the embedded template, never this file, so a mangled mirror can't break anything. New "View default config…" menu item.
  • config.toml — only what the user changes. New installs get a near-empty starter (header + extraVocabulary = []).

Merge semantics

Plain per-key precedence, no magic: a key in config.toml wins wholesale — lists and inline action tables included (no field bleed-through from a default action into its replacement). Section tables ([mappings], [replacements], [rewrite]) merge per contained key, so overriding one mapping keeps the rest. Where different semantics are wanted, the schema provides them: vocabulary (builtin) + extraVocabulary (user's), concatenated and deduped at load — builtin list updates keep flowing to configs that only add words.

Also

  • Rewrite pass defaults ON (plus technicalFormatting) — degrades to regex-only filler stripping without Apple Intelligence, so it's safe everywhere.
  • Embedded template is now the single source of truth: hand-built Swift defaults (duplicate vocab array, summon script copy) deleted.
  • Legacy tingd-directory / config.json migration code removed (no users to migrate).
  • README/DESIGN updated.

Testing

  • 299 assertions green, including a new layering suite: empty/starter overlays are no-ops, per-key wins, wholesale list replacement, inline-table wholesale replacement, extraVocabulary concat + dedupe.
  • Live-tested by Josh on the dev build (his config is now the 8-line starter; defaults mirror + overlay confirmed in logs).

🤖 Generated with Claude Code

joshuagruenstein and others added 2 commits July 12, 2026 02:51
Two files: default-config.toml is a mirror of the embedded defaults,
rewritten on every launch so it always documents the running version
(the app never reads it back). config.toml holds only what the user
changes, applied over defaults with plain per-key precedence — user
keys win wholesale (lists and inline action tables included), section
tables merge per contained key. Vocabulary layering is schema, not
merge magic: builtin vocabulary + user extraVocabulary, concatenated
and deduped. New installs get a near-empty starter config. Rewrite
pass now defaults on (with technicalFormatting). Legacy tingd/json
migration code removed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@joshuagruenstein
joshuagruenstein merged commit 7b71042 into main Jul 12, 2026
2 checks passed
@joshuagruenstein
joshuagruenstein deleted the feat-layered-config branch July 12, 2026 06:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant