Skip to content

feat: prioritize TOON format for agent parsing with JSON fallback - #1497

Closed
DyanGalih wants to merge 7 commits into
Fission-AI:mainfrom
DyanGalih:feat/toon-first-parsing
Closed

feat: prioritize TOON format for agent parsing with JSON fallback#1497
DyanGalih wants to merge 7 commits into
Fission-AI:mainfrom
DyanGalih:feat/toon-first-parsing

Conversation

@DyanGalih

@DyanGalih DyanGalih commented Aug 3, 2026

Copy link
Copy Markdown

What

This PR updates the agent skill instructions (specifically openspec-bulk-archive-change) to explicitly prioritize parsing OpenSpec's structured --toon serialized output over standard JSON, while retaining a robust --json fallback mechanism.

Why

The primary motivation for this change is token efficiency for advanced LLM integrations.

  • TOON is a highly compact serialization format that significantly reduces token overhead, allowing agents to maintain a larger context window while processing OpenSpec status outputs.
  • Previously, agents relied strictly on parsing standard JSON outputs. By utilizing the new --toon flag, we optimize token usage without sacrificing the structured data needed by the agents.
  • Fallback safety: We explicitly configured the skills to fallback to --json parsing. If the agent encounters a parsing failure with the compact TOON format, it will automatically retry the command with --json and parse the standard format to guarantee workflow completion.

Verification

  • Agent skills successfully updated to implement TOON-first logic.
  • JSON fallback gracefully defined as an alternative path.
  • Verified locally using OpenSpec's architecture governance and artifact verification checks.

Summary by CodeRabbit

  • New Features
    • Added selectable CLI output formats: compact JSON, pretty-printed JSON, and TOON.
    • Added --json-pretty and --toon options across supported commands.
    • Added interactive setup support for choosing a default JSON or TOON format.
    • Saved the selected output format in project configuration.
    • Added consistent format-aware success and error responses across commands, with graceful fallback when TOON conversion is unavailable.

@DyanGalih
DyanGalih requested a review from a team as a code owner August 3, 2026 11:48
@DyanGalih
DyanGalih requested review from clay-good and removed request for a team August 3, 2026 11:48
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The CLI now supports JSON, pretty JSON, and TOON output. Commands propagate the selected format through success and failure responses. Initialization stores the selected agent output format in project configuration.

Changes

Output format support

