feat(cli): add openspec agent command group — cut tokens + turns for AI skills#1132
feat(cli): add openspec agent command group — cut tokens + turns for AI skills#1132jussirantala wants to merge 4 commits into
openspec agent command group — cut tokens + turns for AI skills#1132Conversation
Three new verb-first agent helper commands that let AI skills drive the OpenSpec workflow without re-implementing CLI orchestration. Also enriches the existing 'instructions apply --json' payload with numericId and nextPendingId fields so downstream callers can target tasks by author- supplied hierarchical id (1.1, 2.3.4) rather than position. - openspec resolve-change [name] [--auto] [--json]: list active changes, validate a named change, or auto-select when exactly one is active. - openspec next-artifact --change <name>: bundle status next-ready artifact lookup with full instructions in one JSON payload, so skills can run a propose loop with one call per artifact instead of two. - openspec mark-task-done --change <name> <task-id>: flip a tracked tasks.md checkbox by hierarchical task id with anchored matching (1.1 does not match 1.10), EOL preservation, idempotent on already-done lines. Existing parseTasksFile() now also captures the leading N(.N)* token into a new optional 'numericId' field on TaskItem; legacy positional 'id' remains unchanged. ApplyInstructions gains a 'nextPendingId' field (first unchecked task that has a numericId, or null).
…pers - propose template: collapse status + instructions loop into a single next-artifact call. Drops one round-trip per artifact and removes ~30 lines of LLM-facing orchestration prose from both the skill and the command variants. - apply-change template: replace 'openspec list --json + AskUserQuestion' flow with 'openspec resolve-change --auto'; collapse status + apply instructions into a single 'instructions apply --change --json' call (which now includes schemaName + nextPendingId); swap manual checkbox editing for 'openspec mark-task-done'. - Update completion command registry with the three new commands. - Refresh hash gates in skill-templates-parity test. - Add CLI docs (docs/cli.md) for resolve-change / next-artifact / mark-task-done plus a note on the new numericId / nextPendingId fields on 'instructions apply --json'. - Add agent-helpers changeset (minor).
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (5)
📝 WalkthroughWalkthroughThis PR adds three agent helper CLI commands (resolve-change, next-artifact, mark-task-done), enriches instruction/task payloads with per-task numericId and nextPendingId, integrates commands into the CLI/completions, updates workflow templates to use the new commands, and adds docs and comprehensive tests. ChangesAgent Helper Commands and Task Metadata Enrichment
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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 |
These three commands are explicitly skill-facing — keeping them as
top-level verbs polluted `openspec --help` for human users with three
lines they never need. Move them under a dedicated `openspec agent`
subcommand group instead, so the top-level surface stays focused on
human workflows and agents call `openspec agent <subcommand>`
explicitly.
- src/cli/index.ts: nest under `agent` subcommand group.
- src/core/completions/command-registry.ts: register `agent` as a
subcommand group entry.
- src/core/templates/workflows/{propose,apply-change}.ts: update skill
+ command template invocations to the new namespace.
- docs/cli.md: rename section headers + Agent-Compatible table entries.
- test/commands/agent-helpers.test.ts: prefix every runCLI call with
`agent`.
- test/core/templates/skill-templates-parity.test.ts: refresh function
payload + generated content hashes for the two refactored templates.
- .changeset/agent-helpers.md: re-describe surface as a command group.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
test/commands/agent-helpers.test.ts (1)
138-146: ⚡ Quick winUse canonical path comparison for path identity assertions.
This test is asserting path identity via suffix matching. Compare canonicalized actual/expected paths instead, and keep any spelling checks separate if needed.
Suggested fix
-import { promises as fs } from 'fs'; +import { promises as fs, realpathSync } from 'fs'; @@ const json = JSON.parse(result.stdout); expect(json.name).toBe('alpha'); expect(typeof json.path).toBe('string'); - expect(json.path.endsWith('alpha')).toBe(true); + const expectedPath = realpathSync.native(path.join(changesDir, 'alpha')); + const actualPath = realpathSync.native(json.path); + expect(actualPath).toBe(expectedPath);As per coding guidelines: "When asserting existing filesystem paths as identities in tests, canonicalize both actual and expected paths using
fs.realpathSync.native()".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/commands/agent-helpers.test.ts` around lines 138 - 146, The test currently checks path identity with a suffix check; update the assertion in the '--json with a named change emits structured payload' spec to canonicalize both actual and expected paths using fs.realpathSync.native before comparing. Specifically, call fs.realpathSync.native(json.path) and fs.realpathSync.native(path.join(tempDir, 'alpha')) (or the equivalent expected path used in the test) and assert they are strictly equal; keep the existing typeof and name assertions unchanged and import/require fs and path if not already present.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/cli.md`:
- Around line 880-882: The fenced code blocks containing command synopses like
"openspec resolve-change [name] [options]", "openspec next-artifact --change
<name> [options]", and "openspec mark-task-done <task-id> --change <name>
[options]" are missing language identifiers; update each triple-backtick fence
that wraps these command lines to include a language tag (e.g., ```bash) so
markdownlint MD040 is satisfied. Locate the three command synopsis blocks (and
the analogous blocks containing the same commands elsewhere) and prepend "bash"
to the opening ``` of each fenced code block.
In `@src/core/templates/workflows/apply-change.ts`:
- Line 39: The template string in apply-change.ts uses an incorrect command
token `openspec-continue-change`; update the blocked-state wording to use the
proper CLI command form (for example replace `openspec-continue-change` with
`openspec continue-change` or the intended alias) so it matches other template
commands and avoids misleading users; locate the string near where `state`:
`"blocked"` is described and update that literal to the corrected command text.
In `@src/core/templates/workflows/propose.ts`:
- Around line 43-67: Update the template text to consistently reference the
payload returned by openspec next-artifact instead of referring to openspec
instructions; specifically, change any guidance that tells users to follow
fields from "openspec instructions" to read and act on the JSON payload from
"openspec next-artifact" (fields: artifactId, resolvedOutputPath, template,
instruction, context, rules, dependencies), ensure steps that list using the
TodoWrite tool, AskUserQuestion tool and the loop logic all explicitly reference
the next-artifact response structure, and apply the same replacement for the
other occurrence noted around lines 138-162 so there is no mention of "openspec
instructions" anywhere in the propose workflow template.
---
Nitpick comments:
In `@test/commands/agent-helpers.test.ts`:
- Around line 138-146: The test currently checks path identity with a suffix
check; update the assertion in the '--json with a named change emits structured
payload' spec to canonicalize both actual and expected paths using
fs.realpathSync.native before comparing. Specifically, call
fs.realpathSync.native(json.path) and fs.realpathSync.native(path.join(tempDir,
'alpha')) (or the equivalent expected path used in the test) and assert they are
strictly equal; keep the existing typeof and name assertions unchanged and
import/require fs and path if not already present.
🪄 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: CHILL
Plan: Pro
Run ID: 5a833d91-893c-404f-bc41-9bc2c0437d0e
📒 Files selected for processing (14)
.changeset/agent-helpers.mddocs/cli.mdsrc/cli/index.tssrc/commands/workflow/index.tssrc/commands/workflow/instructions.tssrc/commands/workflow/mark-task-done.tssrc/commands/workflow/next-artifact.tssrc/commands/workflow/resolve-change.tssrc/commands/workflow/shared.tssrc/core/completions/command-registry.tssrc/core/templates/workflows/apply-change.tssrc/core/templates/workflows/propose.tstest/commands/agent-helpers.test.tstest/core/templates/skill-templates-parity.test.ts
openspec agent command group — cut tokens + turns for AI skills
- docs/cli.md: add 'bash' language tag to the three new agent subcommand synopsis fences (markdownlint MD040). Lines 880, 929, 992. - src/core/templates/workflows/propose.ts: replace stale 'openspec instructions' guideline reference with 'openspec agent next-artifact' to match the refactored loop. Both skill + command variants. - src/core/templates/workflows/apply-change.ts: disambiguate the blocked-state message — 'suggest openspec-continue-change' → 'suggest the `openspec-continue-change` skill'. Skill name, not CLI command form. - Refresh template parity hashes for the three affected functions.
Summary
Adds an
openspec agentcommand group whose sole reason for existing is to cut token usage and round-trips when an AI assistant drives the OpenSpec workflow. Today the bundled skill templates (openspec-propose,openspec-apply-change) inline a multi-step CLI dance in their prompt text —status --json, theninstructions <artifact> --json, then re-checkstatus, then manually edittasks.mdcheckboxes. Every round-trip is its own tool call, its own JSON parse, and its own prompt-text overhead, and every consumer ends up rewriting the same orchestration in their own repo. This PR moves three deterministic operations into the CLI itself and updates the bundled templates so anopenspec updateslims the skills automatically.Estimated impact on a typical 30-task propose+apply cycle: ~15–20% fewer tokens, ~30–50 fewer turns, ~10–12 minutes of wall-clock saved.
The new commands sit under a dedicated
agentnamespace rather than at the top level — they're explicitly skill-facing, not user-facing, and shouldn't polluteopenspec --helpfor human users.Added
openspec agent resolve-change [name] [--auto] [--json]list --json+ name-validation + ambiguity handling in every skill0ok,1none,2not found,3ambiguous) so callers branch without parsing stderr.openspec agent next-artifact --change <name>status --json+instructions <artifact> --json{ "done": true }when complete.openspec agent mark-task-done <task-id> --change <name>- [ ]→- [x]1.1does not match1.10. Resolves tracking file via schema'sapply.tracks.Changed
openspec instructions apply --change <n> --jsonpayload is enriched:tasks[].numericId— captures the leadingN(.N)*token (e.g."1.1","2.3.4") when the tracking file uses numbered tasks. Existing positionalidfield is unchanged.nextPendingId(top-level) — first unchecked task with anumericId, ornull. Pairs withagent mark-task-doneto drive an apply loop without re-parsingtasks.md.src/core/templates/workflows/{propose,apply-change}.tsnow use the three new commands instead of inlining orchestration. After this lands, downstream consumers runopenspec updateand pick up the slimmer skill bodies automatically. Other workflow templates (continue-change,archive-change,explore,new-change,sync-specs,verify-change,bulk-archive-change,ff-change) are intentionally left untouched in this PR to keep review surface small; they can be migrated incrementally.Non-goals
status,instructions,list,archive,new change,set changeare unchanged.loadChangeContext,formatChangeStatus,generateInstructions,generateApplyInstructions,resolveSchema).Backward compatibility
TaskItemgains optionalnumericId; existing consumers that key offid/description/donekeep working. Note: when a numeric prefix is detected thedescriptionfield no longer carries the leading1.1— this is the intentional improvement (consumers should display bynumericIdif present, else by positionalid).ApplyInstructionsgainsnextPendingId; existing consumers ignore it.Validation
pnpm installpnpm run buildpnpm testzsh-installerWindows-only chmod tests that fail on my machine also fail on cleanupstream/main— confirmed by stashing my changes and re-running. Not regressions from this PR.test/commands/agent-helpers.test.tscovering list mode, named lookup,--autoambiguity matrix,next-artifacthappy path / mid-stream / all-done,mark-task-doneflip / idempotent /1.1vs1.10boundary / CRLF preservation / schema withoutapply.tracks/ no-match, plus three cases on the enrichedinstructions apply --jsonpayload.test/core/templates/skill-templates-parity.test.tsfor the two refactored templates (function payload + generated skill content).openspec init'd workspace:Notes
.mjshelper files that wrapped the sameopenspecinvocations. Once this PR is released, that repo and any other consumer can drop their local helper scripts and runopenspec updateto regenerate the slimmer skill templates.origin/mainbefore pushing so the PR diff is clean.Summary by CodeRabbit
New Features
Documentation