Skip to content

fix: resolve extension-published agents for session command catalogs - #350

Merged
pedronauck merged 5 commits into
compozy:mainfrom
franciscpd:fix/session-commands-extension-agents
Aug 12, 2026
Merged

pedronauck merged 5 commits into
compozy:mainfrom
franciscpd:fix/session-commands-extension-agents

Conversation

@franciscpd

@franciscpd franciscpd commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #349.

Problem

Sessions using an extension-published agent could not build their effective command catalog. That blocked session commands, Web command suggestions, normal prompts, and slash-skill prompts with skills: agent not found.

The failing case has a concrete agent snapshot with a SourcePath. That path is valid for extension agents, but the command service treated every source-backed agent as authored and used the name-based skills registry. The name-based registry intentionally resolves authored and built-in agents, not extension publications.

Root fix

  • Keep the name-based authored-agent lookup first so live authored diagnostics and validation remain authoritative.
  • Fall back to the workspace-fenced daemon agent catalog only when the registry returns skills.ErrAgentNotFound.
  • Resolve the catalog result through CommandCandidatesForAgentDefSession, which supports extension and bundled agents.
  • Preserve all other authored errors, including invalid local agent definitions, and surface non-not-found catalog failures.
  • Keep the catalog dependency lazy because the command service is composed before the resource catalog finishes booting.
  • Wire compozy__skill_view(command_id) to the same explicit session.AgentResolver; retain the concrete session snapshot requirement.

This removes the earlier catalog-first precedence change and the no-snapshot sentinel path. No public HTTP, UDS, CLI, native-tool schema, event, config, or persistence contract changed.

Tests

  • Consolidated the regression coverage into the owning session command suite.
  • Covered extension fallback, authored validation preservation, resolver failures, and late resolver availability.
  • Updated native skill_view(command_id) coverage for a source-backed extension agent.
  • Added an integration E2E that enables dev-cycle, creates an unbound reviewer session, reads its HTTP command catalog, sends a normal prompt, sends an extension slash-skill prompt, and verifies the source-qualified invocation persisted in session history.

Focused race-enabled unit and integration tests pass.

Real-user QA

A fresh isolated targeted lab verified:

  • CLI, HTTP, and direct UDS returned the same revision and 11 commands, including all 9 dev-cycle extension skills.
  • The live Codex agent used compozy__command_list and source-qualified compozy__skill_view successfully.
  • The slash command expanded and persisted its extension source metadata.
  • The Web composer showed the extension commands before and after refresh with no browser errors.
  • A foreign workspace request returned 404.
  • QA evidence audit passed with no blockers or warnings.
  • Teardown completed with clean: true and no surviving processes.

Verification

  • make gate-full — PASS (full make verify)
  • Gate fingerprint: 5b26be80c002fcf6e238b2d2931a185e3c075413
  • Go lint: 0 issues
  • Production source-size gate: pass

Remediation commit: aba35230.

The Vercel authorization status is external to this code change; the repository verification pipeline is green.

Compozy Impact Audit

  • Native tools: no descriptor, schema, digest, risk, or capability-gate changes; compozy__command_list and compozy__skill_view(command_id) inherit the corrected resolver ordering.
  • Extensibility and hooks: no extension manifest, hook, SDK, MCP sidecar, or config-lifecycle changes; existing extension agent publications are now consumed correctly.
  • Workspace data isolation: no new data or ownership changes; CLI/HTTP/UDS/native reads remain fenced by the resolved session workspace, proven by the wrong-workspace QA probe.
  • Official Compozy skill: no update required because no public tool ID, CLI path, hook event, capability, or extension resource contract changed.

Summary by CodeRabbit

  • New Features

    • Session commands can now resolve skills provided by extension-published and bundled agents.
    • Unbound sessions can access extension commands and submit prompts using those skills.
    • Skill activity is preserved in session history after successful invocation.
  • Bug Fixes

    • Existing authored-agent validation and fallback errors remain intact when agent resolution is unavailable.

Sessions bound to an extension-published agent (e.g. the bundled
dev-cycle reviewer/code_implementer agents) could not be prompted
because commandSkillCandidates fell back to the name-based
CommandCandidatesForAgentSession path whenever no agent snapshot was
present, and that path only resolves workspace-authored, builtin, and
global authored agents, never extension-published ones.

