Skip to content

fix(agents): omit model field from all 50 bundled agents#336

Merged
marcusrbrown merged 3 commits into
mainfrom
fix/agent-model-omit
May 5, 2026
Merged

fix(agents): omit model field from all 50 bundled agents#336
marcusrbrown merged 3 commits into
mainfrom
fix/agent-model-omit

Conversation

@marcusrbrown
Copy link
Copy Markdown
Owner

Why

OpenCode's documented contract for subagent model resolution is field-omitted:

If you don't specify a model, ... subagents will use the model of the primary agent that invoked the subagent.
https://opencode.ai/docs/agents/

The literal value model: inherit is not documented by OpenCode and historically broke subagent dispatch. Pre-sst/opencode#17888 (March 2026), Provider.parseModel("inherit") returned a non-null structure that defeated the agent?.model ?? sessionModel fallback, producing ProviderModelNotFoundError on every subagent invocation. The fix special-cases the literal string, but a user on OpenCode older than ~v1.13.x running Systematic v2.x today still gets a hard crash with no breadcrumb pointing at frontmatter.

Field-omitted works on every OpenCode version and matches the documented contract.

What changes

  • All 50 bundled agents under agents/ strip the model: inherit line from their frontmatter.
  • Content-integrity gate (scripts/content-integrity.ts:701-723) flips its rule from "require model: inherit" to "require the field absent". The new violation message cites the OpenCode docs and the upstream PR so contributors who hit it understand the why.
  • writing-systematic-skills spec (SKILL.md + references/foundation-conventions.md) reverses the prior guidance and explains the rationale.
  • Root AGENTS.md gains one Conventions bullet so contributors discover the policy at authoring time, not at CI failure.
  • Test fixtures flip violation expectations: previously the suite asserted "missing/non-inherit/empty/null" as violations; now it asserts "any present model value (including the literal inherit)" as violations.

What does NOT change

  • The CC→OpenCode converter (src/lib/converter.ts:310-313) was already stripping model: inherit from output. The conversion path was correct; only the bundled agents and the spec hadn't caught up.
  • Orchestrator plugin compatibility is unaffected. oh-my-openagent and oh-my-opencode-slim route by agent name and don't read frontmatter model at all. Their model overrides come from category-config, not agent files.

Peer convention check

Audited 5 peer OpenCode plugins for bundled-agent model: patterns:

Plugin Bundled agents model: inherit Explicit model No model field
oh-my-openagent 4 0 0 4
oh-my-opencode-slim 1 0 0 1
opencode-magic-context 38 0 0 38
opencode-copilot-delegate 0 (tools-only)
compound-engineering-plugin 53 44 7 2

Field-omitted is the dominant peer convention (43/43 of agents in plugins that actually omit, vs. CEP which is the historical pattern Systematic inherited).

Verification

Check Result
bun run typecheck
bun run lint
bun run build
bun test tests/unit ✅ 448/448
Content-integrity gate ✅ 162 md + 15 ts scanned, 43 exempt hits, 0 violations (the gate now flags any agent declaring a model field, including inherit)
Registry drift ✅ 101 components
Node ESM smoke

Backward compatibility

Reversible by single revert if a real-world regression surfaces. The literal inherit string still works on post-#17888 OpenCode — this PR removes a deliberately undocumented value, it does not remove behavior.

Leading indicators to watch

If OpenCode ever changes the field-absent default, the canaries are:

  1. Changes to agent?.model ?? sessionModel fallback in sst/opencode packages/opencode/src/session/index.ts
  2. Introduction of a default_subagent_model or equivalent global config key
  3. Wording changes to the "If you don't specify a model..." paragraph at https://opencode.ai/docs/agents/
  4. Release notes mentioning "subagent model" / "default model" / "model inheritance"

Refs: https://opencode.ai/docs/agents/, anomalyco/opencode#17888

OpenCode's docs say subagents with no model field inherit the invoking
primary agent's model — the desired portable behavior. The literal
`model: inherit` was undocumented and produced ProviderModelNotFoundError
on OpenCode older than ~v1.13.x (pre anomalyco/opencode#17888). Omitting the
field works on every OpenCode version.

Strip model: inherit from all 50 bundled agents.

Flip the content-integrity gate: previously required `model: inherit`,
now requires the field to be absent. Update the violation message to
explain the why and link to the OpenCode docs and upstream PR.

Update test fixtures for both directions:
- writeAgent helper now writes agents without a model field
- the suite that previously asserted "missing/non-inherit/empty/null"
  as violations now asserts "any present model value (including the
  literal 'inherit')" as violations
- the integration test that constructed an agent fixture with no
  model field to trigger a violation now constructs one with
  `model: inherit` (which, post-flip, is a violation)

Refs: https://opencode.ai/docs/agents/, anomalyco/opencode#17888
The skill spec previously mandated model: inherit for bundled agents.
Update the spec to require omitting the model field instead.

The why is the same as the agent change: subagents with no model field
inherit from the invoking primary agent per OpenCode's docs, which is
the portable behavior. model: inherit was undocumented and broken on
OpenCode pre anomalyco/opencode#17888.

Updates:
- SKILL.md: reverse Identity Defaults section, common-mistakes table,
  validator rule list, and the spec summary bullet.
- references/foundation-conventions.md: same reversal in the long-form
  Identity Defaults section, plus update the optional-fields table to
  show a non-inherit example for skill-level model overrides.

