Summary
AFT currently uses a single shared config (~/.config/cortexkit/aft.jsonc) for all harnesses (OpenCode, Pi/OMP). The config schema has no per-harness section — hoist_builtin_tools, disabled_tools, tool_surface, etc. are global. This means a user who wants AFT to hoist tools on OpenCode (replacing opencode's natives with AFT's enhanced versions) but keep OMP's natives un-hoisted (so both read and aft_read are available) cannot express that — changing one harness's behavior changes all of them.
The same applies to per-harness LSP config, search_backend, disabled_tools, bash settings, and future harness-specific knobs. Today the only workaround is to keep separate config files and swap them manually or use project-level overrides (<project>/.cortexkit/aft.jsonc), neither of which solves the common case of "two harnesses on the same machine with different needs."
Requested solution
Add a top-level harnesses key to aft.jsonc that allows per-harness overrides:
Why this matters
The current design forces an awkward choice:
- Shared config: every harness gets identical tool sets and behavior. The user who wants AFT exclusives (
aft_callgraph, aft_insight, aft_refactor) on Pi but wants opencode to keep its own native tools has no way to express that.
- Manual swap: keeping two files and renaming them when switching harnesses is error-prone and breaks the "one config" migration story.
- Project overrides: only help when projects are distinct; two harnesses on the same project share the project config.
A harnesses key preserves backward compatibility (the shared top-level still works for users who don't need per-harness control) while adding the missing granularity.
Workarounds today
- Use
<project>/.cortexkit/aft.jsonc per-project (only helps if projects are distinct).
- Keep separate global configs and swap them manually when switching harnesses.
- File a feature request and wait for upstream. 🙂
Alternatives considered
- Separate config files per harness (
aft.pi.jsonc, aft.opencode.jsonc): breaks the "one config" design, migration story becomes unclear.
- CLI flag (
--hoist per invocation): doesn't persist, doesn't cover all settings.
- Env var per harness: limited to boolean/string values, doesn't compose with JSONC.
The harnesses key is the minimal addition that preserves backward compatibility and covers the use case cleanly.
Additional context
Relevant source: packages/config-keys.ts (currently only OPENCODE_ONLY_KEYS and PI_ONLY_KEYS exist, both single-harness), packages/config.ts (schema validation), packages/aft-bridge/src/config-tiers.ts (user+project tiers, no harness tier), packages/pi-plugin/src/index.ts (config loading).
Related prior request: OMP feature request #9972 (provider-level routing override) touches the same theme — the config system needs more granular override paths.
/cc @Alfonso (responded to #267 with the hoist_builtin_tools fix — this is the next logical step).
Summary
AFT currently uses a single shared config (
~/.config/cortexkit/aft.jsonc) for all harnesses (OpenCode, Pi/OMP). The config schema has no per-harness section —hoist_builtin_tools,disabled_tools,tool_surface, etc. are global. This means a user who wants AFT to hoist tools on OpenCode (replacing opencode's natives with AFT's enhanced versions) but keep OMP's natives un-hoisted (so bothreadandaft_readare available) cannot express that — changing one harness's behavior changes all of them.The same applies to per-harness LSP config, search_backend, disabled_tools, bash settings, and future harness-specific knobs. Today the only workaround is to keep separate config files and swap them manually or use project-level overrides (
<project>/.cortexkit/aft.jsonc), neither of which solves the common case of "two harnesses on the same machine with different needs."Requested solution
Add a top-level
harnesseskey toaft.jsoncthat allows per-harness overrides:{ // Shared defaults (current behavior, all fields still work here) "hoist_builtin_tools": false, "disabled_tools": [], // Per-harness overrides — deep-merged on top of shared config "harnesses": { "opencode": { "hoist_builtin_tools": true, "disabled_tools": ["aft_conflicts"] }, "pi": { "hoist_builtin_tools": false, "disabled_tools": ["aft_read", "aft_write", "aft_edit", "aft_grep", "aft_bash"] } } }Why this matters
The current design forces an awkward choice:
aft_callgraph,aft_insight,aft_refactor) on Pi but wants opencode to keep its own native tools has no way to express that.A
harnesseskey preserves backward compatibility (the shared top-level still works for users who don't need per-harness control) while adding the missing granularity.Workarounds today
<project>/.cortexkit/aft.jsoncper-project (only helps if projects are distinct).Alternatives considered
aft.pi.jsonc,aft.opencode.jsonc): breaks the "one config" design, migration story becomes unclear.--hoistper invocation): doesn't persist, doesn't cover all settings.The
harnesseskey is the minimal addition that preserves backward compatibility and covers the use case cleanly.Additional context
Relevant source:
packages/config-keys.ts(currently onlyOPENCODE_ONLY_KEYSandPI_ONLY_KEYSexist, both single-harness),packages/config.ts(schema validation),packages/aft-bridge/src/config-tiers.ts(user+project tiers, no harness tier),packages/pi-plugin/src/index.ts(config loading).Related prior request: OMP feature request #9972 (provider-level routing override) touches the same theme — the config system needs more granular override paths.
/cc @Alfonso (responded to #267 with the
hoist_builtin_toolsfix — this is the next logical step).