Skip to content

roles: capability-tier models with per-harness overrides - #140

Merged
yourconscience merged 1 commit into
mainfrom
roles/model-tier-overrides
Aug 22, 2026
Merged

roles: capability-tier models with per-harness overrides#140
yourconscience merged 1 commit into
mainfrom
roles/model-tier-overrides

Conversation

@yourconscience

@yourconscience yourconscience commented Aug 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • generic model tier (haiku/sonnet/opus) renders natively per harness; add claude.model override for exact ids
  • document OMP/OpenCode verbatim rendering + session-model inheritance in README
  • keep Add shared OMP roles and memory dream review #136 fallback semantics for OMP (tested)

Test plan

  • go test ./cmd/dotagents/ green (incl. updated OMP renderer tests)

Summary by Sourcery

Support capability-tier role models with per-harness overrides and expose session-aware harness metadata.

New Features:

  • Add per-harness Claude model overrides while preserving generic capability-tier models and exact model identifiers for supported harnesses.
  • Expose canonical session-hub harness metadata as JSON for harnesses with session support.

Bug Fixes:

  • Preserve OMP model override and fallback behavior when rendering roles.
  • Avoid duplicating the generic model as a Codex-specific override when converting legacy Codex roles.

Enhancements:

  • Extend canonical role serialization and parsing to retain Claude and OMP overrides.

Documentation:

  • Document capability-tier model rendering, per-harness exact model overrides, and session-model inheritance.

Tests:

  • Add coverage for Claude and OMP model overrides, role parsing, OMP rendering, and session-hub harness contracts.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@sourcery-ai

sourcery-ai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Reviewer's Guide

Introduce capability-tier model handling with per-harness overrides (including a new Claude override), adjust Codex/OMP role rendering and canonical role markdown generation to respect harness-specific models, and add a session-hub harness discovery command plus documentation for model tier semantics and session inheritance.

Sequence diagram for Claude role model rendering

sequenceDiagram
    participant Role as agentRole
    participant Renderer as renderClaudeAgentRole
    participant Output as Claude role markdown
    Role->>Renderer: renderClaudeAgentRole(role)
    Renderer->>Renderer: strings.TrimSpace(role.Claude.Model)
    alt claude.model is set
        Renderer->>Output: writeYAMLScalar(model, claude.model)
    else override is empty
        Renderer->>Renderer: strings.TrimSpace(role.Model)
        Renderer->>Output: writeYAMLScalar(model, generic model tier)
    end
Loading

Flow diagram for per-harness model resolution

flowchart LR
    Role[Role frontmatter] --> Generic[Generic model tier]
    Role --> Overrides[Per-harness model overrides]
    Generic --> Native[Claude Codex Droid native tier rendering]
    Overrides --> Exact[Exact harness model identifier]
    Generic --> Verbatim[OMP OpenCode verbatim rendering]
    Verbatim --> Session[Active session model inheritance]
Loading

File-Level Changes

Change Details Files
Add Claude harness-specific model override support and ensure render/parsing respects it.
  • Extend agentRole with a Claude-specific options struct and YAML unmarshalling for the claude key.
  • Implement claudeRoleOptions with a model field used by renderClaudeAgentRole, falling back to the generic role.Model when no override is given.
  • Update Claude role rendering tests to validate arbitrary model override and preservation of parsed harness-specific overrides.
cmd/dotagents/agents.go
cmd/dotagents/agents_test.go
Clarify capability-tier model semantics and verbatim rendering for harnesses without native tiers.
  • Document that generic model tiers (haiku/sonnet/opus) render natively for Claude Code, Codex, and Droid while OMP/OpenCode render the value verbatim.
  • Provide README examples showing per-harness model overrides and how to inherit the active session model.
README.md
Preserve and emit harness-specific model fields in canonical role markdown, and avoid duplicating Codex model into the generic model field during TOML->Markdown conversion.
  • Ensure renderCanonicalRoleMarkdown includes Claude, Codex, Droid, Opencode, and OMP option blocks when present.
  • Modify convertCodexRoleTOMLToMarkdown to stop setting the generic role.Model from Codex model, keeping harness-specific model in the Codex block only.
cmd/dotagents/setup_scaffold.go
Ensure OMP renderer respects per-role model override while maintaining existing fallback semantics.
  • Update OMP renderer test to use capability-tier model with an explicit OMP model override.
  • Verify the rendered OMP frontmatter model list matches the override and not the generic tier.
cmd/dotagents/harness_test.go
Add a session-hub harness listing command that exposes canonical session contracts and tests to keep harness metadata complete.
  • Implement runSessionHub to output JSON describing harnesses that support sessions, including store path and resume identifiers.
  • Define sessionHubHarness struct and sort harness output deterministically.
  • Add tests asserting each session-aware harness has a complete session contract and that the canonical set of harnesses with sessions is {claude-code, codex, droid, hermes, omp}.
