Problem
The four actionability-gate consumers (idd-list, idd-all, idd-implement, and — since round 4 of PR #318 — idd-plan) share one allowed-tools list:
allowed-tools:
- Bash(gh:*)
- Bash(git:*)
- Bash(jq:*)
- Bash(python3:*)
It is wrong in both directions at once.
Too wide. Bash(python3:*) pre-approves python3 -c '<anything>', Bash(git:*) pre-approves git -c core.pager='!sh -c …', and Bash(gh:*) covers every write sub-command plus gh auth token. On idd-plan this sits directly against the skill's value proposition (nothing stateful before the plan is approved). scripts/tests/actionability-gate/test.sh:393-395 currently asserts that each consumer contains Bash(python3:*), so the width is pinned. idd-ask already shows the narrow form (Bash(gh issue view:*), Bash(gh search:*)).
Too narrow. The reference says the list exists "so unattended runs do not stall on a permission prompt", but the gate block's first command is . "$CLAUDE_PLUGIN_ROOT/scripts/lib/actionability.sh" || { … } — none of the four prefixes matches it, so unattended runs still stall exactly where the list promised they would not. idd-plan additionally lacks Read, EnterPlanMode / ExitPlanMode (Step 4 — the reason the skill exists), AskUserQuestion, TaskCreate / TaskUpdate, Skill; idd-implement and idd-all list those.
allowed-tools is pre-approval, not restriction (official docs: it does not restrict which tools are available), so nothing is broken today — the list simply fails to do what the contract says it is for, on three consumers before round 4 and on four after.
Source
Expected
One list, derived from what the gate block and each skill actually run, applied to all four consumers:
- Bash prefixes narrowed to the commands used:
Bash(gh api:*), Bash(gh issue view:*), Bash(gh issue list:*) (idd-list), Bash(jq:*); python3 restricted to the skill's own script path or removed if the inline snippet moves into scripts/lib/; git only where a consumer actually runs it (idd-implement's branch creation), never on idd-plan.
- The gate block's source line covered — either a prefix form the permission matcher accepts for
. path, or the block rewritten to invoke a named script so Bash(bash $CLAUDE_PLUGIN_ROOT/scripts/*)-style matching applies. Verify the chosen form against the permissions reference before committing to it.
idd-plan gains the non-Bash tools it calls: Read, EnterPlanMode, ExitPlanMode, AskUserQuestion, TaskCreate, TaskUpdate, Skill.
test.sh:393-395 asserts the narrowed set and refutes Bash(python3:*) / bare Bash(git:*) on idd-plan.
Acceptance criteria
Complexity
Simple — four frontmatter edits and one assertion; the only open question is which prefix form matches a . path source line, and that is a documentation lookup, not a design decision.
Problem
The four actionability-gate consumers (
idd-list,idd-all,idd-implement, and — since round 4 of PR #318 —idd-plan) share oneallowed-toolslist:It is wrong in both directions at once.
Too wide.
Bash(python3:*)pre-approvespython3 -c '<anything>',Bash(git:*)pre-approvesgit -c core.pager='!sh -c …', andBash(gh:*)covers every write sub-command plusgh auth token. Onidd-planthis sits directly against the skill's value proposition (nothing stateful before the plan is approved).scripts/tests/actionability-gate/test.sh:393-395currently asserts that each consumer containsBash(python3:*), so the width is pinned.idd-askalready shows the narrow form (Bash(gh issue view:*),Bash(gh search:*)).Too narrow. The reference says the list exists "so unattended runs do not stall on a permission prompt", but the gate block's first command is
. "$CLAUDE_PLUGIN_ROOT/scripts/lib/actionability.sh" || { … }— none of the four prefixes matches it, so unattended runs still stall exactly where the list promised they would not.idd-planadditionally lacksRead,EnterPlanMode/ExitPlanMode(Step 4 — the reason the skill exists),AskUserQuestion,TaskCreate/TaskUpdate,Skill;idd-implementandidd-alllist those.allowed-toolsis pre-approval, not restriction (official docs: it does not restrict which tools are available), so nothing is broken today — the list simply fails to do what the contract says it is for, on three consumers before round 4 and on four after.Source
plugins/issue-driven-dev/references/actionability-gate.md(Prerequisites /allowed-tools).Expected
One list, derived from what the gate block and each skill actually run, applied to all four consumers:
Bash(gh api:*),Bash(gh issue view:*),Bash(gh issue list:*)(idd-list),Bash(jq:*);python3restricted to the skill's own script path or removed if the inline snippet moves intoscripts/lib/;gitonly where a consumer actually runs it (idd-implement's branch creation), never onidd-plan.. path, or the block rewritten to invoke a named script soBash(bash $CLAUDE_PLUGIN_ROOT/scripts/*)-style matching applies. Verify the chosen form against the permissions reference before committing to it.idd-plangains the non-Bash tools it calls:Read,EnterPlanMode,ExitPlanMode,AskUserQuestion,TaskCreate,TaskUpdate,Skill.test.sh:393-395asserts the narrowed set and refutesBash(python3:*)/ bareBash(git:*)onidd-plan.Acceptance criteria
allowed-toolslist; noBash(python3:*)on any of themidd-planlists every non-Bash tool its steps invoketest.shpins the narrowed list and refutes the wide prefixesComplexity
Simple — four frontmatter edits and one assertion; the only open question is which prefix form matches a
. pathsource line, and that is a documentation lookup, not a design decision.