Skip to content

Commit a4d6c24

Browse files
greynewellclaude
andauthored
feat: supermodel factory — AI-native SDLC orchestration (#20)
* feat: add supermodel factory command for AI-native SDLC orchestration Ports the Big Iron (github.com/supermodeltools/bigiron) SDLC workflow into the supermodel CLI as `supermodel factory` with three sub-commands: factory health — graph-based health report (circular deps, domain coupling, blast radius, prioritised recommendations) factory run — generates a graph-enriched 8-phase SDLC execution prompt for a given goal; designed to be piped into Claude Code factory improve — health analysis + prioritised, graph-driven improvement prompt ordered by coupling/circular-dep scoring The implementation follows the vertical slice architecture: internal/factory imports only from sharedKernel (api, cache, config) and owns its own zip helpers. Phase content (planning, arch_check, codegen, quality_gates, test_order, code_review, refactor, guardrails, health_cron) is embedded as Go strings, making the binary fully self-contained. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(factory): address PR review comments + add supermodel audit command Review fixes: - zip.go: deduplicate DOMAIN_RELATES edges in buildCouplingMaps to prevent inflated coupling counts from repeated graph edges - zip.go: skip symlinks in walkZip fallback (os.Open follows them, risking reads outside the repo directory) - zip.go: fall back to walkZip when worktree is dirty — git archive HEAD silently excludes uncommitted changes - health.go: align recommendation threshold (>=3) with CouplingStatus warning threshold so all three places use a consistent value - render.go: add explicit untrusted-data boundary in renderCodebaseContext to guard against prompt injection from hostile repo content - cmd: fix defer os.Remove errcheck in factory and restore New top-level command: - supermodel audit — standalone health analysis (was factory health) - supermodel factory health now delegates to runAudit (same logic, aliased) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * ci: re-trigger architecture check * fix(ci): use set +e around architecture check to preserve output on failure, also skip HTTP 5xx as transient * chore: remove vertical slice architecture check * chore: remove accidentally staged worktree reference * fix(lint): restore os.Remove errcheck suppression — RemoveAll? only matched RemoveAll not Remove --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2a46bf0 commit a4d6c24

8 files changed

Lines changed: 1109 additions & 1 deletion

File tree

cmd/audit.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package cmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
6+
"github.com/supermodeltools/cli/internal/factory"
7+
)
8+
9+
func init() {
10+
var dir string
11+
12+
c := &cobra.Command{
13+
Use: "audit",
14+
Short: "Analyse codebase health using graph intelligence",
15+
Long: `Audit analyses the codebase via the Supermodel API and produces a structured
16+
Markdown health report covering:
17+
18+
- Overall status (HEALTHY / DEGRADED / CRITICAL)
19+
- Circular dependency detection
20+
- Domain coupling metrics and high-coupling domains
21+
- High blast-radius files
22+
- Prioritised recommendations
23+
24+
The report is also used internally by 'supermodel factory run' and
25+
'supermodel factory improve' as the Phase 8 health gate.
26+
27+
Example:
28+
29+
supermodel audit
30+
supermodel audit --dir ./path/to/project`,
31+
RunE: func(cmd *cobra.Command, _ []string) error {
32+
return runAudit(cmd, dir)
33+
},
34+
SilenceUsage: true,
35+
}
36+
37+
c.Flags().StringVar(&dir, "dir", "", "project directory (default: current working directory)")
38+
rootCmd.AddCommand(c)
39+
}
40+
41+
// runAudit is the shared implementation used by both 'supermodel audit' and
42+
// 'supermodel factory health'.
43+
func runAudit(cmd *cobra.Command, dir string) error {
44+
rootDir, projectName, err := resolveFactoryDir(dir)
45+
if err != nil {
46+
return err
47+
}
48+
49+
ir, err := factoryAnalyze(cmd, rootDir, projectName)
50+
if err != nil {
51+
return err
52+
}
53+
54+
report := factory.Analyze(ir, projectName)
55+
factory.RenderHealth(cmd.OutOrStdout(), report)
56+
return nil
57+
}

