feat(skills): auto-approve the openspec CLI in generated skills and commands#1300
feat(skills): auto-approve the openspec CLI in generated skills and commands#1300clay-good wants to merge 2 commits into
Conversation
Emit `allowed-tools: Bash(openspec:*)` in every generated SKILL.md so agents that honor the Agent Skills standard run `openspec` commands without prompting on each call. Scope is limited to the CLI; per the standard `allowed-tools` pre-approves rather than restricts, so every other tool a skill uses stays available under the user's normal permission settings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR adds ChangesSkill auto-approval frontmatter
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Extend the allowed-tools pre-approval to the second surface: Claude Code /opsx:* slash commands share the skill frontmatter contract, so the Claude command adapter now emits `allowed-tools: Bash(openspec:*)` too. The value is single-sourced in `src/core/shared/allowed-tools.ts` (a leaf module both surfaces import). Other command adapters are unchanged — no other tool's slash-command format defines a per-command pre-approval field; on the skills side every tool already gets the standard field via generateSkillContent and non-implementing tools ignore the unknown key. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
alfred-openspec
left a comment
There was a problem hiding this comment.
Reviewed the permission scope and generated-frontmatter compatibility. This looks appropriately narrow, and the targeted generation tests plus strict change validation pass on my side.
What was missing
Every generated OpenSpec skill and
/opsx:*slash command drives theopenspecCLI (openspec list,status,instructions, …), but nothing pre-approved those calls. Agents that gate Bash on permission therefore prompt the user on every singleopenspecinvocation, stalling the workflow on approvals for a first-party CLI the user already installed.The Agent Skills standard has the fix — an
allowed-toolsfrontmatter field that pre-approves listed tools while a skill is active (spec, example given is exactly this form). We just weren't emitting it.This is the narrowly-scoped follow-up to #1284 (closing): it keeps only the "auto-approve OpenSpec commands" piece.
What it does
Two surfaces, one shared constant (
src/core/shared/allowed-tools.ts):SKILL.md(all supported tools' skills directories) carriesallowed-tools: Bash(openspec:*), emitted centrally ingenerateSkillContent, soinit,update, and every current and future skill get it uniformly..claude/commands/opsx/*.md(commands share the skill frontmatter contract).Deliberately scoped to the
openspecCLI only.allowed-toolspre-approves — it does not restrict — so every other tool a skill uses (Read, Write, arbitrary Bash for builds/tests inapply/onboard) still follows the user's existing permission settings. We are not blanket-approving arbitrary shell. The:*form enforces a word boundary (openspec …matches;openspecfoodoesn't) and compound commands (openspec x && rm y) don't inherit the approval.Cross-tool compatibility (verified against official docs/source)
/opsx:*commands stop prompting onopenspeccallsname/description/metadata, serde drops unknown keys (verified incodex-rs/core-skillssource)allowed-toolsbut uses its own bare tool names (shell); our value is inert there. Emittingshellwould pre-approve all shell — over-broad, so intentionally not doneNo surveyed tool errors on an unknown frontmatter key — worst case is status quo (prompts), never worse. Other tools' slash-command formats define no per-command pre-approval field (their approvals live in global config, e.g. Codex
config.toml), so only the Claude adapter changes.Proof it works
openspec init --tools claudeinto a fresh repo emits the field in all 11 skills and all 9 commands (checked exhaustively withgrep -L), and the value parses as the YAML stringBash(openspec:*)with a real YAML parser:skill-templates-parity.test.tsregenerated; command-template function hashes untouched (adapter-level change).openspec validate add-skill-cli-auto-approval --strictpasses.Notes / nits
cli-init(Skill Generation gains the pre-approval scenario) andcommand-generation(Claude adapter frontmatter gains the field). The stale "9 skill directories" list in cli-init is intentionally left untouched.allowed-toolsis marked Experimental in the standard ("support may vary") — which is exactly the safe posture here: pure upside where honored, no-op where not.🤖 Generated with Claude Code