sessionCommandService now tries to resolve the concrete AgentDef via
the daemon's resource-backed agent catalog (resourceAgentCatalog,
already used everywhere else agents are resolved) before falling back
to the name-based lookup, so it can route through
CommandCandidatesForAgentDefSession, which supports extension and
bundle agents.

Review fixes: harden the fallback test with errors.Is + a call-count
assertion proving the name-based path actually ran, drive the
extension-agent test through the public Catalog() entry point,
replace the switch/break branch with a plain if/else chain, and add
the compile-time sessionCommandAgentResolver interface guard next to
resourceAgentCatalog's existing guards.

Boot-order fix: bootPromptProviders constructs sessionCommandService
before bootRuntime populates state.agentCatalog, so capturing the
resolver by value at construction time permanently bound it to a nil
catalog and silently degraded every session to the old name-based
fallback. agentResolver is now a lazy provider (func() ->
sessionCommandAgentResolver), mirroring workspaceResolver's existing
shape, and is evaluated at each resolveAgentDef call instead of once
at construction time. Added a regression test proving a provider that
returns nil at build time and a working resolver later is used once
available.
@franciscpd
franciscpd requested a review from pedronauck as a code owner August 12, 2026 02:01
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

@franciscpd is attempting to deploy a commit to the Compozy Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 894e36c5-1035-4d4a-acd7-0b8bc1e1be9f

📥 Commits

Reviewing files that changed from the base of the PR and between aba3523 and 9c7651d.

📒 Files selected for processing (1)
  • internal/daemon/native_tools_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/daemon/native_tools_test.go

Walkthrough

Session command skill lookup now resolves extension-published agents through a deferred agent catalog. Existing authored-agent validation and fallback errors remain unchanged. Unit and end-to-end tests cover command lookup, prompt execution, SSE completion, and persisted history.

Changes

Session command agent resolution

Layer / File(s) Summary
Agent resolution contract and fallback
internal/daemon/session_commands.go, internal/daemon/native_tool_registry_skills.go
The service resolves an AgentDef through a lazy catalog when name-based lookup reports a missing agent. Existing fallback and error handling remain active.
Lazy agent catalog wiring
internal/daemon/agent_skill_catalog.go, internal/daemon/boot.go, internal/daemon/native_tool_dependencies.go, internal/daemon/native_tool_registry_skills.go, internal/daemon/native_tools_dependencies_builder.go
Daemon dependencies share one agent catalog and provide it as a session AgentResolver.
Resolver and fallback test coverage
internal/daemon/native_tools_test.go, internal/daemon/prompt_skills_test.go
Tests cover extension-agent lookup, authored-agent errors, resolver failures, lazy availability, missing snapshots, and returned skill content.
Extension-agent session flow validation
internal/daemon/daemon_extension_agent_fixture_e2e_integration_test.go
The integration test validates extension commands, plain and skill prompts, SSE completion, session idleness, and persisted skill invocation history.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • compozy/compozy#256: Both changes add first-class agent catalog and discovery support.
  • compozy/compozy#311: Both changes update session command resolution and daemon wiring around agent catalogs.
  • compozy/compozy#323: Both changes update managed-session skill loading and daemon/session tests.

Suggested reviewers: pedronauck

Sequence Diagram(s)

sequenceDiagram
  participant Session
  participant sessionCommandService
  participant AgentResolver
  participant resourceAgentCatalog
  participant SkillRegistry
  Session->>sessionCommandService: request commands or prompt
  sessionCommandService->>AgentResolver: resolve agent name
  AgentResolver->>resourceAgentCatalog: find AgentDef
  resourceAgentCatalog-->>AgentResolver: return extension AgentDef
  AgentResolver-->>sessionCommandService: return AgentDef
  sessionCommandService->>SkillRegistry: resolve command candidates
  SkillRegistry-->>sessionCommandService: return skill content
  sessionCommandService-->>Session: return commands or prompt result
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: resolving extension-published agents for session command catalogs.
Linked Issues check ✅ Passed The changes resolve extension and bundled agents through the daemon catalog while preserving authored lookup and session command behavior required by issue #349.
Out of Scope Changes check ✅ Passed The implementation, dependency wiring, regression tests, and end-to-end test all support the linked issue objectives.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Greptile Summary

