feat(cli): add skill command for AI agent integration#691
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds an Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Details
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/user/cli-reference.md`:
- Around line 1454-1492: The markdown blocks under the "Synopsis", "**Flags:**",
"**Install Locations:**" and "**Examples:**" headings are missing surrounding
blank lines which triggers MD031/MD058; fix by inserting a blank line before and
after the fenced code block under "Synopsis", a blank line before the table
after "**Flags:**", a blank line before the table after "**Install
Locations:**", and a blank line before the fenced code block under
"**Examples:**" (and ensure there is a blank line after each block as well) so
each block is separated from the surrounding headings and text.
In `@pkg/cli/skill_claude_code.go`:
- Around line 230-233: The verify example emits an unsupported flag; update the
fmt.Fprintf call that prints "aicr verify --bundle ./bundles" in
pkg/cli/skill_claude_code.go so the example uses a positional argument instead
(e.g., "aicr verify ./bundles") so the CLI invocation matches the actual parser
and won't cause agents to produce a parse error.
In `@pkg/cli/skill_generator.go`:
- Around line 66-71: The CLI metadata currently omits root/global flags because
cliMeta only has Name, Version, and Commands and extractCLIMeta only walks
root.Commands; add a Flags field (e.g., []flagMeta) to cliMeta and update
extractCLIMeta to also iterate and extract root.Flags (similar to how command
flags are handled in cmdMeta) so global flags like --debug and --log-json are
captured and serialized into the generated skill output; ensure any existing
flag extraction logic (the flagMeta shape and the code used for cmdMeta.Flags)
is reused for the root-level flags.
In `@pkg/cli/skill.go`:
- Around line 47-75: The skill CLI command currently contains business logic;
extract all skill generation and install behavior from skillCmd/runSkillCmd into
a new functional package (e.g., a package that exposes GenerateSkill,
ResolveInstallPath, and InstallSkill/WriteOrStdout functions) and have
runSkillCmd simply validate flags (using skillCmdFlags), call those exported
functions, and format/report results; move handling of generator dispatch,
metadata extraction, overwrite policy, path resolution, and file writes into
those new functions so pkg/cli only captures intent and delegates
implementation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 62a4ae09-02c2-4c83-8188-c47615b48d3d
📒 Files selected for processing (8)
docs/user/cli-reference.mdpkg/cli/doc.gopkg/cli/root.gopkg/cli/skill.gopkg/cli/skill_claude_code.gopkg/cli/skill_codex.gopkg/cli/skill_generator.gopkg/cli/skill_test.go
f203c2f to
d13f93b
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/cli/skill_claude_code.go`:
- Around line 164-203: The current writeCriteriaValues collects any recipe flag
with completions (recipeMeta.Flags where f.Completions != nil) which incorrectly
includes non-criteria flags like "--format"; update writeCriteriaValues to only
include true recipe criteria flags by adding an explicit filter when building
fields: check a dedicated marker (e.g., f.IsCriteria or f.Metadata["criteria"]
== "true") if available on cmdMeta.Flags, otherwise exclude known
non-criteria/global flags (e.g., skip f.Name == "format" and other global flags
or f.IsGlobal/f.Hidden if present); update the loop that appends to fields
(references: writeCriteriaValues, recipeMeta.Flags, criteriaField, f.Name,
f.Completions) to only append when the flag passes this criteria predicate.
In `@pkg/cli/skill.go`:
- Around line 120-131: The current flow does a pre-check with os.Stat and
confirmOverwrite then separately calls writeSkillFile, creating a TOCTOU race;
instead, move the overwrite decision and the actual file replacement into a
single atomic helper (update or replace writeSkillFile) that: re-checks the
destination with os.Lstat to reject symlinks, writes content to a uniquely named
temp file in the same directory, fsyncs the temp file, then atomically replaces
the target via os.Rename; ensure confirmOverwrite is called before the helper
but have the helper perform the final lstat-and-write+rename so the confirmed
path cannot be swapped between confirmation and write (references:
confirmOverwrite, writeSkillFile, os.Lstat, os.Rename).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 5b0c28b4-64fa-4989-9643-153da673271f
📒 Files selected for processing (8)
docs/user/cli-reference.mdpkg/cli/doc.gopkg/cli/root.gopkg/cli/skill.gopkg/cli/skill_claude_code.gopkg/cli/skill_codex.gopkg/cli/skill_generator.gopkg/cli/skill_test.go
d13f93b to
6d8af23
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
pkg/cli/skill_generator.go (1)
56-145: 🛠️ Refactor suggestion | 🟠 MajorMove the skill implementation out of
pkg/cli.These segments implement metadata extraction, generator interfaces, install-path resolution, and file-write behavior. That is domain logic, not CLI wiring, so the command still owns the implementation instead of delegating to a functional package.
Based on learnings: In this repo, ensure packages under
pkg/clicontain only CLI wiring and user-interaction helpers; moveskillGenerator,claudeCodeGenerator/codexGenerator,cliMeta, andextractCLIMetainto a dedicated package such aspkg/skill.Also applies to: 247-320
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/cli/skill_generator.go` around lines 56 - 145, The CLI package currently contains domain logic that should live in a dedicated skill package; move the types and functions skillGenerator, cliMeta, cmdMeta, flagMeta, flagType* constants, cmdNameHelp/cmdNameCompletion, isFrameworkCommand, extractCLIMeta, extractCmdMeta, extractFlagMeta and any generator implementations (e.g., claudeCodeGenerator, codexGenerator) plus their installPath/generate methods into a new package (suggested pkg/skill), change their package declaration, make any needed identifiers exported (capitalize) for cross-package use, update imports in the CLI command to call pkg/skill.ExtractCLIMeta (or renamed exports) and to construct generators from pkg/skill, and run `go vet`/`go test` to fix compile errors (import paths, visibility) introduced by the move.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/cli/skill_test.go`:
- Around line 660-683: The test builds a synthetic root instead of exercising
the real CLI root, so change TestSkillCmd_Stdout to use the actual newRootCmd()
(so runSkillCmd() reads cmd.Root() as in production): call root := newRootCmd(),
set root.Writer = &buf (retain capturing output), then run
root.Run(context.Background(),
[]string{"aicr","skill","--agent","claude-code","--stdout"}) and keep the same
assertions; this ensures the test exercises runSkillCmd(), the real top-level
metadata, and stdout formatting rather than the isolated skillCmd().
---
Duplicate comments:
In `@pkg/cli/skill_generator.go`:
- Around line 56-145: The CLI package currently contains domain logic that
should live in a dedicated skill package; move the types and functions
skillGenerator, cliMeta, cmdMeta, flagMeta, flagType* constants,
cmdNameHelp/cmdNameCompletion, isFrameworkCommand, extractCLIMeta,
extractCmdMeta, extractFlagMeta and any generator implementations (e.g.,
claudeCodeGenerator, codexGenerator) plus their installPath/generate methods
into a new package (suggested pkg/skill), change their package declaration, make
any needed identifiers exported (capitalize) for cross-package use, update
imports in the CLI command to call pkg/skill.ExtractCLIMeta (or renamed exports)
and to construct generators from pkg/skill, and run `go vet`/`go test` to fix
compile errors (import paths, visibility) introduced by the move.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 13504519-f5e9-4177-b6b6-8b8e22259a61
📒 Files selected for processing (8)
docs/user/cli-reference.mdpkg/cli/doc.gopkg/cli/root.gopkg/cli/skill.gopkg/cli/skill_claude_code.gopkg/cli/skill_codex.gopkg/cli/skill_generator.gopkg/cli/skill_test.go
6d8af23 to
194e734
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
pkg/cli/skill_generator.go (1)
56-348: 🛠️ Refactor suggestion | 🟠 MajorMove the skill-generation implementation out of
pkg/cli.This file is almost entirely functional logic: agent modeling, CLI metadata extraction, install-path resolution, file writes, and overwrite policy. That keeps the feature coupled to the UI layer instead of a reusable domain package and continues the
pkg/cliboundary violation already discussed on this PR.Based on learnings,
pkg/clihere should keep only command wiring, urfave/cli flag plumbing, and user-interaction helpers like TTY confirmation, whileskillGenerator,cliMeta,extractCLIMeta, and the generator/install helpers move to a dedicated package such aspkg/skill.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/cli/skill_generator.go` around lines 56 - 348, The code that models skills and performs generation/installation should be moved out of pkg/cli into a new pkg/skill package: extract and relocate the skillGenerator interface, cliMeta, cmdMeta, flagMeta types, constants (flagType*), the functions extractCLIMeta, extractCmdMeta, extractFlagMeta, userHomeDir, skillInstallPath, writeSkillFile (and any helper types like completableStringFlag / CompletableFlag used by these funcs) into pkg/skill; leave CLI-only wiring and user-interaction helpers (confirmOverwrite, isFrameworkCommand, and any urfave/cli command registration) in pkg/cli. After moving, update package declarations, imports, and any call sites to reference pkg/skill (e.g., skill.ExtractCLIMeta, skill.WriteSkillFile or import alias), and ensure error types (errors.*) and referenced symbols compile in the new package.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/cli/skill.go`:
- Around line 120-129: The os.Stat(path) error is being treated as "missing" for
all failures which can hide real errors; modify the logic around the os.Stat
call used with cmd.Bool("force") and confirmOverwrite so that only
os.ErrNotExist bypasses the overwrite prompt—i.e., if os.Stat(path) returns an
error, check if errors.Is(err, os.ErrNotExist) and only then proceed without
prompting; for any other stat error return that error instead; keep the existing
confirmOverwrite(path, os.Stdin, cmd.Root().Writer) and the early return
behavior when the user declines.
---
Duplicate comments:
In `@pkg/cli/skill_generator.go`:
- Around line 56-348: The code that models skills and performs
generation/installation should be moved out of pkg/cli into a new pkg/skill
package: extract and relocate the skillGenerator interface, cliMeta, cmdMeta,
flagMeta types, constants (flagType*), the functions extractCLIMeta,
extractCmdMeta, extractFlagMeta, userHomeDir, skillInstallPath, writeSkillFile
(and any helper types like completableStringFlag / CompletableFlag used by these
funcs) into pkg/skill; leave CLI-only wiring and user-interaction helpers
(confirmOverwrite, isFrameworkCommand, and any urfave/cli command registration)
in pkg/cli. After moving, update package declarations, imports, and any call
sites to reference pkg/skill (e.g., skill.ExtractCLIMeta, skill.WriteSkillFile
or import alias), and ensure error types (errors.*) and referenced symbols
compile in the new package.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: 8eeb17d6-fd65-485b-a4db-f602a93b159b
📒 Files selected for processing (8)
docs/user/cli-reference.mdpkg/cli/doc.gopkg/cli/root.gopkg/cli/skill.gopkg/cli/skill_claude_code.gopkg/cli/skill_codex.gopkg/cli/skill_generator.gopkg/cli/skill_test.go
194e734 to
be016ed
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pkg/cli/skill_claude_code.go`:
- Around line 145-159: The flag Usage text is appended verbatim and may contain
newlines/tabs which break the generated markdown; before inlining use a
normalized/sanitized string (e.g., create a local variable like usage :=
strings.Join(strings.Fields(f.Usage), " ") or strings.ReplaceAll to collapse
newlines/tabs and trim) and use that sanitized variable when building line
(replace uses of f.Usage with usage); apply the same normalization to f.Default
and elements of f.Completions if they might contain whitespace/newlines to
ensure the bullet layout in SKILL.md stays intact.
In `@pkg/cli/skill_generator.go`:
- Around line 74-80: cmdMeta currently lacks a field for positional argument
syntax so generated SKILL.md omits required args; add a field (e.g., ArgsUsage
string) to the cmdMeta struct, populate it in extractCmdMeta by reading
cmd.ArgsUsage, and update writeCommandEntry to include or append that ArgsUsage
(or emit a short synopsis combining Name and ArgsUsage) when rendering each
command so positional arguments like "<bundle-dir>" appear in the output.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: dc3e8193-6037-4a8c-9170-a8f293401939
📒 Files selected for processing (8)
docs/user/cli-reference.mdpkg/cli/doc.gopkg/cli/root.gopkg/cli/skill.gopkg/cli/skill_claude_code.gopkg/cli/skill_codex.gopkg/cli/skill_generator.gopkg/cli/skill_test.go
Adds `aicr skill --agent <claude-code|codex>` which generates a skill file that teaches a coding agent how to use the AICR CLI and installs it to the agent's standard discovery location: claude-code → ~/.claude/skills/aicr/SKILL.md codex → ~/.codex/skills/aicr/SKILL.md Both agents share the same generated content (Claude Code is the canonical generator; the Codex generator delegates to it) so the two skills stay aligned. Only the install path differs. The generator walks the live urfave/cli command tree and emits YAML frontmatter (name, description, user_invocable), a dynamic command reference covering both root-level (global) flags and per-command flags with aliases/defaults/required/completions, a criteria values section pulled from the recipe command's criterion flags, plus prerequisites, output-format guidance, workflow examples, error handling, and best practices. Filtering rules applied during extraction: - Hidden commands and the skill command itself are excluded. - Auto-generated --help/--version flags are excluded. - urfave/cli/v3 auto-injects an unhidden "help" subcommand on every non-leaf command via setupDefaults->ensureHelp at Run() time. This filter excludes "help" so the SKILL.md does not document framework plumbing as an AICR workflow command. - The shell-completion command added via EnableShellCompletion is similarly filtered. (root.go's ConfigureShellCompletionCommand sets Hidden=false on it; the name-based filter catches it regardless.) - The criteria values section uses an explicit allowlist (service, accelerator, intent, os, platform) so completable but non-criterion flags such as --format are not mislabeled as criteria. Flags: --agent <name> target coding agent (required, completable) --stdout print to stdout instead of writing to disk --force overwrite an existing skill file without prompting Overwrite safety: - When the target file exists and --force is not set, the command prompts "overwrite? [y/N]" on a TTY and aborts on no/empty/EOF. - Non-TTY stdin is rejected with a hint to use --force, so CI runs do not silently clobber files. - writeSkillFile uses os.Lstat to refuse overwriting a symlink at the target, then writes via os.CreateTemp + os.Rename so the replace is atomic and TOCTOU-safe (an attacker cannot redirect the write by swapping the path between confirmation and write). extractFlagMeta detects the *completableStringFlag wrapper explicitly so its Usage, Default, Required, and Completions are captured — previously the wrapper fell through to the generic default branch and those fields were dropped. Tests cover metadata extraction (including post-Run() state with auto-injected help/completion subcommands filtered out), agent parsing, install paths, generator content equivalence, the criteria allowlist, the symlink rejection guard, the prompt flow (yes/no/empty/EOF/non-TTY), --force overwrite, and the existing structural CLI checks.
be016ed to
3af09fa
Compare
Co-authored-by: Mark Chmarny <[email protected]>
Summary
Adds
aicr skill --agent <claude-code|codex>which generates a skill file from the live CLI command tree and installs it to the agent's standard discovery location, with--stdoutfor preview,--forcefor non-interactive overwrite, and a[y/N]prompt on TTY when the target file exists.Motivation / Context
Coding agents (Claude Code, Codex) need a structured "skill" file to discover and correctly invoke the AICR CLI. Hand-maintained skill files drift from the CLI flag/criteria surface; this command generates the file from the same urfave/cli command tree the user runs, so it stays in sync automatically.
Fixes: N/A
Related: N/A
Type of Change
Component(s) Affected
cmd/aicr,pkg/cli)docs/,examples/)Implementation Notes
claudeCodeGeneratorproduces the canonical content;codexGenerator.generatedelegates to it. Only the install path differs (~/.claude/skills/aicr/SKILL.mdvs~/.codex/skills/aicr/SKILL.md), so the two skills cannot drift.extractCLIMetaexcludes theskillcommand itself and any hidden commands;extractFlagMetaexcludes auto-generatedhelp/versionflags.extractFlagMetamatches*completableStringFlagexplicitly so Usage/Default/Required/Completions are captured. (Without this, the wrapper falls through to a generic default branch and those fields are dropped.)--forceis not set: promptoverwrite? [y/N]on TTY (empty/EOF/unknown answers default to no); on non-TTY stdin (CI, piped), refuse with a hint to use--forcerather than silently clobber.writeSkillFileis a pure write; existence/confirmation lives in the caller so test-only writes don't fight the prompt logic.Testing
Coverage (pkg/cli): 37.5% → 50.5% (+13.0%); no new exported symbols.
End-to-end smoke test on this branch:
Risk Assessment
Rollout notes: New command in the
Utilitiescategory; no existing behavior touched.aicr skillwrites only to the user's home directory (~/.claude/...or~/.codex/...), never to the repo. No flags, env vars, or APIs renamed.Checklist
make testwith-race)make lint)git commit -S)