Skip to content

Add settings plugin: per-plugin TOML config over schema defaults#40

Open
gering wants to merge 2 commits into
mainfrom
task/plugin-settings-system
Open

Add settings plugin: per-plugin TOML config over schema defaults#40
gering wants to merge 2 commits into
mainfrom
task/plugin-settings-system

Conversation

@gering

@gering gering commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • New settings plugin (phase 1: config surface only). Gives the marketplace an explicit, overrideable, validatable config layer so plugins stop hardcoding conventions (tasks/, .claude/worktrees/, task/, …).
  • Ownership model: each plugin owns a schema/settings.schema.json (types, enums, defaults, config filename); the settings plugin owns the infrastructure (discover → resolve → validate → read/write).
  • Defaults reflect current behavior, not a redesign — migrations flip defaults deliberately, later. Consumer wiring (plugins actually reading resolved settings) is a serial follow-up PR.

Changes

  • plugins/settings/scripts/settings.py (Python 3.11+ stdlib, tomllib) + /settings skill. Subcommands: list, show [--overrides], get, set, unset, validate, defaults. show/get return the resolved config by default.
  • Per-plugin schemas: plugins/{work-system,knowledge-system,pr-flow}/schema/settings.schema.json.
  • [related_projects] sibling-project address book (string or {path,role,tags} table form); a missing path warns, never errors.
  • scripts/test_settings.py (run by check-structure.py in CI): defaults, resolve merge, validation (type/enum/unknown/related-projects), TOML round-trip, coercion, CLI set/get/unset cycle.
  • Docs: plugin README (schema format + consumer contract), CHANGELOG, top-level README, CLAUDE.md plugin list, marketplace.json registration.

Readiness

  • ✅ Structure checks (check-structure.py) — 0 errors (2 pre-existing warnings in unrelated files)
  • ✅ settings tests pass; settings validate clean against all three real schemas
  • ✅ Version/CHANGELOG in sync (new plugin at 0.1.0)
  • ✅ Rebased onto latest main
  • ➖ No build step (declarative plugin repo)

Test plan

  • python3 scripts/check-structure.py is green
  • python3 plugins/settings/scripts/settings.py show work-system shows the resolved config
  • settings set work-system.paths.tasks_dir todos writes only the override; unset prunes it
  • settings set knowledge-system.mode.knowledge_mode bogus is rejected (enum)

🤖 Generated with Claude Code

gering and others added 2 commits July 18, 2026 13:03
Phase 1 (config surface only — consumer wiring is a follow-up):

- New `settings` plugin (v0.1.0) with `scripts/settings.py` (Python 3.11+
  stdlib, tomllib) and the `/settings` skill. Subcommands: list, show
  [--overrides], get, set, unset, validate, defaults. `show` and `get` both
  return the effective (resolved) config by default; `show --overrides` shows
  only what the user changed.
- Ownership model: each plugin ships `schema/settings.schema.json` (a
  JSON-Schema subset carrying types, enums, required, defaults, and the config
  filename). The settings plugin owns discovery, resolve, validate, and IO.
- Schemas for work-system, knowledge-system, pr-flow. Defaults reflect
  *current* behavior (e.g. worktrees_dir = .claude/worktrees), with the neutral
  migration target gated behind [compat] toggles / mode.knowledge_mode — stored
  now, acted on later.
- `[related_projects]` sibling-project address book (string or table entries);
  missing path is a warning, not an error.
- `set`/`unset` write only overrides; defaults stay in the schema. TOML comment
  preservation is deferred (documented).
- Tests in scripts/test_settings.py (run by check-structure.py): defaults,
  resolve merge, validation (type/enum/unknown/related-projects), TOML
  round-trip, coercion, CLI set/get/unset cycle.
- README documents the schema format and the consumer contract; CHANGELOG,
  top-level README, CLAUDE.md plugin list, and marketplace.json updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ToUjTdtMa9oXUwjfgERkXL
Address swarm review findings on the settings CLI (all in settings.py):

- TOML string values now escape control chars (\n, \t, … via short forms +
  \uXXXX), so a value with a newline no longer writes a file tomllib refuses to
  reparse (#1).
- dump_toml quotes table-name and key segments that aren't bare-key-safe, so a
  related_projects entry like `web api` / `a.b` survives a rewrite (#7).
- config_filename rejects any x-config-file that isn't a plain basename
  (absolute, `..`, `~`, nested), so a malformed schema can't write/unlink
  outside the project root (#3).
- `set` classifies the target against the schema: setting a section (#5) or
  descending past a scalar leaf (#8) is now a clear error, not a crash or silent
  mis-nest.
- `set` gates the write on schema validity — a coerced array with wrong element
  types (#4) or a mistyped dynamic related_projects field (#6) is refused
  instead of silently writing an invalid config.

Tests: serializer round-trip (control chars + non-bare keys), config-filename
sandbox, and the four set-path guards.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ToUjTdtMa9oXUwjfgERkXL
@gering
gering force-pushed the task/plugin-settings-system branch from 7f2658a to 4dc7fad Compare July 18, 2026 11:04
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