You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Part of #170 (Epic D, Phase 2). Depends on the reusable lifecycle contract in sibling issue #312.
Goal
Ensure Claude Code subagent tool calls are governed by a verified attenuated child passport rather than merely attributed to an observed child while continuing under parent authority.
Verified current gap
python/vibap/claude_code_hook.py records SubagentStart/SubagentStop receipts and labels a copy of the active parent policy as inherited_policy. It does not issue or bind a child passport.
The current official hook contract matters:
PreToolUse can block the Agent tool before execution.
SubagentStart runs after creation, cannot block the spawn, and exposes agent_id/agent_type but no parent Agent tool-use correlation ID.
Therefore SubagentStart alone cannot provide a race-free dynamic per-prompt authority handoff, especially for parallel same-type spawns.
Observation or context injection is not authority adoption.
What to build
Gate the Claude Agent tool at PreToolUse and atomically reserve/derive child authority before allowing spawn.
Use an operator-authored agent-type policy registry as the safe correlation boundary for CLI hooks. Concurrent same-type spawns may be interchangeable only when their derived policies are byte-equivalent; otherwise fail closed rather than guess.
At SubagentStart, bind the observed (session_id, agent_id, agent_type) to an eligible pending child reservation and inject only a bounded opaque child handle/context marker.
Route subsequent PreToolUse events carrying that agent_id through the bound child session. Never fall back to parent authority when a child binding is missing, ambiguous, expired, closed, or mismatched.
Settle/close the child on SubagentStop; quarantine reservations on missing stop, crash, or timeout for bounded reconciliation.
Rename receipt fields so inherited_policy cannot overclaim enforcement before binding. Preserve explicit states such as observed-only, pending, bound, denied, closed, and unverified child receipt summary.
If current hook inputs cannot safely support a requested dynamic policy mode, document it as unsupported and fail closed; do not infer identity from transcript paths or timing.
Provide an Agent SDK integration path only if it exposes stronger correlation, and keep its claim boundary distinct from CLI hooks.
Acceptance criteria
Agent spawn above parent/depth/budget/policy limits is denied at PreToolUse; a test proves no spawn follows.
A bound subagent tool call is evaluated against its child passport, and a parent-only capability is denied before tool execution.
Parallel different-type and same-type spawns have deterministic, race-tested binding behavior with no authority swap.
Missing agent_id, missing pending reservation, ambiguous binding, replay, timeout, stop-before-start, duplicate stop, and process restart fail closed or quarantine safely.
Lifecycle receipts truthfully distinguish observation from enforced binding and contain no prompts, transcripts, raw credentials, secrets, or host paths.
Existing main-agent Claude Code governance remains compatible.
Unit, concurrency, hook-contract, daemon/fallback, privacy, report, package, and relevant full-suite tests pass.
Docs cite the exact supported Claude Code hook contract and limitations.
PR targets dev from an isolated EXTENDED worktree with signed DCO commits and green CI.
Non-goals
Do not claim SubagentStart can block a spawn.
Do not dynamically derive policy from untrusted prompt text.
Do not use transcript paths, timestamps, or child final text as authentication.
Do not combine this platform-specific hook work with the reusable LangGraph adapter PR.
Part of #170 (Epic D, Phase 2). Depends on the reusable lifecycle contract in sibling issue #312.
Goal
Ensure Claude Code subagent tool calls are governed by a verified attenuated child passport rather than merely attributed to an observed child while continuing under parent authority.
Verified current gap
python/vibap/claude_code_hook.pyrecordsSubagentStart/SubagentStopreceipts and labels a copy of the active parent policy asinherited_policy. It does not issue or bind a child passport.The current official hook contract matters:
PreToolUsecan block the Agent tool before execution.SubagentStartruns after creation, cannot block the spawn, and exposesagent_id/agent_typebut no parent Agent tool-use correlation ID.SubagentStartalone cannot provide a race-free dynamic per-prompt authority handoff, especially for parallel same-type spawns.Observation or context injection is not authority adoption.
What to build
PreToolUseand atomically reserve/derive child authority before allowing spawn.SubagentStart, bind the observed(session_id, agent_id, agent_type)to an eligible pending child reservation and inject only a bounded opaque child handle/context marker.PreToolUseevents carrying thatagent_idthrough the bound child session. Never fall back to parent authority when a child binding is missing, ambiguous, expired, closed, or mismatched.SubagentStop; quarantine reservations on missing stop, crash, or timeout for bounded reconciliation.inherited_policycannot overclaim enforcement before binding. Preserve explicit states such as observed-only, pending, bound, denied, closed, and unverified child receipt summary.Acceptance criteria
PreToolUse; a test proves no spawn follows.agent_id, missing pending reservation, ambiguous binding, replay, timeout, stop-before-start, duplicate stop, and process restart fail closed or quarantine safely.devfrom an isolated EXTENDED worktree with signed DCO commits and green CI.Non-goals
SubagentStartcan block a spawn.Primary sources