Skip to content

feat(subagents): lean Hermes+Claude catalog with wired isolation - #111

Merged
divo12 merged 2 commits into
mainfrom
feat/lean-subagent-redesign
Aug 16, 2026
Merged

divo12 merged 2 commits into
mainfrom
feat/lean-subagent-redesign

Conversation

@divo12

@divo12 divo12 commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

User description

Summary

  • Add fail-closed explore / plan / verify builtins and wire model, permission_overlay, spawned_by, and IsolationMode on the live spawn path
  • Keep sync as the beat default; add delegation_get / delegation_stop for background lifecycle; strip host-only tools via Hermes-style blocklist
  • Optional git worktree isolation + tighten-only overlay gate; design notes in docs/designs/2026-08-09-lean-subagent-redesign.md

Companion: Chorus lean roster cut (merge dream first or pin dream SHA).

Test plan

  • uv run pytest tests/test_subagents/
  • CI green
  • Smoke spawn of builtin explore / plan / verify from a host session
  • Confirm background spawn + delegation_get / delegation_stop round-trip
  • Confirm overlay cannot widen host permissions

Made with Cursor


CodeAnt-AI Description

Add safer built-in subagents with isolated execution and controllable background work

What Changed

  • Adds explore, plan, and verify subagents to every enabled spawn catalog; explore and plan are read-only, while verify returns a strict PASS, FAIL, or PARTIAL result.
  • Restricts child tools and permissions so subagents cannot access host-only capabilities or expand the parent’s permissions.
  • Supports optional ephemeral Git worktrees for child edits, keeping changes out of the parent workspace and removing them after completion.
  • Adds delegation_get and delegation_stop for checking or stopping background subagent work; delegation access is limited to the owning session and stopped work has its own status.
  • Keeps synchronous spawning as the default, while allowing bounded nested delegation and optional model, permission, and workspace isolation settings.

Impact

✅ Safer read-only exploration and verification
✅ Child edits isolated from the parent workspace
✅ Clearer background delegation status and control

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@codeant-ai

codeant-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed 985530b Aug 16, 2026 · 15:00 15:00
✅ Reviewed your PR 046a777 Aug 09, 2026 · 16:52 16:55

@codeant-ai

codeant-ai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@greptile-apps greptile-apps 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.