The PR corrects session command resolution for extension-published agents while preserving authored-agent validation precedence.

  • Adds a lazy, workspace-fenced agent-catalog fallback when name-based lookup reports an agent absent.
  • Wires native skill_view(command_id) through the same explicit session agent resolver.
  • Adds unit, integration, and QA coverage for extension command catalogs, prompts, source-qualified skill invocation, late resolver availability, and workspace isolation.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
internal/daemon/session_commands.go Adds lazy catalog fallback only for agent-not-found results while preserving authored validation errors.
internal/daemon/native_tool_registry_skills.go Routes source-qualified skill views through the explicit session agent resolver and documents the resolution contract.
internal/daemon/native_tools_dependencies_builder.go Wires the production resource agent catalog into both catalog and resolver dependencies.
internal/daemon/agent_skill_catalog.go Adds a compile-time assertion that the production catalog satisfies the session agent resolver interface.
internal/daemon/daemon_extension_agent_fixture_e2e_integration_test.go Adds end-to-end coverage for extension command discovery, prompting, slash invocation, and persisted source metadata.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant Commands as Session Command Service
  participant Registry as Authored Skills Registry
  participant Catalog as Workspace Agent Catalog
  Caller->>Commands: Request session command catalog
  Commands->>Registry: Resolve agent skills by name
  alt Authored agent found or validation fails
    Registry-->>Commands: Candidates or authoritative error
  else Agent not found
    Commands->>Catalog: Resolve extension/bundled agent
    Catalog-->>Commands: Concrete agent definition
    Commands->>Registry: Resolve candidates from definition
    Registry-->>Commands: Source-qualified candidates
  end
  Commands-->>Caller: Effective command catalog
Loading

Reviews (5): Last reviewed commit: "test: cover skill_view command_id when t..." | Re-trigger Greptile

Comment thread internal/daemon/native_tool_registry_skills.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/daemon/session_commands_test.go (1)

69-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Mark the top-level test as parallel.

Add t.Parallel() immediately after Line 69. The parallel subtests do not make the top-level test parallel.

As per coding guidelines, “Before editing Go tests, activate eng-test-conventions; use … default t.Parallel.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/daemon/session_commands_test.go` around lines 69 - 70, Add
t.Parallel() immediately at the start of
TestSessionCommandServiceCommandSkillCandidatesExtensionAgent, before the t.Run
call, so the top-level Go test executes in parallel with other tests while
preserving its existing parallel subtests.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/daemon/native_tool_registry_skills.go`:
- Around line 226-233: The resolveSkillViewTarget flow must allow command-ID
skill views when sessionAgentDefinition has no snapshot: replace the early
rejection with an empty AgentDef and continue into service.project. Preserve
commandSkillCandidates resolution through info.AgentName and AgentCatalog, and
update the canonical native-tool test to cover this extension-agent command-ID
path.

---

Nitpick comments:
In `@internal/daemon/session_commands_test.go`:
- Around line 69-70: Add t.Parallel() immediately at the start of
TestSessionCommandServiceCommandSkillCandidatesExtensionAgent, before the t.Run
call, so the top-level Go test executes in parallel with other tests while
preserving its existing parallel subtests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e0f2c16e-e1f9-4731-b554-0eeb422db8af

📥 Commits

Reviewing files that changed from the base of the PR and between 7fc534a and 1ed69d7.

📒 Files selected for processing (7)
  • internal/daemon/agent_skill_catalog.go
  • internal/daemon/boot.go
  • internal/daemon/native_tool_registry_skills.go
  • internal/daemon/native_tools_test.go
  • internal/daemon/prompt_skills_test.go
  • internal/daemon/session_commands.go
  • internal/daemon/session_commands_test.go

Comment thread internal/daemon/native_tool_registry_skills.go
…path

CodeRabbit flagged that resolveSkillViewTarget's compozy__skill_view
native tool rejected any command_id lookup for a session with no
cached concrete agent snapshot, before ever reaching the catalog
resolver wired into its ad-hoc sessionCommandService. That made the
resolver unreachable for exactly the sessions this PR fixes:
extension-published agents whose snapshot has not persisted yet.

sessionAgentDefinition now distinguishes "session dependency
unavailable" (still a hard failure) from "no snapshot cached for this
session yet" via a new sentinel error. resolveSkillViewTarget treats
only the latter as non-fatal: it proceeds with an empty AgentDef and
lets commandSkillCandidates resolve the concrete definition itself
(agent catalog, then the name-based lookup as a final fallback for
truly unknown agents) instead of rejecting outright. Added a
regression test proving the command_id path now resolves an
extension-published agent with no cached snapshot, alongside the
existing coverage for a genuinely unavailable session dependency.