cmd/factory.go

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"time"
9+
10+
"github.com/spf13/cobra"
11+
12+
"github.com/supermodeltools/cli/internal/api"
13+
"github.com/supermodeltools/cli/internal/cache"
14+
"github.com/supermodeltools/cli/internal/config"
15+
"github.com/supermodeltools/cli/internal/factory"
16+
)
17+
18+
func init() {
19+
factoryCmd := &cobra.Command{
20+
Use: "factory",
21+
Short: "AI-native SDLC orchestration via graph intelligence",
22+
Long: `Factory is an AI-native SDLC system that uses the Supermodel code graph API
23+
to power graph-first development workflows.
24+
25+
Inspired by Big Iron (github.com/supermodeltools/bigiron), factory provides
26+
three commands:
27+
28+
health — Analyse codebase health: circular deps, domain coupling, blast radius
29+
run — Generate a graph-enriched 8-phase SDLC execution plan for a goal
30+
improve — Generate a prioritised, graph-driven improvement plan
31+
32+
All commands require an API key (run 'supermodel login' to configure).
33+
34+
Examples:
35+
36+
supermodel factory health
37+
supermodel factory run "Add rate limiting to the order API"
38+
supermodel factory improve`,
39+
SilenceUsage: true,
40+
}
41+
42+
// ── health ────────────────────────────────────────────────────────────────
43+
var healthDir string
44+
healthCmd := &cobra.Command{
45+
Use: "health",
46+
Short: "Alias for 'supermodel audit'",
47+
Long: "Health is an alias for 'supermodel audit'. See 'supermodel audit --help' for full documentation.",
48+
RunE: func(cmd *cobra.Command, _ []string) error {
49+
return runAudit(cmd, healthDir)
50+
},
51+
SilenceUsage: true,
52+
}
53+
healthCmd.Flags().StringVar(&healthDir, "dir", "", "project directory (default: current working directory)")
54+
55+
// ── run ───────────────────────────────────────────────────────────────────
56+
var runDir string
57+
runCmd := &cobra.Command{
58+
Use: "run <goal>",
59+
Short: "Generate a graph-enriched SDLC execution plan for a goal",
60+
Long: `Run analyses the codebase and generates a graph-enriched 8-phase SDLC
61+
execution plan tailored to the supplied goal.
62+
63+
The output is a Markdown prompt designed to be consumed by Claude Code or any
64+
AI agent. Pipe it directly into an agent session:
65+
66+
supermodel factory run "Add rate limiting to the order API" | claude --print
67+
68+
The plan includes codebase context (domains, key files, tech stack), the goal,
69+
and phase-by-phase instructions with graph-aware quality gates.`,
70+
Args: cobra.ExactArgs(1),
71+
RunE: func(cmd *cobra.Command, args []string) error {
72+
return runFactoryRun(cmd, runDir, args[0])
73+
},
74+
SilenceUsage: true,
75+
}
76+
runCmd.Flags().StringVar(&runDir, "dir", "", "project directory (default: current working directory)")
77+
78+
// ── improve ───────────────────────────────────────────────────────────────
79+
var improveDir string
80+
improveCmd := &cobra.Command{
81+
Use: "improve",
82+
Short: "Generate a graph-driven improvement plan",
83+
Long: `Improve runs a health analysis and generates a prioritised improvement plan
84+
using the Supermodel code graph.
85+
86+
The output is a Markdown prompt that guides an AI agent through:
87+
88+
1. Scoring improvement targets (circular deps, coupling, dead code, depth)
89+
2. Executing refactors in bottom-up topological order
90+
3. Running quality gates after each change
91+
4. A final dead code sweep and health check
92+
93+
Pipe it into an agent session:
94+
95+
supermodel factory improve | claude --print`,
96+
RunE: func(cmd *cobra.Command, _ []string) error {
97+
return runFactoryImprove(cmd, improveDir)
98+
},
99+
SilenceUsage: true,
100+
}
101+
improveCmd.Flags().StringVar(&improveDir, "dir", "", "project directory (default: current working directory)")
102+
103+
factoryCmd.AddCommand(healthCmd, runCmd, improveCmd)
104+
rootCmd.AddCommand(factoryCmd)
105+
}
106+
107+
// ── run ───────────────────────────────────────────────────────────────────────
108+
109+
func runFactoryRun(cmd *cobra.Command, dir, goal string) error {
110+
rootDir, projectName, err := resolveFactoryDir(dir)
111+
if err != nil {
112+
return err
113+
}
114+
115+
ir, err := factoryAnalyze(cmd, rootDir, projectName)
116+
if err != nil {
117+
return err
118+
}
119+
120+
report := factory.Analyze(ir, projectName)
121+
data := factoryPromptData(report, goal)
122+
factory.RenderRunPrompt(cmd.OutOrStdout(), data)
123+
return nil
124+
}
125+
126+
// ── improve ───────────────────────────────────────────────────────────────────
127+
128+
func runFactoryImprove(cmd *cobra.Command, dir string) error {
129+
rootDir, projectName, err := resolveFactoryDir(dir)
130+
if err != nil {
131+
return err
132+
}
133+
134+
ir, err := factoryAnalyze(cmd, rootDir, projectName)
135+
if err != nil {
136+
return err
137+
}
138+
139+
report := factory.Analyze(ir, projectName)
140+
data := factoryPromptData(report, "")
141+
factory.RenderImprovePrompt(cmd.OutOrStdout(), data)
142+
return nil
143+
}
144+
145+
// ── shared helpers ────────────────────────────────────────────────────────────
146+
147+
func resolveFactoryDir(dir string) (rootDir, projectName string, err error) {
148+
if dir == "" {
149+
dir, err = os.Getwd()
150+
if err != nil {
151+
return "", "", fmt.Errorf("get working directory: %w", err)
152+
}
153+
}
154+
rootDir = findGitRoot(dir)
155+
projectName = filepath.Base(rootDir)
156+
return rootDir, projectName, nil
157+
}
158+
159+
func factoryAnalyze(cmd *cobra.Command, rootDir, projectName string) (*api.SupermodelIR, error) {
160+
cfg, err := config.Load()
161+
if err != nil {
162+
return nil, err
163+
}
164+
if cfg.APIKey == "" {
165+
return nil, fmt.Errorf("no API key configured — run 'supermodel login' first")
166+
}
167+
168+
fmt.Fprintln(cmd.ErrOrStderr(), "Creating repository archive…")
169+
zipPath, err := factory.CreateZip(rootDir)
170+
if err != nil {
171+
return nil, fmt.Errorf("create archive: %w", err)
172+
}
173+
defer func() { _ = os.Remove(zipPath) }()
174+
175+
hash, err := cache.HashFile(zipPath)
176+
if err != nil {
177+
return nil, fmt.Errorf("hash archive: %w", err)
178+
}
179+
180+
client := api.New(cfg)
181+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
182+
defer cancel()
183+
184+
fmt.Fprintf(cmd.ErrOrStderr(), "Analyzing %s…\n", projectName)
185+
ir, err := client.AnalyzeDomains(ctx, zipPath, "factory-"+hash[:16])
186+
if err != nil {
187+
return nil, err
188+
}
189+
return ir, nil
190+
}
191+
192+
func factoryPromptData(report *factory.HealthReport, goal string) *factory.SDLCPromptData {
193+
domains := make([]factory.DomainHealth, len(report.Domains))
194+
copy(domains, report.Domains)
195+
196+
criticalFiles := make([]factory.CriticalFile, len(report.CriticalFiles))
197+
copy(criticalFiles, report.CriticalFiles)
198+
199+
data := &factory.SDLCPromptData{
200+
ProjectName: report.ProjectName,
201+
Language: report.Language,
202+
TotalFiles: report.TotalFiles,
203+
TotalFunctions: report.TotalFunctions,
204+
ExternalDeps: report.ExternalDeps,
205+
Domains: domains,
206+
CriticalFiles: criticalFiles,
207+
CircularDeps: report.CircularDeps,
208+
Goal: goal,
209+
GeneratedAt: report.AnalyzedAt.Format("2006-01-02 15:04:05 UTC"),
210+
}
211+
if goal == "" {
212+
data.HealthReport = report
213+
}
214+
return data
215+
}

cmd/restore.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func restoreViaAPI(cmd *cobra.Command, cfg *config.Config, rootDir, projectName
116116
if err != nil {
117117
return nil, fmt.Errorf("create archive: %w", err)
118118
}
119-
defer os.Remove(zipPath)
119+
defer func() { _ = os.Remove(zipPath) }()
120120

121121
hash, err := cache.HashFile(zipPath)
122122
if err != nil {

internal/factory/doc.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Package factory implements the supermodel factory command: an AI-native
2+
// SDLC orchestration system that uses the Supermodel code graph API to
3+
// provide health analysis, graph-enriched execution plans, and prioritised
4+
// improvement prompts.
5+
//
6+
// Three sub-commands are exposed:
7+
//
8+
// - health — analyse codebase health (circular deps, coupling, blast radius)
9+
// - run — generate a graph-enriched 8-phase SDLC prompt for a given goal
10+
// - improve — generate a prioritised improvement plan from health data
11+
//
12+
// The design is inspired by the Big Iron project (github.com/supermodeltools/bigiron).
13+
package factory

0 commit comments

Comments
 (0)