divo12 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codeant-ai codeant-ai Bot added the size:XXL This PR changes 1000+ lines, ignoring generated files label Aug 9, 2026
self._timeout_seconds = timeout_seconds
self._active: dict[str, _ActiveDelegation] = {}
self._completed: defaultdict[str, deque[DelegationCompletion]] = defaultdict(deque)
self._history: dict[str, DelegationSnapshot] = {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: _history retains every delegation snapshot indefinitely, while the manager is long-lived for the harness and no deletion or retention bound is provided. Repeated background spawns will therefore grow completed results and error strings without limit. Add bounded retention or remove snapshots after they are consumed or explicitly expired. [memory leak]

Severity Level: Major ⚠️
- ⚠️ Long-lived harnesses retain every background result.
- ⚠️ Large subagent outputs increase process memory usage.
- ❌ Sustained delegation use can cause memory pressure or termination.

Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/dream/subagents/_async_delegation.py
**Line:** 83:83
**Comment:**
	*Memory Leak: `_history` retains every delegation snapshot indefinitely, while the manager is long-lived for the harness and no deletion or retention bound is provided. Repeated background spawns will therefore grow completed results and error strings without limit. Add bounded retention or remove snapshots after they are consumed or explicitly expired.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread src/dream/subagents/_overlay_gate.py Outdated
Comment on lines +25 to +26
deny_tools = frozenset(token for token in overlay if token not in _WRITE_TOKENS)
deny_writes = bool(_WRITE_TOKENS.intersection(overlay))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The overlay contract treats entries as permission capabilities to remove, but this implementation only recognizes write tokens and otherwise interprets entries as tool names. An overlay containing network or execute therefore does not block network or execution effects; it only blocks tools literally named network or execute, allowing the child to retain capabilities the declaration says to remove. Map every supported permission effect to the corresponding PermissionRequest fields before consulting the parent gate. [security]

Severity Level: Major ⚠️
- ❌ Custom subagents can retain overlaid network capabilities.
- ❌ Execution restrictions are not enforced by the child gate.
- ⚠️ Overlay behavior diverges from projection permission semantics.

Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/dream/subagents/_overlay_gate.py
**Line:** 25:26
**Comment:**
	*Security: The overlay contract treats entries as permission capabilities to remove, but this implementation only recognizes write tokens and otherwise interprets entries as tool names. An overlay containing `network` or `execute` therefore does not block network or execution effects; it only blocks tools literally named `network` or `execute`, allowing the child to retain capabilities the declaration says to remove. Map every supported permission effect to the corresponding `PermissionRequest` fields before consulting the parent gate.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

content="No async delegation manager on this session.",
is_error=True,
)
snap = await ctx.delegations.stop(args.delegation_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The stop operation is keyed only by delegation_id; it does not verify that the delegation belongs to ctx.session_id. Because the manager can contain delegations for multiple sessions, any session that obtains another session's ID can cancel its background work. Pass the caller session identity to the manager and enforce ownership before stopping. [security]

Severity Level: Major ⚠️
- ❌ One session can cancel another session's background work.
- ⚠️ Shared harness delegation lifecycle lacks isolation.
- ⚠️ Long-running delegated tasks can be externally interrupted.

Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/dream/tools/builtin/delegation_stop.py
**Line:** 31:31
**Comment:**
	*Security: The stop operation is keyed only by `delegation_id`; it does not verify that the delegation belongs to `ctx.session_id`. Because the manager can contain delegations for multiple sessions, any session that obtains another session's ID can cancel its background work. Pass the caller session identity to the manager and enforce ownership before stopping.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +27 to +32
PLAN,
VERIFY,
explore_agent,
merge_builtins,
plan_agent,
spawn_catalog_names,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The builtin resolver runs before merge_builtins, so a role that intentionally overrides explore, plan, or verify is advertised in the merged catalog but can never be selected. Resolve the merged catalog entry first, and only use the builtin resolver when no role override exists. [api mismatch]

Severity Level: Major ⚠️
- ⚠️ Custom `explore` roles are silently ignored.
- ⚠️ Advertised catalog descriptions differ from execution behavior.
- ⚠️ Role-specific tools and policies are not applied.

Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/dream/tools/builtin/spawn_subagent.py
**Line:** 27:32
**Comment:**
	*Api Mismatch: The builtin resolver runs before `merge_builtins`, so a role that intentionally overrides `explore`, `plan`, or `verify` is advertised in the merged catalog but can never be selected. Resolve the merged catalog entry first, and only use the builtin resolver when no role override exists.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment thread src/dream/_factory.py
Comment on lines +791 to +800
session_working_dir = working_dir
override_cwd = options.metadata.get(SUBAGENT_WORKING_DIR_METADATA_KEY)
if isinstance(override_cwd, str) and override_cwd:
session_working_dir = Path(override_cwd)

overlay = options.metadata.get(SUBAGENT_OVERLAY_METADATA_KEY)
child_gate = permission_gate
if isinstance(overlay, tuple) and overlay:
child_gate = wrap_permission_gate(permission_gate, overlay)
context_metadata[PARENT_PERMISSIONS_KEY] = child_gate

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: For a worktree-isolated child, session_working_dir points at the temporary worktree, but child_gate still wraps the permission policy created for the parent's working_dir. The permission checker therefore treats writes inside the child worktree as outside the allowed repository boundary and denies mutating tools, making IsolationMode.WORKTREE unusable for the operations it is intended to isolate. Build the child permission gate against the effective session working directory while preserving the parent's policy restrictions. [api mismatch]

Severity Level: Major ⚠️
- ❌ WORKTREE children cannot modify isolated checkout files.
- ⚠️ Isolated planning or verification workflows lose write-capable tools.
- ⚠️ Child sessions report permission denials instead of useful results.

Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/dream/_factory.py
**Line:** 791:800
**Comment:**
	*Api Mismatch: For a worktree-isolated child, `session_working_dir` points at the temporary worktree, but `child_gate` still wraps the permission policy created for the parent's `working_dir`. The permission checker therefore treats writes inside the child worktree as outside the allowed repository boundary and denies mutating tools, making `IsolationMode.WORKTREE` unusable for the operations it is intended to isolate. Build the child permission gate against the effective session working directory while preserving the parent's policy restrictions.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +38 to +43
snap = ctx.delegations.get(args.delegation_id)
if snap is None:
return ToolResult(
content=f"Unknown delegation_id {args.delegation_id!r}.",
is_error=True,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The tool retrieves a delegation by ID without verifying that snap.session_id matches ctx.session_id. Any session that obtains or guesses another delegation ID can read its subagent names, errors, and completed output, potentially exposing sensitive work across sessions. Enforce session ownership before returning the snapshot. [security]

Severity Level: Major ⚠️
- ❌ Cross-session polling can disclose delegation outputs.
- ⚠️ Subagent errors and names may cross session boundaries.
- ⚠️ Shared-harness background lifecycle lacks endpoint ownership enforcement.

Fix in Cursor Fix in VSCode Claude

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/dream/tools/builtin/delegation_get.py
**Line:** 38:43
**Comment:**
	*Security: The tool retrieves a delegation by ID without verifying that `snap.session_id` matches `ctx.session_id`. Any session that obtains or guesses another delegation ID can read its subagent names, errors, and completed output, potentially exposing sensitive work across sessions. Enforce session ownership before returning the snapshot.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

divo12 and others added 2 commits August 16, 2026 20:12
Ship explore/plan/verify builtins, wire model/overlay/spawned_by/isolation on
the live path, add delegation poll/stop for background spawns, and keep sync
as the beat default with a host tool blocklist.

Co-authored-by: Cursor <cursoragent@cursor.com>
Scope asynchronous delegation to its owning session and make overlays and worktree execution fail closed so the lean subagent catalog is safe to expose.

Co-authored-by: Cursor <cursoragent@cursor.com>
@divo12
divo12 force-pushed the feat/lean-subagent-redesign branch from 046a777 to 985530b Compare August 16, 2026 15:00
@codeant-ai

codeant-ai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@greptile-apps greptile-apps 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.

divo12 has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.

@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Aug 16, 2026
@divo12
divo12 merged commit 99b09bf into main Aug 16, 2026
4 checks passed
@divo12
divo12 deleted the feat/lean-subagent-redesign branch August 16, 2026 15:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant