Skip to content

Commit e1ab574

Browse files
shahar-cauraclaude
andcommitted
forge: Add PromptSuffix to Agent interface so Ralph exits cleanly
Also fix all errcheck/lint violations across 17 files, harden the agent prompt to explicitly require running linters before finishing, and add ignore/later.md note for post-agent CI guard step. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 13ea69d commit e1ab574

26 files changed

Lines changed: 1535 additions & 67 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
bin/
33
dist/
44
*.exe
5+
/forge
56

67
# Logs
78
*.log

cmd/forge/cmd_logs.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ func cmdLogs(runID string, follow bool, step int) error {
4848
if err != nil {
4949
return fmt.Errorf("opening log: %w", err)
5050
}
51-
defer f.Close()
51+
defer func() { _ = f.Close() }()
5252

5353
_, err = io.Copy(os.Stdout, f)
5454
return err

cmd/forge/cmd_resume.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func newResumeCmd(logger *slog.Logger) *cobra.Command {
3030
}
3131

3232
cmd.Flags().StringVar(&fromStep, "from", "", "step name to resume from")
33-
cmd.RegisterFlagCompletionFunc("from", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
33+
_ = cmd.RegisterFlagCompletionFunc("from", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
3434
return completeStepNames(toComplete)
3535
})
3636

cmd/forge/cmd_run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func newRunCmd(logger *slog.Logger) *cobra.Command {
6363
cmd.Flags().BoolVar(&allIssues, "all-issues", false, "Run all open issues in dependency order")
6464
cmd.Flags().StringVar(&label, "label", "", "Filter issues by label (used with --all-issues)")
6565
cmd.Flags().BoolVar(&dryRun, "dry-run", false, "Print execution plan without running (used with --all-issues)")
66-
cmd.RegisterFlagCompletionFunc("issue", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
66+
_ = cmd.RegisterFlagCompletionFunc("issue", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
6767
return completeIssueNumbers(toComplete)
6868
})
6969
return cmd

cmd/forge/helpers.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
"github.com/shahar-caura/forge/internal/config"
1414
"github.com/shahar-caura/forge/internal/pipeline"
15+
"github.com/shahar-caura/forge/internal/provider"
1516
"github.com/shahar-caura/forge/internal/provider/agent"
1617
"github.com/shahar-caura/forge/internal/provider/notifier"
1718
"github.com/shahar-caura/forge/internal/provider/tracker"
@@ -93,7 +94,7 @@ func wireProviders(cfg *config.Config, logger *slog.Logger) (pipeline.Providers,
9394
repoRoot,
9495
logger,
9596
),
96-
Agent: agent.New(cfg.Agent.Timeout.Duration, logger),
97+
Agent: newAgent(cfg, logger),
9798
VCS: vcs.New(cfg.VCS.Repo, logger),
9899
}
99100

@@ -108,6 +109,15 @@ func wireProviders(cfg *config.Config, logger *slog.Logger) (pipeline.Providers,
108109
return p, nil
109110
}
110111

112+
func newAgent(cfg *config.Config, logger *slog.Logger) provider.Agent {
113+
switch cfg.Agent.Provider {
114+
case "ralph":
115+
return agent.NewRalph(cfg.Agent.Timeout.Duration, cfg.Agent.AllowedTools, logger)
116+
default:
117+
return agent.New(cfg.Agent.Timeout.Duration, logger)
118+
}
119+
}
120+
111121
// --- Git helpers ---
112122

113123
// detectDirtyGitState returns a non-empty reason if the worktree is

docs/DASHBOARD_GOLD_STANDARD.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
Forge Dashboard — Vision Brainstorm
2+
3+
What You Already Have (Raw Material)
4+
5+
- .forge/runs/<id>.yaml — full run state per step, branch, PR URL, Jira key, errors
6+
- .forge/runs/<id>-agent-step<N>.log — real-time agent output
7+
- Flat-file YAML, no daemon, no DB — the dashboard needs to bridge this gap
8+
9+
The Core: forge serve
10+
11+
A Go HTTP server embedded in the forge binary. Serves a React SPA + SSE endpoint. Zero extra deps to run — just forge serve and open a
12+
browser.
13+
14+
---
15+
Tier 1 — The Essentials
16+
17+
1. Multi-Repo Run Aggregator
18+
Scan all repos on disk (configurable list or auto-discover from ~/code/*/.forge/runs/). One unified view across every project. Each run
19+
tagged with repo name, account identity, and which forge.yaml config was used.
20+
21+
2. Live Pipeline Visualization
22+
Each run rendered as a horizontal pipeline of 11 steps. Steps light up green/yellow/red as they transition. Currently-running step
23+
pulses. Failed step shows the error inline. Click a step to see its log.
24+
25+
3. Real-Time Log Streaming
26+
SSE-backed live tail of agent logs. Like forge logs -f but in the browser with syntax highlighting, collapsible tool calls, and
27+
auto-scroll. Stream .forge/runs/<id>-agent-step4.log as the agent writes to it.
28+
29+
4. Account Awareness
30+
Detect which GitHub account is active per repo (gh auth status). Tag each run with the identity that executed it. Filter/group by
31+
account. Critical for consultants managing multiple orgs.
32+
33+
---
34+
Tier 2 — Intelligence Layer
35+
36+
5. Run Timeline / Gantt View
37+
Right now you don't track per-step timestamps — add StartedAt/CompletedAt to each StepState. Then render a Gantt chart showing exactly
38+
where time was spent. "Agent ran for 12 minutes, CR poll waited 3 minutes, push took 2 seconds." This alone would be worth the
39+
dashboard.
40+
41+
6. Cost & Token Tracking
42+
Parse Claude's JSON output for token counts (or intercept the --output-format json response). Track input/output tokens per run, per
43+
step, per repo. Show daily/weekly burn rate. Alert when a single run exceeds a threshold. "This month: 2.1M tokens across 47 runs,
44+
~$14.30."
45+
46+
7. PR Lifecycle Tracking
47+
Don't stop at "PR created." Poll gh pr view to show: PR open → review requested → changes requested → approved → merged. The dashboard
48+
becomes the single pane of glass for the full lifecycle, not just the forge pipeline.
49+
50+
8. Dependency Graph Visualization
51+
When running --all-issues, render the issue dependency DAG visually. Show which issues are queued, running in parallel, blocked. Animate
52+
as issues complete and unlock downstream work. Like a CI pipeline view but for your entire feature plan.
53+
54+
---
55+
Tier 3 — Power Features
56+
57+
9. Diff Preview per Run
58+
After the agent runs, capture git diff of the worktree. Show the actual code changes in the dashboard with syntax highlighting before
59+
the PR is even pushed. Review agent output without leaving the dashboard.
60+
61+
10. Agent Replay / Debug Mode
62+
Record every tool call the agent made (Read, Write, Bash, etc.) with timestamps. Replay them step-by-step in the UI. "At 2:03 PM the
63+
agent read auth.go, then wrote 47 lines to middleware.go, then ran go test." Understand how the agent solved the problem, not just that
64+
it did.
65+
66+
11. Run Comparison
67+
Compare two runs side-by-side. Same plan, different agent configs. Same issue, attempt 1 vs attempt 2. Show diffs in: time taken, tokens
68+
used, files changed, test results. Useful for tuning prompts and agent settings.
69+
70+
12. Batch Orchestration Dashboard
71+
For --all-issues runs: a Kanban-style board. Columns = topo levels. Cards = issues. Cards move right as they complete. Shows parallelism
72+
factor ("3 issues running concurrently"). Estimated completion based on average step durations.
73+
74+
---
75+
Tier 4 — Delightful Extras
76+
77+
13. Notification Center
78+
Aggregate Slack notifications, PR comments, CR feedback all in one feed. "FORGE-42: PR approved and merged" alongside "FORGE-43: CR
79+
feedback received — agent fixing." Replace Slack-hopping with one timeline.
80+
81+
14. Health & Trends Dashboard
82+
- Success rate over time (% of runs that complete without intervention)
83+
- Average time-to-PR (from forge run to PR created)
84+
- Most common failure step (is it always CR? Always tests?)
85+
- Runs per day/week heatmap
86+
- Agent "hit rate" — how often does the first agent pass succeed vs needing CR fixes?
87+
88+
15. Quick Actions from UI
89+
- Resume a failed run (button → forge resume <id>)
90+
- Open the worktree in your editor
91+
- Open the PR in GitHub
92+
- Open the Jira issue
93+
- Retry with a different agent (claude vs ralph)
94+
- Kill a stuck run
95+
96+
16. Forge "Control Tower" Mode
97+
For teams: a shared forge serve instance that watches a directory of plan files. Drop a .md file into plans/, forge picks it up, runs
98+
it, dashboard shows progress. Like a CI server but for AI-driven development. Plans as the unit of work.
99+
100+
17. Terminal Dashboard Alternative (TUI)
101+
Not everyone wants a browser. A forge dashboard TUI using bubbletea — split panes, live log tailing, keyboard navigation. Fits the
102+
"single binary" philosophy better than React. Could be the V1, with web as V2.
103+
104+
18. Webhook/API for External Integration
105+
forge serve exposes a REST API. Other tools can query run status, trigger runs, subscribe to events. Integrate with Raycast, Alfred, or
106+
a custom Slack bot. "Hey Forge, what's running right now?"
107+
108+
---
109+
Architecture Suggestion
110+
111+
forge serve [--port 8080] [--repos ~/code/project1,~/code/project2]
112+
113+
├── Go HTTP server (net/http, no framework)
114+
│ ├── GET /api/runs → list all runs across repos
115+
│ ├── GET /api/runs/:id → run detail + steps
116+
│ ├── GET /api/runs/:id/logs → SSE stream of agent log
117+
│ ├── POST /api/runs/:id/resume → trigger resume
118+
│ ├── GET /api/stats → aggregate metrics
119+
│ └── GET / → serve embedded React SPA
120+
121+
├── State watcher (fsnotify on .forge/runs/*.yaml)
122+
│ └── pushes SSE events on state change
123+
124+
├── React SPA (embedded via go:embed)
125+
│ ├── Dashboard (all runs, filters, search)
126+
│ ├── Run detail (pipeline viz + logs)
127+
│ ├── Batch view (dependency graph)
128+
│ └── Stats (charts, trends)
129+
130+
└── SQLite (optional, for cross-repo aggregation + history beyond retention)
131+
132+
What I'd Build First
133+
134+
1. Add per-step timestamps to StepState (tiny change, massive value)
135+
2. forge serve with a minimal Go HTTP server + SSE
136+
3. TUI dashboard (forge dashboard) using bubbletea — faster to ship, stays true to CLI philosophy
137+
4. Multi-repo scanner that finds all .forge/runs/ directories
138+
5. React SPA embedded via go:embed for the full web experience

0 commit comments

Comments
 (0)