T-IIZO-per-target-overrides
State: planning/proposed · Impact: high · Complexity: medium
The canonical model says what every harness has in common, so a field only one harness carries has
nowhere to live: Claude Code’s permissionMode, OpenCode’s permission block, Codex’s
policy.allow_implicit_invocation. ap-overrides gives a note the last word for one target, in
that harness’s own key names, without bending the shared model to fit a single runtime. The support
warnings, the harness gap table and the edit form’s Overrides section all resolve to this key.
| Location | Role today |
|---|---|
solutions/agent-pants/crates/agent-adapt-core/src/frontmatter.rs#VaultFrontmatter | Types every modelled ap- key; an unmodelled one lands in unknown_ours and reaches no destination |
solutions/agent-pants/crates/agent-adapt-core/src/namespace.rs#SPEC_KEYS | The spec’s own keys, outside our namespace — untouched by anything added under the ap stem |
solutions/agent-pants/crates/agent-adapt-core/src/projection.rs#project_skill | Strips the namespace and projects a note onto SkillContent; project_agent and project_command sit beside it |
solutions/agent-pants/crates/agent-adapt-core/src/publish.rs#canonical_target | Folds every accepted spelling onto one name per destination; canonical_targets() is the roster |
packages/rust/agent-adapt/src/render/frontmatter.rs#FrontmatterBuilder | Builds one target’s frontmatter through its dialect; raw_entry already writes an arbitrary key and JSON value |
packages/rust/agent-adapt/src/runtime.rs#FrontmatterDialect | omit_fields is how a target declines a canonical key |
packages/rust/agent-adapt/src/render/hooks_json.rs#render_hooks_json | Serializes hooks with no seam for a per-target key |
packages/rust/agent-adapt/src/render/command_toml.rs#render_command_toml | Serializes one command with no seam for a per-target key |
solutions/agent-pants/docs/vault/decisions/entity-kind-and-frontmatter-namespace.md | The ap stem rule and the field roster a new key joins |
solutions/determined/crates/determined-core/src/wire/mod.rs#AgentSkillNoteFields | The writable frontmatter surface: carries ap_targets, nothing per target |
solutions/determined/experiences/agent-pants/app/components/ApTargetsControl.vue | Edits ap-targets — which destinations, never what one of them receives |
solutions/determined/experiences/agent-pants/app/utils/fieldSpec.ts#FIELD_SPECS | One entry per modelled field, each with the kinds it applies to |
Proposed
Section titled “Proposed”A note may carry ap-overrides: a map keyed by canonical target, each value a map written in that
harness’s own key names — permissionMode: plan for claude, permission: {bash: ask} for
opencode, policy.allow_implicit_invocation: true for codex. Canonical fields render first and
the override map merges last, over the rendered output for that runtime only. Nothing an override
says reaches another target.
Three rules hold at the seam. A target key the capability matrix does not know for that harness is
a refusal naming both the target and the key, never a silent write. A target name outside
canonical_target is the existing unknown-target refusal. An override whose value equals what
the projection already emits is reported as a redundant-override diagnostic, not a refusal.
ap-overrides sits under the vault’s configured stem like every other key Agent Pants owns, so
SPEC_KEYS and the spec’s six fields are unaffected, and the emit-side strip keeps the key off
every destination.
A per-target body — ap-overrides.<target>.body: "note" — is decided here and lands off. The
body is what the author reads and edits, and a second body per target splits the note in a way
nothing else in the model does. The decision is written down so a later task can reopen it.
Approach
Section titled “Approach”- Model the key.
VaultFrontmattergainsoverrides: BTreeMap<String, Map<String, Value>>, read intake_from. Each map key folds throughpublish::canonical_target; an unfoldable name is the existingunknown-targetrefusal. A value that is not a map is the same wrong-shape refusal the other typed keys already raise. - Validate override keys against the capability matrix from T-HLEW-harness-capability-matrix. A key the matrix does not list for that target is refused, naming both. Decision inside this step: a target the matrix has no entry for refuses every override rather than passing them through, so an unmapped harness cannot receive unchecked keys.
- Merge in the frontmatter renderer.
FrontmatterBuildergains an override map applied after every canonical field, through the existingraw_entry. Decision inside this step: an override outranksFrontmatterDialect::omit_fields, because the author named that target explicitly. - Give
render_hooks_jsonandrender_command_tomlthe same merge, so a hook and a command accept overrides on the same terms as a skill’s frontmatter. - Report redundancy. The renderer compares the pre-merge and post-merge value per key and returns a diagnostic where they are equal. Diagnostics travel with the publish preview; they never block a write.
- Carry the key on the wire.
AgentSkillNoteFieldsgainsap_overrides, round-tripped bywrite_note;FIELD_SPECSgains an entry so the field docs and the form can name it. - Document it: the
ap-overridesrow indocs/vault-layout.mdand indocs/frontmatter-reference.md, and the field roster in the namespace decision. - Record the per-target-body decision as declined, with the reason, in the namespace decision.
| Area | Note |
|---|---|
solutions/agent-pants/crates/agent-adapt-core/src/frontmatter.rs | VaultFrontmatter::overrides, parsed and refused in take_from |
solutions/agent-pants/crates/agent-adapt-core/src/projection.rs | Carry the overrides map onto the projection the renderer receives |
solutions/agent-pants/crates/agent-adapt-core/src/publish.rs | Fold override target keys through canonical_target; surface refusals and diagnostics |
packages/rust/agent-adapt/src/render/frontmatter.rs | Merge the target’s override map last, via raw_entry |
packages/rust/agent-adapt/src/render/hooks_json.rs | Same merge for a hook’s rendered entry |
packages/rust/agent-adapt/src/render/command_toml.rs | Same merge for a command’s TOML |
packages/rust/agent-adapt/src/runtime.rs | Note that an override outranks omit_fields |
solutions/determined/crates/determined-core/src/wire/mod.rs | AgentSkillNoteFields::ap_overrides |
solutions/determined/crates/determined-agent-skills/src/lib.rs | Round-trip ap-overrides through write_note and the note detail |
solutions/determined/experiences/agent-pants/app/utils/fieldSpec.ts | A FIELD_SPECS entry for ap-overrides |
solutions/determined/experiences/agent-pants/docs/vault-layout.md | Where overrides sit and what they reach |
solutions/determined/experiences/agent-pants/docs/frontmatter-reference.md | The ap-overrides key reference |
solutions/agent-pants/docs/vault/decisions/entity-kind-and-frontmatter-namespace.md | Add ap-overrides to the field roster; record the declined per-target body |
solutions/agent-pants/crates/agent-adapt-core/tests/ | Fixtures for an accepted override, an unknown key, an unknown target, a redundant override |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1: A note carrying
ap-overrides.claude.permissionMode: planpublishes toclaudewith that key in the rendered frontmatter, and tocodex,gemini-cliandopencodewithout it. - AC-2:
ap-overridesappears in no rendered output for any target — the emit-side namespace strip covers it, asserted by a test over theclaudeandportablerenders. - AC-3: An override key the matrix does not list for that target refuses, and the refusal text names the target and the key.
- AC-4: An override target name outside
canonical_targetrefusesunknown-target. - AC-5: An override whose value equals the projection’s own output produces a redundant-override diagnostic and still publishes.
- AC-6: A hook’s
hooks.jsonentry and a command’s TOML each accept an override for their target, covered by one test apiece. - AC-7:
write_noteround-tripsap-overridesbyte-identically when nothing else changed. - AC-8:
docs/frontmatter-reference.mddocumentsap-overrides, and the namespace decision records the per-target body as declined with its reason.
Out of scope
Section titled “Out of scope”- The editor’s Overrides section: T-GHE3-edit-form-in-center-pane renders it.
- The “add a
<target>override” affordance on a support warning: T-8BUZ-marketplace-targets-and-support-warnings. - Marking overridden keys in the per-target preview: T-K1A2-preview-pane-per-entity-and-target.
- A per-target body. Decided here, landed off.
- Any change to
SPEC_KEYSor to the six spec fields.
Dependencies
Section titled “Dependencies”- T-HLEW-harness-capability-matrix is the only oracle for “does this harness know this key”, so the refusal in step 2 cannot be written before it lands.
- T-8BUZ-marketplace-targets-and-support-warnings, T-GHE3-edit-form-in-center-pane, T-K1A2-preview-pane-per-entity-and-target and T-0AF7-hook-editor-and-harness-gap-table consume this key; none of them blocks it.
Discovery context
Section titled “Discovery context”Member of milestone M-BMFD, from the user’s planning request of 2026-09-07: where a harness
diverges too far for the canonical model to map onto it, a note may carry a target-specific
override, and that is a feature rather than an escape hatch. The divergence is catalogued in
solutions/agent-pants/docs/vault/reference/harness-comparison.md and in the assessment
solutions/agent-pants/docs/vault/design/workflow-and-ux-assessment.md. The harness key names come
from Claude Code subagents,
OpenCode and Codex CLI,
all fetched 2026-09-07.
Depends on
Section titled “Depends on”T-HLEW-harness-capability-matrix