← back to Cli Printing Press
feat(cli): add --json flag to generate, print, and vision commands
7f5c35202eed5a6f48cd8243462be953e853b886 · 2026-03-27 13:35:10 -0700 · Trevin Chow
Enables agents to programmatically extract results from the three
mutating commands. JSON goes to stdout via json.NewEncoder, matching
the existing pattern in dogfood and scorecard. All stderr output is
unchanged.
The generate command's "polished" field reflects actual outcome (not
just the flag), and print's "phases_completed" derives from pipeline
state so --resume reports correct progress.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files touched
M internal/cli/root.goM internal/cli/vision.go
Diff
commit 7f5c35202eed5a6f48cd8243462be953e853b886
Author: Trevin Chow <trevin@trevinchow.com>
Date: Fri Mar 27 13:35:10 2026 -0700
feat(cli): add --json flag to generate, print, and vision commands
Enables agents to programmatically extract results from the three
mutating commands. JSON goes to stdout via json.NewEncoder, matching
the existing pattern in dogfood and scorecard. All stderr output is
unchanged.
The generate command's "polished" field reflects actual outcome (not
just the flag), and print's "phases_completed" derives from pipeline
state so --resume reports correct progress.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
internal/cli/root.go | 45 +++++++++++++++++++++++++++++++++++++++++++++
internal/cli/vision.go | 9 +++++++++
2 files changed, 54 insertions(+)
diff --git a/internal/cli/root.go b/internal/cli/root.go
index 68b169d8..1a207e58 100644
--- a/internal/cli/root.go
+++ b/internal/cli/root.go
@@ -3,6 +3,7 @@ package cli
import (
"crypto/sha256"
"encoding/hex"
+ "encoding/json"
"fmt"
"io"
"net/http"
@@ -55,6 +56,7 @@ func newGenerateCmd() *cobra.Command {
var lenient bool
var docsURL string
var polish bool
+ var asJSON bool
cmd := &cobra.Command{
Use: "generate",
@@ -115,6 +117,7 @@ func newGenerateCmd() *cobra.Command {
}
}
+ polished := false
if polish {
fmt.Fprintln(os.Stderr, "Running LLM polish pass...")
polishResult, polishErr := llmpolish.Polish(llmpolish.PolishRequest{
@@ -126,12 +129,22 @@ func newGenerateCmd() *cobra.Command {
} else if polishResult.Skipped {
fmt.Fprintf(os.Stderr, "polish skipped: %s\n", polishResult.SkipReason)
} else {
+ polished = true
fmt.Fprintf(os.Stderr, "Polish: %d help texts improved, %d examples added, README %v\n",
polishResult.HelpTextsImproved, polishResult.ExamplesAdded, polishResult.READMERewritten)
}
}
fmt.Fprintf(os.Stderr, "Generated %s-cli at %s (from docs)\n", parsed.Name, absOut)
+ if asJSON {
+ json.NewEncoder(os.Stdout).Encode(map[string]interface{}{
+ "name": parsed.Name,
+ "output_dir": absOut,
+ "spec_files": specFiles,
+ "validated": validate,
+ "polished": polished,
+ })
+ }
return nil
}
@@ -199,6 +212,7 @@ func newGenerateCmd() *cobra.Command {
}
}
+ polished := false
if polish {
fmt.Fprintln(os.Stderr, "Running LLM polish pass...")
polishResult, polishErr := llmpolish.Polish(llmpolish.PolishRequest{
@@ -210,12 +224,22 @@ func newGenerateCmd() *cobra.Command {
} else if polishResult.Skipped {
fmt.Fprintf(os.Stderr, "polish skipped: %s\n", polishResult.SkipReason)
} else {
+ polished = true
fmt.Fprintf(os.Stderr, "Polish: %d help texts improved, %d examples added, README %v\n",
polishResult.HelpTextsImproved, polishResult.ExamplesAdded, polishResult.READMERewritten)
}
}
fmt.Fprintf(os.Stderr, "Generated %s-cli at %s\n", apiSpec.Name, absOut)
+ if asJSON {
+ json.NewEncoder(os.Stdout).Encode(map[string]interface{}{
+ "name": apiSpec.Name,
+ "output_dir": absOut,
+ "spec_files": specFiles,
+ "validated": validate,
+ "polished": polished,
+ })
+ }
return nil
},
}
@@ -229,6 +253,7 @@ func newGenerateCmd() *cobra.Command {
cmd.Flags().BoolVar(&lenient, "lenient", false, "Skip validation errors from broken $refs in OpenAPI specs")
cmd.Flags().StringVar(&docsURL, "docs", "", "API documentation URL to generate spec from")
cmd.Flags().BoolVar(&polish, "polish", false, "Run LLM polish pass on generated CLI (requires claude or codex CLI)")
+ cmd.Flags().BoolVar(&asJSON, "json", false, "Output as JSON")
return cmd
}
@@ -353,6 +378,7 @@ func newPrintCmd() *cobra.Command {
var outputDir string
var force bool
var resume bool
+ var asJSON bool
cmd := &cobra.Command{
Use: "print <api-name>",
@@ -380,6 +406,14 @@ func newPrintCmd() *cobra.Command {
}
fmt.Fprintf(os.Stderr, "\nStart with: /ce:work %s\n", state.PlanPath(pipeline.PhasePreflight))
+ if asJSON {
+ json.NewEncoder(os.Stdout).Encode(map[string]interface{}{
+ "api_name": apiName,
+ "pipeline_dir": state.OutputDir,
+ "phases_completed": countCompletedPhases(state),
+ "state_file": pipeline.StatePath(apiName),
+ })
+ }
return nil
},
}
@@ -387,6 +421,17 @@ func newPrintCmd() *cobra.Command {
cmd.Flags().StringVar(&outputDir, "output", "", "Output directory (default: ./<api-name>-cli)")
cmd.Flags().BoolVar(&force, "force", false, "Overwrite existing pipeline")
cmd.Flags().BoolVar(&resume, "resume", false, "Resume from existing checkpoint")
+ cmd.Flags().BoolVar(&asJSON, "json", false, "Output as JSON")
return cmd
}
+
+func countCompletedPhases(state *pipeline.PipelineState) int {
+ n := 0
+ for _, p := range state.Phases {
+ if p.Status == pipeline.StatusCompleted {
+ n++
+ }
+ }
+ return n
+}
diff --git a/internal/cli/vision.go b/internal/cli/vision.go
index 3a309466..2c032d6c 100644
--- a/internal/cli/vision.go
+++ b/internal/cli/vision.go
@@ -1,6 +1,7 @@
package cli
import (
+ "encoding/json"
"fmt"
"os"
"path/filepath"
@@ -12,6 +13,7 @@ import (
func newVisionCmd() *cobra.Command {
var apiName string
var outputDir string
+ var asJSON bool
cmd := &cobra.Command{
Use: "vision",
@@ -75,12 +77,19 @@ The vision command produces the structure; Phase 0 fills it with intelligence.`,
fmt.Fprintf(os.Stderr, "Visionary research template written to %s/visionary-research.md\n", absOut)
fmt.Fprintf(os.Stderr, "Run Phase 0 (SKILL.md) to fill it with real research.\n")
+ if asJSON {
+ json.NewEncoder(os.Stdout).Encode(map[string]interface{}{
+ "api_name": apiName,
+ "output_file": filepath.Join(absOut, "visionary-research.md"),
+ })
+ }
return nil
},
}
cmd.Flags().StringVar(&apiName, "api", "", "API name to research")
cmd.Flags().StringVar(&outputDir, "output", "", "Output directory (default: <api>-cli)")
+ cmd.Flags().BoolVar(&asJSON, "json", false, "Output as JSON")
return cmd
}
← 862dfa70 fix(generate): reject non-empty output directory without --f
·
back to Cli Printing Press
·
feat(cli): add --dry-run flag to generate command b494c3b8 →