Layer / File(s) Summary
Shared output formatting
package.json, src/core/format-output.ts, src/commands/shared-output.ts, src/commands/workflow/shared.ts
Adds TOON serialization and shared format-aware output helpers.
Project format configuration
src/core/project-config.ts, src/core/config-prompts.ts, src/core/init.ts
Accepts JSON or TOON during initialization and persists the selected format.
CLI format selection
src/cli/index.ts
Adds format flags, resolves output formats, passes them to commands, and formats failures.
Core command output migration
src/commands/change.ts, src/commands/validate.ts, src/core/list.ts, src/commands/config.ts, src/commands/spec.ts, src/core/archive.ts
Routes command responses through shared format-aware output.
Schema and workflow output migration
src/commands/schema.ts, src/commands/workflow/*
Adds format options and shared output handling for schema and workflow responses.
Command flags and completions
src/core/completions/*, src/commands/context.ts, src/commands/doctor.ts, src/commands/store.ts, src/commands/workset.ts, test/core/completions/*
Adds JSON-pretty and TOON flags across registered commands and updates completion tests.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Command
  participant printJson
  participant formatAgentOutput
  CLI->>Command: invoke with selected format
  Command->>printJson: pass response payload and format
  printJson->>formatAgentOutput: serialize payload
  formatAgentOutput-->>printJson: return formatted text
  printJson-->>CLI: write formatted response
Loading

Possibly related PRs

Suggested reviewers: clay-good

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: prioritizing TOON output for agent parsing with JSON fallback.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cli/index.ts (1)

305-328: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Map the new flags to json and format before dispatch.

--json-pretty sets options.jsonPretty, and --toon sets options.toon. This handler passes only options.json, so both flags leave the command in text mode. The same pattern appears in the other changed command registrations and failure handlers.

Add one output-format resolver. It should map the flags to 'json', 'json-pretty', or 'toon'. Pass json: true and the resolved format to command handlers. Pass the same format to failWithError. Reject conflicting output flags or define a documented precedence.

🤖 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 `@src/cli/index.ts` around lines 305 - 328, Introduce a shared output-format
resolver for the changed command registrations, mapping jsonPretty, toon, and
json to 'json-pretty', 'toon', or 'json' and handling conflicting flags with a
clear rejection or documented precedence. Update each affected action handler to
pass json: true and the resolved format to its command execution and to pass
that same format to failWithError, including the handler around
resolveRootForCommand and the other changed registrations.
🧹 Nitpick comments (1)
src/commands/change.ts (1)

131-131: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add a typed format option before calling printJson.

The CLI accepts --json, --json-pretty, and --toon, but the focused handlers do not pass that choice into their typed option contracts, so the selected format is read only through any. Add format?: OutputFormat to the relevant option types and call printJson(..., options.format ?? 'json-pretty') instead of relying on each json?: boolean branch to default to 'json'.

🤖 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 `@src/commands/change.ts` at line 131, Add format?: OutputFormat to the typed
option contracts used by the focused handlers, then update every printJson call
at src/commands/change.ts:131-131, src/commands/change.ts:189-189,
src/commands/change.ts:267-267, src/commands/config.ts:241-241,
src/commands/spec.ts:120-120, src/commands/spec.ts:189-189,
src/commands/spec.ts:241-241, src/commands/workflow/schemas.ts:28-28, and
src/commands/workflow/templates.ts:86-86 to pass options.format ?? 'json-pretty'
instead of reading format through any or deriving it from json flags. Ensure the
existing CLI choices --json, --json-pretty, and --toon flow through the typed
format option.
🤖 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 `@src/cli/index.ts`:
- Around line 184-195: Update the output-format prompt guard around
agentOutputFormat to match InitCommand.canPromptInteractively(): only prompt
when options?.tools is undefined and isInteractive receives { interactive:
options?.interactive }, preventing prompts for --no-interactive and --tools
invocations.

In `@src/commands/validate.ts`:
- Line 219: Preserve the resolved OutputFormat by passing it to every affected
printJson call instead of boolean literals or relying on the default:
src/commands/validate.ts lines 219, 311, and 367; src/core/list.ts lines 113,
151, 174, 184, and 208; src/core/archive.ts line 271; src/commands/schema.ts
lines 372-375, 420-424, 467-470, 499-503, 519-524, 538-541, 565-568, 582-586,
605-609, 638-645, 655-658, 694-697, 713-717, 790-794, 904-910, and 925-928;
src/commands/workflow/instructions.ts lines 172, 515, and 621; and
src/commands/workflow/status.ts line 114.

In `@src/core/project-config.ts`:
- Around line 46-50: Update readProjectConfig to validate raw.agentOutputFormat
with the same z.enum(['json', 'toon']) schema and assign the parsed result to
config.agentOutputFormat, preserving optional behavior when the field is absent.

---

Outside diff comments:
In `@src/cli/index.ts`:
- Around line 305-328: Introduce a shared output-format resolver for the changed
command registrations, mapping jsonPretty, toon, and json to 'json-pretty',
'toon', or 'json' and handling conflicting flags with a clear rejection or
documented precedence. Update each affected action handler to pass json: true
and the resolved format to its command execution and to pass that same format to
failWithError, including the handler around resolveRootForCommand and the other
changed registrations.

---

Nitpick comments:
In `@src/commands/change.ts`:
- Line 131: Add format?: OutputFormat to the typed option contracts used by the
focused handlers, then update every printJson call at
src/commands/change.ts:131-131, src/commands/change.ts:189-189,
src/commands/change.ts:267-267, src/commands/config.ts:241-241,
src/commands/spec.ts:120-120, src/commands/spec.ts:189-189,
src/commands/spec.ts:241-241, src/commands/workflow/schemas.ts:28-28, and
src/commands/workflow/templates.ts:86-86 to pass options.format ?? 'json-pretty'
instead of reading format through any or deriving it from json flags. Ensure the
existing CLI choices --json, --json-pretty, and --toon flow through the typed
format option.
🪄 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 Plus

Run ID: ce707705-a1b9-41f8-9aee-780769c0bd42

📥 Commits

Reviewing files that changed from the base of the PR and between 45cca5d and 81e7795.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • package.json
  • src/cli/index.ts
  • src/commands/change.ts
  • src/commands/config.ts
  • src/commands/schema.ts
  • src/commands/shared-output.ts
  • src/commands/spec.ts
  • src/commands/validate.ts
  • src/commands/workflow/instructions.ts
  • src/commands/workflow/schemas.ts
  • src/commands/workflow/shared.ts
  • src/commands/workflow/status.ts
  • src/commands/workflow/templates.ts
  • src/core/archive.ts
  • src/core/config-prompts.ts
  • src/core/format-output.ts
  • src/core/init.ts
  • src/core/list.ts
  • src/core/project-config.ts

Comment thread src/cli/index.ts
Comment thread src/commands/validate.ts Outdated
Comment thread src/core/project-config.ts
- Updated package version in package.json from 1.7.0 to 1.8.0.
- Added @toon-format/toon as a dependency.
- Enhanced CLI commands to support TOON format output.
- Introduced printJson function to handle different output formats (JSON, pretty JSON, TOON).
- Updated various command files to utilize the new printJson function for consistent output formatting.
- Modified InitCommand to accept agentOutputFormat option for specifying output format.
- Updated project configuration schema to include agentOutputFormat.
@DyanGalih
DyanGalih force-pushed the feat/toon-first-parsing branch from 81e7795 to d28f701 Compare August 3, 2026 12:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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 `@src/cli/index.ts`:
- Around line 632-640: Update the action handler’s reserved `apply` and
`archive` branches to pass options augmented with `format:
resolveOutputFormat(options)` into `applyInstructionsCommand` and
`archiveInstructionsCommand`, matching the existing `instructionsCommand` branch
while preserving all other options.
- Around line 69-73: Normalize CLI options before command dispatch by using
resolveOutputFormat to detect any selected structured format and setting json to
true when a format is returned. Pass these normalized options to every command
so --json-pretty and --toon consistently enable machine-readable behavior while
preserving the selected output format.
🪄 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 Plus

Run ID: 622871f5-ff70-423b-8e61-200370b7e69f

📥 Commits

Reviewing files that changed from the base of the PR and between 81e7795 and d28f701.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • package.json
  • src/cli/index.ts
  • src/commands/change.ts
  • src/commands/config.ts
  • src/commands/schema.ts
  • src/commands/shared-output.ts
  • src/commands/spec.ts
  • src/commands/validate.ts
  • src/commands/workflow/instructions.ts
  • src/commands/workflow/new-change.ts
  • src/commands/workflow/schemas.ts
  • src/commands/workflow/shared.ts
  • src/commands/workflow/status.ts
  • src/commands/workflow/templates.ts
  • src/core/archive.ts
  • src/core/config-prompts.ts
  • src/core/format-output.ts
  • src/core/init.ts
  • src/core/list.ts
  • src/core/project-config.ts
  • test-spec-command-tmp/openspec/specs/auth/spec.md
  • test-spec-command-tmp/openspec/specs/payment/spec.md
🚧 Files skipped from review as they are similar to previous changes (14)
  • src/core/format-output.ts
  • src/core/project-config.ts
  • src/commands/workflow/shared.ts
  • src/core/config-prompts.ts
  • src/core/init.ts
  • src/commands/shared-output.ts
  • src/commands/workflow/status.ts
  • src/commands/spec.ts
  • src/core/archive.ts
  • src/core/list.ts
  • src/commands/config.ts
  • package.json
  • src/commands/schema.ts
  • src/commands/change.ts

Comment thread src/cli/index.ts Outdated
Comment thread src/cli/index.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/core/completions/command-registry.test.ts (1)

211-212: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add runtime output tests.

These assertions validate only COMMAND_REGISTRY metadata. They can pass while commands accept the flags but emit human output. Add focused success and failure tests for the new output modes in each command family.

As per coding guidelines, run the focused file with pnpm exec vitest run test/core/completions/command-registry.test.ts.

Also applies to: 253-262

🤖 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/core/completions/command-registry.test.ts` around lines 211 - 212, Add
focused runtime tests in test/core/completions/command-registry.test.ts for the
json-pretty and toon output modes across each affected command family, covering
both successful output and failure output rather than only COMMAND_REGISTRY
metadata. Use the existing command execution and assertion helpers, then run the
focused test file with pnpm exec vitest run
test/core/completions/command-registry.test.ts.

Source: Coding guidelines

🤖 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 `@src/commands/context.ts`:
- Around line 173-174: The output format is not propagated beyond flag
registration, so JSON-pretty and TOON selections are ignored. In
src/commands/context.ts:173-174 and src/commands/doctor.ts:198-199, add a shared
format option type to the action signatures and pass it through success and
failure output calls; in src/commands/store.ts:711-712 and
src/commands/workset.ts:619-620, extend command option types and both output
paths to use the selected format, printing TOON when the format is toon while
preserving existing JSON behavior.

---

Nitpick comments:
In `@test/core/completions/command-registry.test.ts`:
- Around line 211-212: Add focused runtime tests in
test/core/completions/command-registry.test.ts for the json-pretty and toon
output modes across each affected command family, covering both successful
output and failure output rather than only COMMAND_REGISTRY metadata. Use the
existing command execution and assertion helpers, then run the focused test file
with pnpm exec vitest run test/core/completions/command-registry.test.ts.
🪄 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 Plus

Run ID: 15c68df3-271b-4a84-bc14-d9a3f2279387

📥 Commits

Reviewing files that changed from the base of the PR and between d28f701 and 8e708c3.

📒 Files selected for processing (10)
  • src/commands/config.ts
  • src/commands/context.ts
  • src/commands/doctor.ts
  • src/commands/schema.ts
  • src/commands/spec.ts
  • src/commands/store.ts
  • src/commands/workset.ts
  • src/core/completions/command-registry.ts
  • src/core/completions/shared-flags.ts
  • test/core/completions/command-registry.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/commands/config.ts
  • src/commands/schema.ts
  • src/commands/spec.ts

Comment thread src/commands/context.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
test-hook.mjs (1)

4-17: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add executable assertions to the Commander option probes.

Both scripts only log the action options. A regression can still exit successfully.

  • test-hook.mjs#L4-L17: Assert that the action receives options.json === true.
  • test-options.js#L3-L18: Assert that --toon causes the action to receive options.json === true.
🤖 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-hook.mjs` around lines 4 - 17, The Commander option probes currently
only log action options, so regressions can exit successfully; replace those
observational logs with executable assertions. In test-hook.mjs lines 4-17,
assert that the action callback receives options.json === true, and in
test-options.js lines 3-18, assert that invoking the command with --toon causes
the action to receive options.json === true.
🤖 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 `@src/cli/index.ts`:
- Line 625: Update the empty-status output path in statusCommand to serialize
its payload through printJson(payload, options.format) instead of
JSON.stringify. Preserve the existing behavior for non-empty status results
while ensuring --toon and compact JSON formatting are honored.
- Around line 76-85: Update the return type of normalizeOptions to replace the
empty-object type {} with object, preserving the existing conditional type
behavior and returned format property.

---

Nitpick comments:
In `@test-hook.mjs`:
- Around line 4-17: The Commander option probes currently only log action
options, so regressions can exit successfully; replace those observational logs
with executable assertions. In test-hook.mjs lines 4-17, assert that the action
callback receives options.json === true, and in test-options.js lines 3-18,
assert that invoking the command with --toon causes the action to receive
options.json === true.
🪄 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 Plus

Run ID: 08fba0b3-4d26-41cc-8b10-81ac855b9f46

📥 Commits

Reviewing files that changed from the base of the PR and between 7d254be and 19d4034.

📒 Files selected for processing (3)
  • src/cli/index.ts
  • test-hook.mjs
  • test-options.js

Comment thread src/cli/index.ts Outdated
Comment thread src/cli/index.ts
@clay-good

clay-good commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Thanks for putting this together and for focusing on token efficiency. After reviewing the implementation, we are going to keep this PR closed because it breaks OpenSpec’s single canonical machine-readable contract and introduces unsafe retry semantics for mutating commands.

Current OpenSpec deliberately has one agent protocol: --json emits exactly one JSON document, with documented shapes for every command: general contract, command shapes.

This branch creates three formats across the CLI (json, json-pretty, and toon) and makes a nonstandard serialization a project-level default. The implementation has several contract failures:

  • --toon silently emits JSON when TOON encoding throws, so a caller cannot know which grammar it received: formatter fallback.
  • Initialization rewrites every generated skill by blindly replacing every --json occurrence with --toon: generated workflow mutation.
  • The project config persists that output-protocol choice, coupling checked-in project state to agent parser capabilities: config field.
  • --toon is added not only to read-only status/instructions commands but also to archive, which mutates specs and moves a change: archive option.

The PR’s advertised fallback is to retry with --json when TOON parsing fails. That is unsafe for mutation:

openspec archive add-auth --toon   # archive succeeds, parser fails
openspec archive add-auth --json   # fallback runs the mutation again

The second invocation now targets a change that has already moved and can report a misleading failure; the same pattern is worse for any future non-idempotent command. A serialization optimization must never require re-executing an operation to understand whether it succeeded.

It also adds a new runtime dependency and format branches across most commands for speculative token savings without providing a stable, independently versioned schema or parser capability negotiation. Compact consumers can already select only the fields they need from canonical JSON, while OpenSpec retains one testable protocol.

The architectural cost and ambiguity outweigh the claimed token benefit, so JSON should remain the sole machine-readable contract and this PR should not be merged.

We appreciate the substantial work that went into this. If you would like to explore a narrower proposal—such as opt-in TOON output for read-only commands, with explicit format signaling and no retry of mutations—we would be happy to discuss that design in an issue before another implementation.

@clay-good clay-good closed this Aug 4, 2026
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.

2 participants