cmd/dotagents/session_hub.go
cmd/dotagents/session_hub_test.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@yourconscience
yourconscience merged commit 6454b32 into main Aug 22, 2026
4 of 5 checks passed
@yourconscience
yourconscience deleted the roles/model-tier-overrides branch August 22, 2026 20:20

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="cmd/dotagents/session_hub.go" line_range="17-34" />
<code_context>
+	Resume []string `json:"resume"`
+}
+
+func runSessionHub(args []string) error {
+	if len(args) != 2 || args[0] != "harnesses" || args[1] != "--json" {
+		return errors.New("usage: dotagents session-hub harnesses --json")
+	}
+	registry := getHarnesses()
+	out := make([]sessionHubHarness, 0, len(registry))
+	for name, harness := range registry {
+		if harness.Sessions == nil {
+			continue
+		}
+		out = append(out, sessionHubHarness{Name: name, Store: harness.Sessions.Store, Resume: harness.Sessions.Resume})
+	}
+	sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
+	if err := json.NewEncoder(os.Stdout).Encode(map[string]any{"harnesses": out}); err != nil {
+		return fmt.Errorf("encode session-hub contract: %w", err)
+	}
+	return nil
+}
</code_context>
<issue_to_address>
**issue (bug_risk):** `runSessionHub` is never dispatched from `run`, so invoking `dotagents session-hub harnesses --json` returns the unknown-subcommand error instead of emitting the session-hub contract.

**Triggers:** When the session hub invokes the newly documented CLI contract.

**Suggested fix:** Add a `session-hub` case to the top-level command switch that calls `runSessionHub(args[1:])`.
</issue_to_address>

### Comment 2
<location path="cmd/dotagents/setup_scaffold.go" line_range="665-674" />
<code_context>
 		Effort      string              `yaml:"effort,omitempty"`
 		Tools       []string            `yaml:"tools,omitempty"`
 		Color       string              `yaml:"color,omitempty"`
+		Claude      claudeRoleOptions   `yaml:"claude,omitempty"`
 		Codex       codexRoleOptions    `yaml:"codex,omitempty"`
 		Droid       droidRoleOptions    `yaml:"droid,omitempty"`
 		Opencode    opencodeRoleOptions `yaml:"opencode,omitempty"`
-	}{Name: role.Name, Description: role.Description, Model: role.Model, Effort: role.Effort, Tools: role.Tools, Color: role.Color, Codex: role.Codex, Droid: role.Droid, Opencode: role.Opencode}
+		OMP         ompRoleOptions      `yaml:"omp,omitempty"`
+	}{
+		Name: role.Name, Description: role.Description, Model: role.Model, Effort: role.Effort,
+		Tools: role.Tools, Color: role.Color, Claude: role.Claude, Codex: role.Codex,
+		Droid: role.Droid, Opencode: role.Opencode, OMP: role.OMP,
+	}
 	meta, err := yaml.Marshal(front)
 	if err != nil {
</code_context>
<issue_to_address>
**issue (broader_impact):** OpenCode roles still omit the generic `role.Model` when `role.Opencode.Model` is empty, so a role with `model: opus` renders no model at all instead of rendering `opus` verbatim as the README promises.

**Triggers:** When a role defines only the generic capability-tier `model` and no `opencode.model` override.

**Suggested fix:** In `renderOpenCodeAgentRole`, fall back from `role.Opencode.Model` to `role.Model` before deciding whether to emit the model field.
</issue_to_address>

Sourcery assessment

Approval pending. 2 findings to address first.

Blocking findings: cmd/dotagents/session_hub.go:34, cmd/dotagents/setup_scaffold.go:674


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +17 to +34
func runSessionHub(args []string) error {
if len(args) != 2 || args[0] != "harnesses" || args[1] != "--json" {
return errors.New("usage: dotagents session-hub harnesses --json")
}
registry := getHarnesses()
out := make([]sessionHubHarness, 0, len(registry))
for name, harness := range registry {
if harness.Sessions == nil {
continue
}
out = append(out, sessionHubHarness{Name: name, Store: harness.Sessions.Store, Resume: harness.Sessions.Resume})
}
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
if err := json.NewEncoder(os.Stdout).Encode(map[string]any{"harnesses": out}); err != nil {
return fmt.Errorf("encode session-hub contract: %w", err)
}
return nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (bug_risk): runSessionHub is never dispatched from run, so invoking dotagents session-hub harnesses --json returns the unknown-subcommand error instead of emitting the session-hub contract.

Triggers: When the session hub invokes the newly documented CLI contract.

Suggested fix: Add a session-hub case to the top-level command switch that calls runSessionHub(args[1:]).

Comment on lines +665 to +674
Claude claudeRoleOptions `yaml:"claude,omitempty"`
Codex codexRoleOptions `yaml:"codex,omitempty"`
Droid droidRoleOptions `yaml:"droid,omitempty"`
Opencode opencodeRoleOptions `yaml:"opencode,omitempty"`
}{Name: role.Name, Description: role.Description, Model: role.Model, Effort: role.Effort, Tools: role.Tools, Color: role.Color, Codex: role.Codex, Droid: role.Droid, Opencode: role.Opencode}
OMP ompRoleOptions `yaml:"omp,omitempty"`
}{
Name: role.Name, Description: role.Description, Model: role.Model, Effort: role.Effort,
Tools: role.Tools, Color: role.Color, Claude: role.Claude, Codex: role.Codex,
Droid: role.Droid, Opencode: role.Opencode, OMP: role.OMP,
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (broader_impact): OpenCode roles still omit the generic role.Model when role.Opencode.Model is empty, so a role with model: opus renders no model at all instead of rendering opus verbatim as the README promises.

Triggers: When a role defines only the generic capability-tier model and no opencode.model override.

Suggested fix: In renderOpenCodeAgentRole, fall back from role.Opencode.Model to role.Model before deciding whether to emit the model field.

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