Skip to content

fix(mod): open a subagent card only once Claude Code allowed the Agent call - #75

Merged
omartelo merged 1 commit into
mainfrom
fix/agent-cards-permission-check
Oct 10, 2026
Merged

omartelo merged 1 commit into
mainfrom
fix/agent-cards-permission-check

Conversation

@omartelo

Copy link
Copy Markdown
Collaborator

Fixes #74.

Cause

hooks/agent-cards.js answered the Agent tool.call without calling next. In Claude Code, next is where the permission flow lives: rules, mode, the dialog and PreToolUse hooks. So none of them ever applied to a call the mod took. Measured on 2.1.296: with permissions.ask: ["Agent"], the old mod opened the lich session and no dialog appeared at all.

Fix

The mod still decides in tool.call whether it takes the call, but it now passes the call on to next. It opens the worker at agent.spawn, which Claude Code raises only once the call was allowed and before the native agent or its worktree exist. There it denies the native spawn and answers the Agent call with lich's outcome. A call refused at the permission check never reaches agent.spawn, so lich opens nothing. The fallback to the native agent before lich has the task, and the deny on Esc, behave as before.

Verification

  • node --test tests/*.test.mjs: 417/417. The two new tests in agent-cards.test.mjs (a refused call opens nothing; a refusal does not affect the next allowed call) fail against the old mod.
  • claude plugin test .: 32/32.
  • Live session on Claude Code 2.1.296 with --plugin-dir, a fake LICH_BIN and an ask rule on Agent:
    • Rejected at the dialog: the fake lich was never called.
    • Approved: lich open --worktree subagent/... ran, the call came back as a backgrounded agent, and no native worktree was left over.

Test changes

  • The fake engines in agent-cards.test.mjs and prompt-text.test.mjs now model what was measured: beneath an Agent call's next, the permission decision comes first, then agent.spawn, then the native agent. The existing assertions are unchanged.
  • Four tests in agent-cards.engine.test.ts pinned the open happening above next. The kit refuses $.agent.spawn from a test's hook, so it cannot express the new chain. They now assert what it can: a taken call reaches the permission check, and a refusal there runs no lich. The open path is covered by the unit suite and the live run.

…t call

The agent-cards mod answered the Agent tool.call before calling next, which
is where Claude Code applies its permission rules, mode, dialog and PreToolUse
hooks. A deny or ask rule never applied, and a call the user rejected could
still open a lich session that ran the task.

The mod now passes a call it takes on beneath it and opens the worker at
agent.spawn, which Claude Code raises only once the call was allowed and
before the native agent or its worktree exist; it denies that spawn and
answers the Agent call with lich's outcome. Both orders measured on 2.1.296.

Fixes #74
@omartelo
omartelo merged commit cacb98b into main Oct 10, 2026
3 checks passed
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.

A rejected Agent tool call still opens a lich session

1 participant