The auto-generated docs/src/content/docs/reference/* files are
gitignored and re-generated by bun run docs:generate during build.

Refs: https://opencode.ai/docs/agents/, anomalyco/opencode#17888
Surface the no-model-field convention in repo-level AGENTS.md so
contributors discover it at authoring time, not at CI failure. Cites
the OpenCode docs (subagents inherit when model is unset) and the
upstream PR that special-cased the literal "inherit" string in
March 2026.

The content-integrity gate already enforces this; this commit is a
discoverability mirror for human contributors and AI agents reading
AGENTS.md before authoring.

Refs: https://opencode.ai/docs/agents/, anomalyco/opencode#17888
Copy link
Copy Markdown
Collaborator

@fro-bot fro-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: PASS

This is a clean, well-scoped change that removes the model: inherit field from all 50 bundled agents, flips the content-integrity gate from requiring model: inherit to requiring its absence, and updates documentation to explain the rationale.

What the PR does correctly

  1. All 50 agents have model: inherit removed — verified via grep -c "^model:" agents/**/*.md returning 0 for all.
  2. Content-integrity gate (scripts/content-integrity.ts:701-723) correctly flips from model !== 'inherit' violation to Object.hasOwn(parsed.data, 'model') violation, which catches any present model value (including inherit, explicit provider IDs, empty strings, null).
  3. Violation message is informative — cites the OpenCode docs URL and the upstream PR, so contributors hitting CI will understand why.
  4. Test fixtures are updated consistently — writeAgent helper now omits model, the "allows agents with model field omitted" test replaces the old "allows agents with model inherit" test, and the "flags any present model value" test covers inherit, hardcoded, empty, and null.
  5. Skill frontmatter test correctly uses model: anthropic/claude-haiku-4-5 (skills ≠ agents; the model field is still valid for skills).
  6. AGENTS.md, writing-systematic-skills/SKILL.md, and foundation-conventions.md all document the new policy with the same rationale and references.
  7. Non-object frontmatter case is now correctly ignored (no model key to flag) rather than producing a spurious violation.
  8. The integration test (checkContentIntegrity against real repo) enforces zero violations at HEAD, and the content-integrity gate confirms 0 violations on the PR branch.

Blocking issues

None.

Non-blocking concerns

  1. Converter already strips model: inherit — The PR description correctly notes src/lib/converter.ts:310-313 already strips this field during CC→OpenCode conversion. No change needed here, but worth a brief inline comment or changelog note that the converter's strip logic is now redundant for bundled agents (it's still useful for ad-hoc imports, so no action required).

  2. isAgentFile helper path check — The isAgentFile function checks for exactly 3 path segments (agents/<category>/<name>.md). This is correct and pre-existing, but worth noting it won't catch agents at unexpected depths. No change needed; just an observation.

Missing tests

None. The test suite comprehensively covers the new behavior (4 checkAgentModel tests, 1 integration test, 1 CLI test). All pass (66/66).

Risk assessment: LOW

  • Likelihood of regression: Extremely low. The change removes an undocumented value (model: inherit) that caused hard crashes on older OpenCode versions. Field omission is the documented default and works on all versions.
  • Blast radius: Limited to bundled agent dispatch behavior. Skills, config merging, tool registration, and bootstrap injection are unaffected.
  • Reversibility: Single git revert restores the old state if a regression surfaces.
  • Security: No security implications — this tightens the integrity gate (now flags any model value on agents) rather than loosening it.

Run Summary
Field Value
Event pull_request
Repository marcusrbrown/systematic
Run ID 25360486626
Cache hit
Session ses_209459521ffe4VrjlpA5FywVu9

@marcusrbrown marcusrbrown merged commit 072e755 into main May 5, 2026
11 checks passed
@marcusrbrown marcusrbrown deleted the fix/agent-model-omit branch May 5, 2026 06:07
marcusrbrown added a commit that referenced this pull request May 6, 2026
Sweep all 13 tracked plan documents to reflect their current state:

- 2026-01-20 implementation + design plans: add YAML frontmatter, mark completed (initial v0.x shipped to npm; project evolved independently since).
- 2026-02-08 docs-next-steps: add frontmatter, mark completed (reference pages + transform-content.ts shipped).
- 2026-02-09 frontmatter-conversion + upstream-tracking: mark superseded by truth-reset; sync infrastructure deleted in PR #243.
- 2026-02-12 reference-section-refresh: add frontmatter, mark completed (sidebar metadata + custom CSS shipped).
- 2026-02-12 sidebar-badges + index-pages: add frontmatter, mark completed (LinkCard/CardGrid generation in transform-content.ts).
- 2026-02-15 automated-resync-workflow: mark superseded; sync infrastructure was deleted before this plan shipped.
- 2026-04-18 content-integrity-gate: flip active -> completed, add PR #301 link + post-merge note covering #306/#313/#319 follow-ups.
- 2026-04-25 registry-automation: flip active -> completed, add PR #315 link + post-merge note (100-component auto-generated registry).
- 2026-04-30 writing-systematic-skills: tick all 7 unit checkboxes, add Post-merge reconciliation explaining Unit 2 direction inversion by PR #336 (model field omission).
- 2026-05-01 idempotent-plugin-registration: flip active -> completed, add PR #335 link + post-merge note covering Phase 0 probe outcome and Option-2 (empty-hooks) decision.

Already-correct plans (refactor-credibility-reset, refactor-truth-reset) left untouched.

No behavioral changes; documentation reconciliation only.
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.

2 participants