Also addresses the remaining PR review feedback: t.Parallel() on the
top-level extension-agent test (subtests already were), and godoc
comments on every function/type/interface this branch added or
touched, to close the PR's docstring coverage gap.
@franciscpd

Copy link
Copy Markdown
Contributor Author

All three CodeRabbit findings addressed in f15d9e5:

  1. skill_view command_id path (Major) — the early rejection no longer blocks sessions without a cached agent snapshot; see the inline reply for the sentinel-error distinction that preserves the dependency-unavailable semantics two existing tests rely on. New canonical regression test covers the extension-agent command_id path.
  2. t.Parallel() — added on the top-level test per the repo's test conventions.
  3. Docstring coverage — godoc comments added across every function/interface this PR introduced or touched (session_commands.go, native_tool_registry_skills.go, native_tool_authored_paths.go, agent_skill_catalog.go, test stubs).

go test ./internal/daemon/... -race -count=1 clean on two fresh runs after the changes.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 12, 2026
@pedronauck

Copy link
Copy Markdown
Member

PR review remediation is now pushed in aba35230.

The original PR found the right missing dependency, but its catalog-first ordering could bypass live authored-agent validation, and its no-snapshot skill_view path modeled the wrong runtime state. The remediation now:

  • keeps authored lookup and diagnostics first;
  • falls back to the workspace-fenced catalog only on skills.ErrAgentNotFound;
  • uses the existing session.AgentResolver explicitly in both session commands and skill_view(command_id);
  • consolidates the unit coverage and adds a publication → unbound session → catalog → normal prompt → slash prompt E2E with persisted source metadata;
  • completes CLI/HTTP/UDS/Web/native/provider QA, including refresh and wrong-workspace fencing.

make gate-full passed for fingerprint 5b26be80c002fcf6e238b2d2931a185e3c075413 with Go lint at 0 issues. The isolated QA audit passed without blockers or warnings, and teardown reported clean: true with no survivors.

The remaining Vercel authorization check is external to the code change.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/daemon/daemon_extension_agent_fixture_e2e_integration_test.go`:
- Around line 74-76: Update the session setup exercised by this test so it
explicitly has an empty or missing AgentDef snapshot, rather than relying only
on an empty Runtime.ACPSessionID. Use the existing session creation or runtime
snapshot symbols to assert the snapshot is absent before the first prompt, then
preserve the current unbound-ACP assertion.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f3dd8b1c-032a-4aef-92cc-c1768f0c96ff

📥 Commits

Reviewing files that changed from the base of the PR and between f15d9e5 and aba3523.

⛔ Files ignored due to path filters (2)
  • docs/qa/reports/2026-08-12-issue-349-extension-agent-commands.md is excluded by !**/*.md
  • docs/qa/scenarios/ET-session-command-catalog-parity.md is excluded by !**/*.md
📒 Files selected for processing (9)
  • internal/daemon/agent_skill_catalog.go
  • internal/daemon/boot.go
  • internal/daemon/daemon_extension_agent_fixture_e2e_integration_test.go
  • internal/daemon/native_tool_dependencies.go
  • internal/daemon/native_tool_registry_skills.go
  • internal/daemon/native_tools_dependencies_builder.go
  • internal/daemon/native_tools_test.go
  • internal/daemon/prompt_skills_test.go
  • internal/daemon/session_commands.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/daemon/agent_skill_catalog.go
  • internal/daemon/boot.go
  • internal/daemon/session_commands.go
  • internal/daemon/native_tools_test.go

CreateSession stores the agent definition snapshot before ACP binding, so
the unbound-session E2E cannot construct the missing-snapshot state. Pin
that branch at the unit layer instead: a session manager whose snapshot
reader reports no cached definition must surface the dependency error on
the command_id skill view path.

Co-Authored-By: Claude Fable 5 <[email protected]>
@pedronauck
pedronauck merged commit 594d9fd into compozy:main Aug 12, 2026
22 of 23 checks passed
@franciscpd
franciscpd deleted the fix/session-commands-extension-agents branch August 12, 2026 13:23
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.

Prompting a session bound to an extension-published agent fails with 500 "skills: agent not found"

2 participants