@sugar-crash-studios/vibe-forge 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/clear-attention.md +63 -0
- package/.claude/commands/compact-context.md +52 -0
- package/.claude/commands/configure-vcs.md +102 -0
- package/.claude/commands/forge.md +171 -0
- package/.claude/commands/need-help.md +77 -0
- package/.claude/commands/update-status.md +64 -0
- package/.claude/commands/worker-loop.md +106 -0
- package/.claude/hooks/worker-loop.js +198 -0
- package/.claude/scripts/setup-worker-loop.sh +45 -0
- package/.claude/settings.local.json +46 -0
- package/LICENSE +21 -0
- package/README.md +238 -0
- package/agents/aegis/personality.md +294 -0
- package/agents/anvil/personality.md +276 -0
- package/agents/architect/personality.md +258 -0
- package/agents/crucible/personality.md +360 -0
- package/agents/ember/personality.md +291 -0
- package/agents/forge-master/capabilities.md +144 -0
- package/agents/forge-master/context-template.md +128 -0
- package/agents/forge-master/personality.md +138 -0
- package/agents/furnace/personality.md +340 -0
- package/agents/herald/personality.md +247 -0
- package/agents/loki/personality.md +108 -0
- package/agents/oracle/personality.md +283 -0
- package/agents/pixel/personality.md +113 -0
- package/agents/planning-hub/personality.md +320 -0
- package/agents/scribe/personality.md +251 -0
- package/agents/temper/personality.md +218 -0
- package/bin/cli.js +375 -0
- package/bin/dashboard/api/agents.js +333 -0
- package/bin/dashboard/api/dispatch.js +483 -0
- package/bin/dashboard/api/tasks.js +416 -0
- package/bin/dashboard/frontend/index.html +13 -0
- package/bin/dashboard/frontend/package.json +16 -0
- package/bin/dashboard/frontend/src/App.svelte +222 -0
- package/bin/dashboard/frontend/src/app.css +1777 -0
- package/bin/dashboard/frontend/src/lib/components/AgentCard.svelte +60 -0
- package/bin/dashboard/frontend/src/lib/components/AgentsPanel.svelte +57 -0
- package/bin/dashboard/frontend/src/lib/components/DispatchModal.svelte +180 -0
- package/bin/dashboard/frontend/src/lib/components/Footer.svelte +33 -0
- package/bin/dashboard/frontend/src/lib/components/Header.svelte +84 -0
- package/bin/dashboard/frontend/src/lib/components/IssueCard.svelte +33 -0
- package/bin/dashboard/frontend/src/lib/components/IssuesPanel.svelte +73 -0
- package/bin/dashboard/frontend/src/lib/components/KeyboardShortcutsModal.svelte +108 -0
- package/bin/dashboard/frontend/src/lib/components/MobileTabs.svelte +52 -0
- package/bin/dashboard/frontend/src/lib/components/NotificationCard.svelte +60 -0
- package/bin/dashboard/frontend/src/lib/components/NotificationsPanel.svelte +44 -0
- package/bin/dashboard/frontend/src/lib/components/TaskCard.svelte +63 -0
- package/bin/dashboard/frontend/src/lib/components/TasksPanel.svelte +82 -0
- package/bin/dashboard/frontend/src/lib/components/Toast.svelte +45 -0
- package/bin/dashboard/frontend/src/lib/stores/agents.js +34 -0
- package/bin/dashboard/frontend/src/lib/stores/issues.js +54 -0
- package/bin/dashboard/frontend/src/lib/stores/notifications.js +48 -0
- package/bin/dashboard/frontend/src/lib/stores/tasks.js +63 -0
- package/bin/dashboard/frontend/src/lib/stores/theme.js +33 -0
- package/bin/dashboard/frontend/src/lib/stores/toast.js +35 -0
- package/bin/dashboard/frontend/src/lib/stores/ui.js +25 -0
- package/bin/dashboard/frontend/src/lib/stores/voice.js +275 -0
- package/bin/dashboard/frontend/src/lib/stores/websocket.js +295 -0
- package/bin/dashboard/frontend/src/lib/utils/api.js +101 -0
- package/bin/dashboard/frontend/src/lib/utils/formatters.js +54 -0
- package/bin/dashboard/frontend/src/main.js +9 -0
- package/bin/dashboard/frontend/svelte.config.js +5 -0
- package/bin/dashboard/frontend/vite.config.js +20 -0
- package/bin/dashboard/public/assets/index-DnfVj9Ce.css +1 -0
- package/bin/dashboard/public/assets/index-Ze5h0kXQ.js +2 -0
- package/bin/dashboard/public/index.html +14 -0
- package/bin/dashboard/server.js +566 -0
- package/bin/forge-daemon.sh +463 -0
- package/bin/forge-setup.sh +645 -0
- package/bin/forge-spawn.sh +164 -0
- package/bin/forge.cmd +83 -0
- package/bin/forge.sh +533 -0
- package/bin/lib/agents.sh +177 -0
- package/bin/lib/colors.sh +44 -0
- package/bin/lib/config.sh +347 -0
- package/bin/lib/constants.sh +241 -0
- package/bin/lib/daemon/display.sh +128 -0
- package/bin/lib/daemon/notifications.sh +263 -0
- package/bin/lib/daemon/routing.sh +77 -0
- package/bin/lib/daemon/state.sh +115 -0
- package/bin/lib/daemon/sync.sh +95 -0
- package/bin/lib/database.sh +310 -0
- package/bin/lib/heimdall-setup.js +113 -0
- package/bin/lib/heimdall.js +265 -0
- package/bin/lib/json.sh +264 -0
- package/bin/lib/terminal.js +451 -0
- package/bin/lib/util.sh +126 -0
- package/bin/lib/vcs.js +349 -0
- package/config/agent-manifest.yaml +203 -0
- package/config/agents.json +168 -0
- package/config/task-template.md +159 -0
- package/config/task-types.yaml +106 -0
- package/context/agent-status/aegis.json +7 -0
- package/context/agent-status/anvil.json +7 -0
- package/context/agent-status/architect.json +7 -0
- package/context/agent-status/crucible.json +7 -0
- package/context/agent-status/ember.json +7 -0
- package/context/agent-status/furnace.json +7 -0
- package/context/agent-status/loki.json +7 -0
- package/context/agent-status/oracle.json +7 -0
- package/context/agent-status/pixel.json +7 -0
- package/context/agent-status/planning-hub.json +7 -0
- package/context/agent-status/scribe.json +7 -0
- package/context/agent-status/temper.json +7 -0
- package/context/feature-brainstorm.md +426 -0
- package/context/forge-state.yaml +19 -0
- package/context/modern-conventions.md +129 -0
- package/context/project-context-template.md +122 -0
- package/context/project-context.md +122 -0
- package/docs/TODO.md +150 -0
- package/docs/agents.md +409 -0
- package/docs/architecture/decisions/ADR-001-daemon-modularization.md +122 -0
- package/docs/architecture/vibe-lab-integration.md +684 -0
- package/docs/architecture.md +194 -0
- package/docs/bmad-gap-analysis-2026-03-31.md +444 -0
- package/docs/cleanup-workflow.md +329 -0
- package/docs/commands.md +451 -0
- package/docs/dashboard-mockup.html +989 -0
- package/docs/getting-started.md +261 -0
- package/docs/integration/forge-ownership-policy.md +112 -0
- package/docs/npm-publishing.md +132 -0
- package/docs/roadmap-2026.md +519 -0
- package/docs/security.md +144 -0
- package/docs/wireframes/dashboard-mvp.md +1164 -0
- package/docs/workflows/README.md +32 -0
- package/docs/workflows/azure-devops.md +108 -0
- package/docs/workflows/bitbucket.md +104 -0
- package/docs/workflows/git-only.md +130 -0
- package/docs/workflows/gitea.md +168 -0
- package/docs/workflows/github.md +103 -0
- package/docs/workflows/gitlab.md +105 -0
- package/docs/workflows.md +454 -0
- package/package.json +73 -0
- package/tasks/completed/ARCH-001-duplicate-agent-config.md +121 -0
- package/tasks/completed/ARCH-002-mixed-bash-node-implementation.md +88 -0
- package/tasks/completed/ARCH-003-worker-loop-hook-duplication.md +77 -0
- package/tasks/completed/ARCH-009-test-organization.md +78 -0
- package/tasks/completed/ARCH-011-jq-vs-nodejs-json.md +94 -0
- package/tasks/completed/ARCH-012-tmp-files-in-root.md +71 -0
- package/tasks/completed/ARCH-013-exit-code-constants.md +65 -0
- package/tasks/completed/ARCH-014-sed-incompatibility.md +96 -0
- package/tasks/completed/ARCH-015-docs-todo-tracking.md +83 -0
- package/tasks/completed/BUG-dash-001-tasks-filter-error.md +31 -0
- package/tasks/completed/BUG-dash-002-agents-unknown.md +41 -0
- package/tasks/completed/CLEAN-001.md +38 -0
- package/tasks/completed/CLEAN-002.md +43 -0
- package/tasks/completed/CLEAN-003.md +47 -0
- package/tasks/completed/CLEAN-004.md +56 -0
- package/tasks/completed/CLEAN-005.md +75 -0
- package/tasks/completed/CLEAN-006.md +47 -0
- package/tasks/completed/CLEAN-007.md +34 -0
- package/tasks/completed/CLEAN-008.md +49 -0
- package/tasks/completed/CLEAN-012.md +58 -0
- package/tasks/completed/CLEAN-013.md +45 -0
- package/tasks/completed/FEATURE-001a-dashboard-wireframes.md +162 -0
- package/tasks/completed/IMPL-007a-daemon-notifications-module.md +82 -0
- package/tasks/completed/IMPL-007b-daemon-sync-module.md +71 -0
- package/tasks/completed/IMPL-007c-daemon-state-module.md +80 -0
- package/tasks/completed/IMPL-007d-daemon-routing-module.md +77 -0
- package/tasks/completed/IMPL-007e-daemon-display-module.md +77 -0
- package/tasks/completed/IMPL-007f-daemon-integration.md +124 -0
- package/tasks/completed/PLAT-1-heimdall.md +420 -0
- package/tasks/completed/SEC-001-sql-injection-fix.md +58 -0
- package/tasks/completed/SEC-002-notification-injection-fix.md +45 -0
- package/tasks/completed/SEC-003-eval-injection-fix.md +54 -0
- package/tasks/completed/SEC-004-pid-race-condition-fix.md +49 -0
- package/tasks/completed/SEC-005-worker-loop-path-fix.md +51 -0
- package/tasks/completed/SEC-006-eval-agent-names.md +55 -0
- package/tasks/completed/SEC-007-spawn-escaping.md +67 -0
- package/tasks/completed/TASK-DASH-001-server-infrastructure.md +185 -0
- package/tasks/completed/TASK-anvil-001-dashboard-frontend.md +133 -0
- package/tasks/completed/review-bmad-aegis.md +89 -0
- package/tasks/completed/review-bmad-anvil.md +80 -0
- package/tasks/completed/review-bmad-crucible.md +81 -0
- package/tasks/completed/review-bmad-ember.md +90 -0
- package/tasks/completed/review-bmad-furnace.md +79 -0
- package/tasks/completed/review-bmad-pixel.md +82 -0
- package/tasks/completed/review-bmad-scribe.md +92 -0
- package/tasks/completed/review-bmad-sentinel.md +83 -0
- package/tasks/pending/ARCH-004-git-bash-detection-duplication.md +72 -0
- package/tasks/pending/ARCH-005-missing-src-directory.md +95 -0
- package/tasks/pending/ARCH-006-task-template-location.md +64 -0
- package/tasks/pending/ARCH-008-forge-master-vs-hub.md +81 -0
- package/tasks/pending/ARCH-010-missing-index-files.md +84 -0
- package/tasks/pending/CLEAN-009.md +31 -0
- package/tasks/pending/CLEAN-010.md +30 -0
- package/tasks/pending/CLEAN-011.md +30 -0
- package/tasks/pending/CLEAN-014.md +32 -0
- package/tasks/pending/DESIGN-dash-001-layout-review.md +45 -0
- package/tasks/pending/FEATURE-001-dashboard-mvp.md +268 -0
- package/tasks/review/ARCH-007-daemon-monolith.md +162 -0
- package/tasks/review/bmad-review-aegis.md +349 -0
- package/tasks/review/bmad-review-anvil.md +259 -0
- package/tasks/review/bmad-review-crucible.md +277 -0
- package/tasks/review/bmad-review-ember.md +307 -0
- package/tasks/review/bmad-review-furnace.md +285 -0
- package/tasks/review/bmad-review-pixel.md +329 -0
- package/tasks/review/bmad-review-scribe.md +361 -0
- package/tasks/review/bmad-review-sentinel.md +242 -0
- package/tasks/review/task-001.md +78 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
# vibe-forge / vibe-lab Integration Architecture
|
|
2
|
+
|
|
3
|
+
**Status:** Proposed — pending vibe-lab review
|
|
4
|
+
**Date:** 2026-04-01
|
|
5
|
+
**Version:** 2.1 (blockers resolved)
|
|
6
|
+
**Authors:** vibe-forge architect, vibe-lab architect (synthesized)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Platform Model
|
|
11
|
+
|
|
12
|
+
vibe-forge and vibe-lab are one platform delivered in two configurations:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
vibe-forge (standalone)
|
|
16
|
+
The interactive session layer.
|
|
17
|
+
For developers who want forge's agent model without a CI/CD pipeline.
|
|
18
|
+
Installs independently. Works without lab.
|
|
19
|
+
|
|
20
|
+
vibe-lab (includes forge)
|
|
21
|
+
The full platform.
|
|
22
|
+
Lab is the pipeline protocol layer.
|
|
23
|
+
Forge is the execution runtime.
|
|
24
|
+
Installing lab installs forge. Starting lab starts forge.
|
|
25
|
+
Lab without forge is not a supported configuration.
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The previous framing ("two systems with an integration boundary") is retired. There is one platform. The boundary that exists is between **protocol** (lab) and **execution** (forge), not between two optional peer systems.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Why This Model
|
|
33
|
+
|
|
34
|
+
Lab's existing execution model — `claude -p` headless subprocesses — is opaque by design. Status indicators on a dashboard are not the same as visibility. The "stuck" feeling is structural: you cannot distinguish a working agent from a hung one without attaching to its process.
|
|
35
|
+
|
|
36
|
+
Forge terminal sessions are inherently observable. You can watch any worker in real time. You know in seconds whether it is making progress.
|
|
37
|
+
|
|
38
|
+
The platform model resolves this permanently: all story execution runs through forge workers. Lab provides orchestration, handoff protocol, and release management. Forge provides every agent that does work.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Installation and Dependency
|
|
43
|
+
|
|
44
|
+
Lab declares forge as a versioned dependency:
|
|
45
|
+
|
|
46
|
+
```json
|
|
47
|
+
// vibe-lab/package.json
|
|
48
|
+
{
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"vibe-forge": "^1.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
`lab install` (or `npm install` in the lab directory) pulls forge. No separate forge install step for lab users. vibe-forge standalone users install forge directly via `npx vibe-forge` as today — unchanged.
|
|
56
|
+
|
|
57
|
+
**Version constraints:** The IPC protocol between lab's dispatcher and forge's daemon is versioned independently of both packages. On startup, lab and forge perform a handshake:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
lab → forge daemon: { "protocol": "ipc-v1", "project_id": "..." }
|
|
61
|
+
forge → lab: { "ok": true } | { "error": "protocol_mismatch", "supported": "ipc-v1" }
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Transport: `POST http://localhost:2800/api/handshake` — forge's dashboard server already runs HTTP at port 2800. IPC-1 must specify this explicitly. The port is configurable in `_vibe-chain/config.yaml` under `forge.dashboard_port`.
|
|
65
|
+
|
|
66
|
+
If versions are incompatible, lab falls back to degraded mode and logs a warning. Lab never fails to start because forge is on an unexpected version — it degrades gracefully.
|
|
67
|
+
|
|
68
|
+
**Upgrades:** Forge updates follow semver. Minor and patch versions are compatible. Major versions may break the IPC protocol — lab's package.json pins to a major version range (`^1.0.0`) and the CI matrix validates the combination before publishing.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Deployment Architecture
|
|
73
|
+
|
|
74
|
+
When `lab start` runs, it starts two services:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
lab start
|
|
78
|
+
├── sentinel (lab: filesystem watcher, pipeline state, hub sync)
|
|
79
|
+
├── relay (lab: WebSocket fan-out for dashboard)
|
|
80
|
+
├── hub (lab: API server, dashboard frontend)
|
|
81
|
+
└── forge-daemon (forge: worker lifecycle manager, task router)
|
|
82
|
+
├── anvil (forge worker: frontend)
|
|
83
|
+
├── furnace (forge worker: backend)
|
|
84
|
+
├── crucible (forge worker: testing)
|
|
85
|
+
├── sentinel (forge worker: code review)
|
|
86
|
+
├── architect (forge worker: arch review)
|
|
87
|
+
└── pixel (forge worker: UX review)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Forge workers run as **persistent background processes**, not terminal tabs that a human opens. The forge daemon owns worker lifetimes. Workers start with lab, run continuously, and stop with lab.
|
|
91
|
+
|
|
92
|
+
Workers run with `--dangerously-skip-permissions`. There is no user-required interaction during execution. Overnight runs, unattended runs, and active session runs are identical from the pipeline's perspective.
|
|
93
|
+
|
|
94
|
+
### Visibility On Demand
|
|
95
|
+
|
|
96
|
+
Workers run in the background by default. When you want to observe:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
forge attach anvil # live terminal session, watch in real time
|
|
100
|
+
# detach with Ctrl+D, worker keeps running
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The session persists independently of whether you are watching it. This is the tmux attach model applied to agent workers.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Security Model for Background Workers: Heimdall
|
|
108
|
+
|
|
109
|
+
Forge workers run with `--dangerously-skip-permissions`. In the terminal tab model, a human can observe and intervene. In background daemon mode there is no runtime human gate. The compensating control is **Heimdall** — a pre-tool hook interceptor that guards every action before it executes.
|
|
110
|
+
|
|
111
|
+
Heimdall is named for the Norse watchman of the gods, guardian of the Bifrost bridge between realms. The Bifrost here is the bridge between lab's pipeline and forge's workers. Heimdall sits at the crossing and decides what passes.
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
bin/lib/heimdall.js
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### How Heimdall Works
|
|
118
|
+
|
|
119
|
+
Claude Code's hook system fires before each tool execution. Heimdall is registered as a `PreToolUse` hook. It receives the tool name and input as JSON on stdin, checks against policy, and returns:
|
|
120
|
+
|
|
121
|
+
- Exit `0` — allow (optionally with audit log entry)
|
|
122
|
+
- Exit `2` — block, explanation written to stdout and fed back to the model as context
|
|
123
|
+
|
|
124
|
+
The model receives the block message and reasons about it, typically self-correcting without retrying the same action.
|
|
125
|
+
|
|
126
|
+
The forge daemon writes `.claude/settings.local.json` into each worker's working directory at startup:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"hooks": {
|
|
131
|
+
"PreToolUse": [
|
|
132
|
+
{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "node bin/lib/heimdall.js" }] },
|
|
133
|
+
{ "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "node bin/lib/heimdall.js" }] }
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### What Heimdall Blocks (Hard Block)
|
|
140
|
+
|
|
141
|
+
**Catastrophic filesystem operations:**
|
|
142
|
+
- `rm -rf` targeting any path outside `worktree_path`
|
|
143
|
+
- `rm -rf /`, `rm -rf ~`, `rm -rf ..`
|
|
144
|
+
- `DROP TABLE`, `TRUNCATE` (without explicit `has_db_migration: true` flag)
|
|
145
|
+
- `DELETE FROM` without a WHERE clause
|
|
146
|
+
|
|
147
|
+
**Path escapes:**
|
|
148
|
+
- Any Write or Edit to a path outside `worktree_path`, `handoff_dir`, or `worker-inbox/`
|
|
149
|
+
|
|
150
|
+
**Credential access:**
|
|
151
|
+
- Any read of `.env`, `~/.ssh/*`, `~/.aws/credentials`, `**/secrets/**`
|
|
152
|
+
- Any bash command assigning or echoing `*TOKEN*`, `*SECRET*`, `*PASSWORD*`, `*API_KEY*`
|
|
153
|
+
|
|
154
|
+
**Dangerous git operations:**
|
|
155
|
+
- `git push --force` or `git push --force-with-lease`
|
|
156
|
+
- `git reset --hard HEAD~` (more than one commit back)
|
|
157
|
+
- `git clean -fd`
|
|
158
|
+
- Any git push to a branch other than the assigned story branch
|
|
159
|
+
- Any git operation targeting a remote other than `origin`
|
|
160
|
+
|
|
161
|
+
### What Heimdall Logs But Allows
|
|
162
|
+
|
|
163
|
+
High-risk but legitimate operations — allowed with audit log entry:
|
|
164
|
+
|
|
165
|
+
- `npm install`, `pip install`, `cargo build` — dependency changes are high-signal
|
|
166
|
+
- `git commit --amend` — legitimate but noted
|
|
167
|
+
- Any `curl` or `wget` — destination logged
|
|
168
|
+
- DB migrations when `has_db_migration: true` — explicitly authorized
|
|
169
|
+
- Writes to `_vibe-chain-output/` — allowed, every write logged
|
|
170
|
+
|
|
171
|
+
### Context File
|
|
172
|
+
|
|
173
|
+
The forge daemon writes a context file alongside each inbox task:
|
|
174
|
+
|
|
175
|
+
```json
|
|
176
|
+
// _vibe-chain-output/worker-inbox/anvil/{story-id}.context.json
|
|
177
|
+
{
|
|
178
|
+
"story_id": "FORGE-3",
|
|
179
|
+
"agent": "anvil",
|
|
180
|
+
"worktree_path": "G:/dev/vibe-lab/.worktrees/forge-3-events-api",
|
|
181
|
+
"assigned_branch": "feature/forge-3-events-api",
|
|
182
|
+
"handoff_dir": "G:/dev/vibe-lab/_vibe-chain-output/handoffs",
|
|
183
|
+
"has_db_migration": false,
|
|
184
|
+
"has_api_changes": true,
|
|
185
|
+
"allowed_paths": [
|
|
186
|
+
"G:/dev/vibe-lab/.worktrees/forge-3-events-api",
|
|
187
|
+
"G:/dev/vibe-lab/_vibe-chain-output/handoffs",
|
|
188
|
+
"G:/dev/vibe-lab/_vibe-chain-output/worker-inbox"
|
|
189
|
+
]
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Heimdall reads this on every invocation. Policy is derived from task context, not global config.
|
|
194
|
+
|
|
195
|
+
### Escalation: Sounding the Gjallarhorn
|
|
196
|
+
|
|
197
|
+
If a worker accumulates 3 or more blocks in a single task (configurable), Heimdall writes a `{story-id}.escalation` signal file. The forge daemon detects it, logs `HEIMDALL SOUNDED`, and writes an escalation handoff. Lab's sentinel routes the story to a human review queue rather than retrying.
|
|
198
|
+
|
|
199
|
+
Audit log format:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
[2026-04-01T12:34:00Z] HEIMDALL BLOCKED anvil/FORGE-3: path escape — rm -rf ../
|
|
203
|
+
[2026-04-01T12:34:01Z] HEIMDALL BLOCKED anvil/FORGE-3: credential access — read .env
|
|
204
|
+
[2026-04-01T12:34:02Z] HEIMDALL SOUNDED anvil/FORGE-3: 3 violations, escalating to human review
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Story
|
|
208
|
+
|
|
209
|
+
**PLAT-1: Heimdall** is a prerequisite for IPC-7 (background worker daemon mode). Running workers in visible terminal tabs with a human present is an acceptable substitute. Running them as unattended background services is not — SEC-1 ships before IPC-7.
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
PLAT-1: Heimdall — forge worker pre-tool hook interceptor
|
|
213
|
+
- bin/lib/heimdall.js
|
|
214
|
+
- Context file schema (.context.json alongside each inbox task)
|
|
215
|
+
- Daemon writes .claude/settings.local.json at worker startup
|
|
216
|
+
- Audit log in forge daemon output
|
|
217
|
+
- HEIMDALL SOUNDED escalation on N violations (default: 3, configurable)
|
|
218
|
+
- Policy config in _vibe-chain/config.yaml
|
|
219
|
+
Prerequisite for: IPC-7
|
|
220
|
+
Parallel with: IPC-1 through IPC-6
|
|
221
|
+
Note: SEC-1 is already assigned to "Relay server security hardening" in the lab pipeline.
|
|
222
|
+
PLAT-1 is intentionally in a new epic (PLAT) for cross-cutting platform stories.
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Trust Model
|
|
226
|
+
|
|
227
|
+
Workers are granted the same trust level as a human developer. This is a trust policy, not a technical capability limit. `--dangerously-skip-permissions` removes confirmation prompts — Heimdall replaces those prompts with automated policy enforcement. The underlying OS permissions are unchanged. The security gate at merge time (lab's review chain) remains the final control for output correctness.
|
|
228
|
+
|
|
229
|
+
### Compromise Scenario
|
|
230
|
+
|
|
231
|
+
If a worker is compromised or misbehaving, blast radius is bounded by:
|
|
232
|
+
- `VIBE_LAB_FORGE_TOKEN` scope: `create_story` and `post_events` only, matching `project_id`
|
|
233
|
+
- Worktree isolation: changes are in a branch, not main
|
|
234
|
+
- Heimdall: blocks path escapes, credential access, and destructive operations at execution time
|
|
235
|
+
- Lab's review chain: output must pass arch review, code review, and tests before merge
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Execution Layer: IPC Inbox Mechanism
|
|
240
|
+
|
|
241
|
+
Lab's dispatcher does not spawn `claude -p` subprocesses for execution stages. It routes to running forge workers via the **IPC inbox mechanism**.
|
|
242
|
+
|
|
243
|
+
### Inbox Location
|
|
244
|
+
|
|
245
|
+
Inbox files live in the project directory alongside other handoffs:
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
_vibe-chain-output/
|
|
249
|
+
handoffs/ (existing — PR handoffs, review approvals, etc.)
|
|
250
|
+
worker-inbox/ (new — lab task files for forge workers)
|
|
251
|
+
anvil/
|
|
252
|
+
{story-id}.md
|
|
253
|
+
furnace/
|
|
254
|
+
{story-id}.md
|
|
255
|
+
sentinel/
|
|
256
|
+
{story-id}.md
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
This keeps all pipeline state visible in one place, scoped to the project, with no global `~/.forge/` state. Two lab projects on the same machine cannot collide.
|
|
260
|
+
|
|
261
|
+
### Inbox Task File Format
|
|
262
|
+
|
|
263
|
+
```markdown
|
|
264
|
+
---
|
|
265
|
+
story_id: FORGE-3
|
|
266
|
+
project_id: vibe-lab
|
|
267
|
+
worktree_path: G:/dev/vibe-lab/.worktrees/forge-3-events-api
|
|
268
|
+
project_root: G:/dev/vibe-lab
|
|
269
|
+
handoff_dir: G:/dev/vibe-lab/_vibe-chain-output/handoffs
|
|
270
|
+
agent: furnace
|
|
271
|
+
task_type: backend
|
|
272
|
+
ipc_protocol: ipc-v1
|
|
273
|
+
submitted_at: 2026-04-01T12:00:00Z
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
[lab operational instructions for this story, including exact handoff frontmatter]
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
The `worktree_path` field is mandatory — Anvil or Furnace must know which worktree to work in. This is IPC-3 territory and must be in the spec.
|
|
280
|
+
|
|
281
|
+
### Routing Flow
|
|
282
|
+
|
|
283
|
+
```
|
|
284
|
+
Lab dispatcher has a story to execute:
|
|
285
|
+
|
|
286
|
+
1. GET http://localhost:2800/api/workers/available?task_type=backend
|
|
287
|
+
→ { "available": true, "agent": "furnace", "idle_since": "..." }
|
|
288
|
+
|
|
289
|
+
2. Write _vibe-chain-output/worker-inbox/furnace/{story-id}.md
|
|
290
|
+
|
|
291
|
+
3. Forge worker's stop hook fires on next idle cycle (5-10s)
|
|
292
|
+
Worker checks worker-inbox/<self>/ before exiting
|
|
293
|
+
Finds {story-id}.md, picks it up
|
|
294
|
+
|
|
295
|
+
4. Worker writes {story-id}.picked-up to signal acceptance
|
|
296
|
+
|
|
297
|
+
5. Worker executes story in assigned worktree
|
|
298
|
+
Uses forge personality + lab operational instructions (hybrid model)
|
|
299
|
+
|
|
300
|
+
6. Worker writes pr-handoff.md to _vibe-chain-output/handoffs/
|
|
301
|
+
|
|
302
|
+
7. Lab sentinel detects the handoff, continues the pipeline
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### Agent Availability API
|
|
306
|
+
|
|
307
|
+
The forge dashboard server exposes availability at a stable endpoint:
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
GET http://localhost:2800/api/workers/available?task_type=frontend
|
|
311
|
+
|
|
312
|
+
Response:
|
|
313
|
+
{
|
|
314
|
+
"available": true,
|
|
315
|
+
"agent": "anvil",
|
|
316
|
+
"idle_since": "2026-04-01T12:00:00Z",
|
|
317
|
+
"current_task": null
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
Response (busy):
|
|
321
|
+
{
|
|
322
|
+
"available": false,
|
|
323
|
+
"agent": "anvil",
|
|
324
|
+
"idle_since": null,
|
|
325
|
+
"current_task": "FORGE-2",
|
|
326
|
+
"estimated_free": null
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
Response (no matching worker):
|
|
330
|
+
{
|
|
331
|
+
"available": false,
|
|
332
|
+
"agent": null,
|
|
333
|
+
"reason": "no_worker_configured"
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
If no worker is available for the requested `task_type`, lab falls back to degraded spawn (spawn-per-story with forge personality adapter). The port `2800` is configurable in `_vibe-chain/config.yaml` under `forge.dashboard_port`. Defaults to `2800`.
|
|
338
|
+
|
|
339
|
+
### Timeout and Orphan Policy
|
|
340
|
+
|
|
341
|
+
**Orphan** — a task file written to the inbox but not picked up by a worker within 5 minutes. Cause: worker is crashed, stuck, or not running.
|
|
342
|
+
|
|
343
|
+
**Hung task** — a task picked up (`.picked-up` signal present) but no handoff written within the stage timeout.
|
|
344
|
+
|
|
345
|
+
**Stage timeouts:**
|
|
346
|
+
|
|
347
|
+
| Stage | Timeout |
|
|
348
|
+
|---|---|
|
|
349
|
+
| Dev (frontend, backend, fullstack) | 30 minutes |
|
|
350
|
+
| Code review | 15 minutes |
|
|
351
|
+
| Arch review | 15 minutes |
|
|
352
|
+
| UX review | 10 minutes |
|
|
353
|
+
| Test runner | 20 minutes |
|
|
354
|
+
|
|
355
|
+
**On orphan (not picked up within 5 min):**
|
|
356
|
+
- Forge daemon writes `{story-id}.orphaned` signal file
|
|
357
|
+
- Lab sentinel detects it, removes the inbox task file, falls back to degraded spawn
|
|
358
|
+
- Degraded spawn proceeds identically to the Way 2 model
|
|
359
|
+
|
|
360
|
+
**On timeout (picked up but no handoff within stage timeout):**
|
|
361
|
+
- Forge daemon writes `{story-id}.timeout` signal file
|
|
362
|
+
- Lab sentinel detects it, marks the run as failed in pipeline.db
|
|
363
|
+
- Writes `{story-id}-error-handoff.md` with `status: failed, reason: worker_timeout`
|
|
364
|
+
- Dispatcher picks up the error handoff on next cycle and decides retry vs escalation (same policy as today's agent failures)
|
|
365
|
+
|
|
366
|
+
**Tracking:** Forge daemon maintains a `_vibe-chain-output/worker-inbox/.tracking.json` file with timestamps for each task: `submitted_at`, `picked_up_at`, `completed_at`. This is the daemon's orphan/timeout detection source. Sentinel reads it on each cycle.
|
|
367
|
+
|
|
368
|
+
**Inbox cleanup:** When a story completes — handoff written and confirmed by sentinel — the forge daemon is responsible for removing `{story-id}.md`, `{story-id}.picked-up`, and the tracking entry from `.tracking.json`. Lab sentinel writes a `{story-id}.confirmed` signal file after consuming the handoff; the forge daemon watches for this before cleaning up. Ownership: forge daemon cleans, sentinel signals. IPC-5 must specify this protocol explicitly.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Worker Context: Benefit and Tradeoff
|
|
373
|
+
|
|
374
|
+
Workers accumulate codebase context across tasks within a session. A worker that just implemented a frontend feature already has the component structure loaded when the next frontend story arrives — no re-reading. This is a genuine velocity advantage.
|
|
375
|
+
|
|
376
|
+
**The tradeoff:** Accumulated context means accumulated assumptions. A worker finishing UX-3 brings UX-3's mental model into UX-4. In the cold-start model, each story starts clean.
|
|
377
|
+
|
|
378
|
+
**Mitigation:** The lab operational instructions delivered via the IPC inbox (IPC-3) must include a context-reset prompt at task start:
|
|
379
|
+
|
|
380
|
+
```
|
|
381
|
+
Before reading this task, set aside any assumptions from previous tasks.
|
|
382
|
+
Treat this story as independent. Read the handoff file and the worktree
|
|
383
|
+
state to form your understanding of what is needed.
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
This is a prompt instruction, not a process restart. It does not eliminate context bleed entirely but reduces the risk of a worker importing the wrong frame. Document this tradeoff in IPC-3's spec.
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
## Handoff Model: Hybrid Execution
|
|
391
|
+
|
|
392
|
+
Forge personality files contain forge-specific task execution patterns that have no meaning in a lab worktree. Lab's sentinel validates handoff frontmatter against a schema registry — a malformed `pr-handoff.md` stalls the pipeline.
|
|
393
|
+
|
|
394
|
+
**The split:** forge personalities handle the work, lab operational instructions handle the handoffs.
|
|
395
|
+
|
|
396
|
+
When the stop hook delivers a lab task, the prompt is structured as:
|
|
397
|
+
|
|
398
|
+
```
|
|
399
|
+
[forge personality adapter — identity, principles, domain expertise, coding standards]
|
|
400
|
+
[explicit: forge task execution instructions are SUSPENDED for this task]
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
[lab operational instructions — worktree_path, exact handoff frontmatter,
|
|
405
|
+
completion signal protocol, sprint-status update procedure]
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
Personality adapter documents live at `_vibe-chain/agents/forge/<agent>.md` — maintained in the lab repo, containing Identity and Principles from each forge personality with forge-operational sections omitted.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Fallback: Degraded Mode
|
|
413
|
+
|
|
414
|
+
When forge workers are unavailable (daemon not running, worker crashed, orphan timeout), lab falls back to spawn-per-story with forge personality adapters as prompt prefixes. This is the safety net, not the normal path.
|
|
415
|
+
|
|
416
|
+
In degraded mode:
|
|
417
|
+
- Lab spawns `claude -p` with the forge personality adapter prepended to the prompt
|
|
418
|
+
- Execution is headless — the visibility model does not apply
|
|
419
|
+
- Pipeline correctness is maintained — handoff format is identical to IPC mode
|
|
420
|
+
- Workers recovering in the background resume IPC routing automatically
|
|
421
|
+
|
|
422
|
+
Degraded mode is transparent from a pipeline correctness standpoint. It is visible in the forge dashboard (workers show as offline or degraded).
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## Agent Roster Mapping
|
|
427
|
+
|
|
428
|
+
| Pipeline Stage | Forge Worker | Notes |
|
|
429
|
+
|---|---|---|
|
|
430
|
+
| Dev — frontend | anvil | Frontend specialist |
|
|
431
|
+
| Dev — backend | furnace | Backend/infra specialist |
|
|
432
|
+
| Dev — fullstack | anvil | Default to frontend lead |
|
|
433
|
+
| Code review | temper | Adversarial reviewer — NOT crucible |
|
|
434
|
+
| Arch review | architect | Structural and design review |
|
|
435
|
+
| UX review | pixel | Design and accessibility review |
|
|
436
|
+
| Test runner | crucible | Tester and coverage writer |
|
|
437
|
+
| Release manager | **lab agent-7** | Must stay lab — see below |
|
|
438
|
+
|
|
439
|
+
**Crucible → test runner, forge Sentinel → code review.** This mapping is fixed.
|
|
440
|
+
|
|
441
|
+
### Why Release Manager Must Stay Lab
|
|
442
|
+
|
|
443
|
+
Lab's `agent-7-release-manager` is the pipeline termination agent. It is hardcoded in `SubagentManager.check_completed()`:
|
|
444
|
+
|
|
445
|
+
```python
|
|
446
|
+
if agent.agent_type == "release-manager" and status == "completed":
|
|
447
|
+
log_pipeline_run_complete(...)
|
|
448
|
+
remove_story_worktree(project_path, agent.story_id)
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Any other agent in this slot means worktrees are never pruned. Stories pile up as orphans. Lab's release agent must stay lab's. Herald (forge's release agent) does not know this protocol and must not own this slot.
|
|
452
|
+
|
|
453
|
+
---
|
|
454
|
+
|
|
455
|
+
## Story Submission: Forge → Lab
|
|
456
|
+
|
|
457
|
+
> **Long-term transport note:** `create_story` and `get_story_status` currently use sentinel's local MCP server (stdio) as transport. This is intentional for now — forge is local, sentinel is local, no network hop required. The sentinel MCP surface is a candidate for deprecation as hub MCP matures. When hub MCP reaches parity on these two tools, forge should migrate to hub MCP as the stable external-facing transport. This migration is not in the current story set but should not be designed out — forge's MCP call sites should be abstracted behind a thin client so the transport swap is a one-line config change.
|
|
458
|
+
|
|
459
|
+
```
|
|
460
|
+
MCP tool: create_story
|
|
461
|
+
Transport: stdio (local sentinel MCP server)
|
|
462
|
+
|
|
463
|
+
Required fields:
|
|
464
|
+
forge_task_id string task filename without extension
|
|
465
|
+
source string always "forge"
|
|
466
|
+
session_id string forge daemon session ID (correlation key)
|
|
467
|
+
task_type enum frontend | backend | arch | docs | test | devops | security
|
|
468
|
+
urgency enum low | normal | high
|
|
469
|
+
skip_reviews string[] default []
|
|
470
|
+
has_db_migration boolean default false
|
|
471
|
+
has_api_changes boolean default false
|
|
472
|
+
|
|
473
|
+
Optional fields:
|
|
474
|
+
estimated_scope enum small | medium | large (defaults to "medium" when absent)
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
**urgency → priority mapping** (resolved in FORGE-1):
|
|
478
|
+
|
|
479
|
+
| urgency (forge) | priority (lab) |
|
|
480
|
+
|---|---|
|
|
481
|
+
| low | low |
|
|
482
|
+
| normal | medium |
|
|
483
|
+
| high | high |
|
|
484
|
+
|
|
485
|
+
`has_db_migration: true` — suppresses fast-lane, forces full arch review.
|
|
486
|
+
`has_api_changes: true` — forces code review even on small scope.
|
|
487
|
+
Both fields must be wired to Dispatcher routing logic at FORGE-1 time. Storing without acting is not sufficient.
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
491
|
+
## Event Stream: Forge → Lab
|
|
492
|
+
|
|
493
|
+
```
|
|
494
|
+
HTTP POST /api/projects/:id/events
|
|
495
|
+
Auth: Bearer VIBE_LAB_FORGE_TOKEN
|
|
496
|
+
|
|
497
|
+
{
|
|
498
|
+
"source": "forge",
|
|
499
|
+
"type": "forge-session-started | forge-session-ended | forge-agent-started |
|
|
500
|
+
forge-agent-idle | forge-task-started | forge-task-completed |
|
|
501
|
+
forge-task-escalated",
|
|
502
|
+
"agent": "anvil",
|
|
503
|
+
"task_id": "task-042",
|
|
504
|
+
"session_id": "abc123",
|
|
505
|
+
"timestamp": "<ISO8601>",
|
|
506
|
+
"metadata": { "agent_display_name": "Anvil", "task_title": "Add login form" }
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
Fire-and-forget. `|| true`. Never blocks worker execution.
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Status Feedback: Lab → Forge
|
|
515
|
+
|
|
516
|
+
**Story status query (FORGE-5)**
|
|
517
|
+
|
|
518
|
+
```
|
|
519
|
+
MCP tool: get_story_status
|
|
520
|
+
Parameters: forge_task_id, project_path
|
|
521
|
+
Returns: { lab_story_id, found, status, title, assigned_to, started, completed, pr, branch }
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
Called by the forge daemon at idle maintenance cycles. Non-fatal if lab is unreachable.
|
|
525
|
+
|
|
526
|
+
**Real-time relay subscription (FORGE-6)**
|
|
527
|
+
|
|
528
|
+
```
|
|
529
|
+
WebSocket: wss://<relay-host>/subscribe?project=<project-id>
|
|
530
|
+
Auth: first-message → { "auth": "<VIBE_LAB_FORGE_TOKEN>" }
|
|
531
|
+
|
|
532
|
+
Forge subscribes to: story_transition, agent_completed, queue_summary
|
|
533
|
+
Forge ignores: heartbeat, agent_start
|
|
534
|
+
|
|
535
|
+
Relay event envelope (all forge-originated events):
|
|
536
|
+
{
|
|
537
|
+
"project_id": "vibe-lab", ← explicit project ID, not just "project" alias
|
|
538
|
+
"project": "vibe-lab", ← existing field, kept for relay compatibility
|
|
539
|
+
"event": "story_transition",
|
|
540
|
+
"story": "FORGE-3",
|
|
541
|
+
"forge_task_id": "FORGE-TASK-42",
|
|
542
|
+
"from_status": "in-progress",
|
|
543
|
+
"to_status": "review",
|
|
544
|
+
"timestamp": "<ISO8601>"
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
Both `project_id` and `forge_task_id` must be present on all events for forge-originated stories.
|
|
548
|
+
Thread through: DB → sentinel event → relay broadcast.
|
|
549
|
+
`project_id` is the authoritative cross-project discriminator. Forge uses it, not `story`, to correlate events.
|
|
550
|
+
|
|
551
|
+
Forge maintains one relay connection per lab project. If forge manages multiple lab projects simultaneously,
|
|
552
|
+
it opens one WebSocket subscription per project_id and routes incoming events by project_id before
|
|
553
|
+
dispatching to the appropriate local tracking entry.
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
Relay validates `VIBE_LAB_FORGE_TOKEN` against hub DB on connect. Fail closed if hub unreachable.
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Authentication
|
|
561
|
+
|
|
562
|
+
**One credential: `VIBE_LAB_FORGE_TOKEN`**
|
|
563
|
+
|
|
564
|
+
- Environment variable only — never written to any committed file or log
|
|
565
|
+
- Injected into forge daemon process only, not passed to worker subprocesses
|
|
566
|
+
- Hub enforces scope: `create_story` and `post_events`, `source == "forge"`, matching `project_id` only. All other calls 403.
|
|
567
|
+
- Rate limit: 5 `create_story` per 10-second window per `session_id`. 429 + `Retry-After`. Forge retries on next sync cycle.
|
|
568
|
+
- Relay: validated against hub DB on connect, cached for session lifetime, re-validated on reconnect, fail closed.
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## Story Ownership
|
|
573
|
+
|
|
574
|
+
Once a story enters the lab pipeline, **lab owns the execution lifecycle unconditionally.**
|
|
575
|
+
|
|
576
|
+
Forge creates a story and submits it. Lab routes it to forge workers for execution, sequences the review chain, merges, and releases. Forge workers cannot modify, reprioritize, or cancel an in-progress story.
|
|
577
|
+
|
|
578
|
+
Forge must not re-submit a story that already has an entry in `.forge/lab-stories.json`. The tracking file is keyed by `{project_id}/{forge_task_id}` — not by story ID alone — because vibe-lab manages multiple projects and story IDs are only unique within a project, not across them.
|
|
579
|
+
|
|
580
|
+
```json
|
|
581
|
+
// .forge/lab-stories.json
|
|
582
|
+
{
|
|
583
|
+
"vibe-lab/FORGE-TASK-42": {
|
|
584
|
+
"project_id": "vibe-lab",
|
|
585
|
+
"forge_task_id": "FORGE-TASK-42",
|
|
586
|
+
"lab_story_id": "FORGE-3",
|
|
587
|
+
"status": "in-progress",
|
|
588
|
+
"last_checked": "2026-04-01T12:00:00Z"
|
|
589
|
+
},
|
|
590
|
+
"vibe-api/FORGE-TASK-07": {
|
|
591
|
+
"project_id": "vibe-api",
|
|
592
|
+
"forge_task_id": "FORGE-TASK-07",
|
|
593
|
+
"lab_story_id": "FORGE-3",
|
|
594
|
+
"status": "backlog",
|
|
595
|
+
"last_checked": "2026-04-01T11:00:00Z"
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
Note both entries above have `lab_story_id: "FORGE-3"` — valid, because they are in different projects. The `{project_id}/{forge_task_id}` composite key is what makes them distinct.
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
## Full Story Set and Sequencing
|
|
605
|
+
|
|
606
|
+
### FORGE Stories — pipeline plumbing
|
|
607
|
+
|
|
608
|
+
```
|
|
609
|
+
FORGE-7 (ownership policy doc, co-authored)
|
|
610
|
+
↓
|
|
611
|
+
FORGE-1 (create_story forge fields + DB migration + urgency mapping + routing wiring)
|
|
612
|
+
↓
|
|
613
|
+
FORGE-5 (get_story_status MCP tool)
|
|
614
|
+
↓
|
|
615
|
+
FORGE-2 (CORS + scoped forge token)
|
|
616
|
+
↓
|
|
617
|
+
FORGE-3 (events API) ┐
|
|
618
|
+
FORGE-4 (forge sessions dashboard panel, relay push) ├── parallel
|
|
619
|
+
FORGE-6 (relay subscription + forge_task_id threading) ┘
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### LAB-FORGE Stories — personality execution layer
|
|
623
|
+
|
|
624
|
+
```
|
|
625
|
+
LAB-FORGE-1 (agent_personalities config schema) ─── start now
|
|
626
|
+
LAB-FORGE-2 (personality adapter docs: all agents) ─── parallel
|
|
627
|
+
↓
|
|
628
|
+
LAB-FORGE-3 (SubagentManager personality_prefix + context-reset prompt)
|
|
629
|
+
↓
|
|
630
|
+
LAB-FORGE-4 (Dispatcher personality routing)
|
|
631
|
+
↓
|
|
632
|
+
LAB-FORGE-5 (integration test — forge personality end-to-end, validates handoff format)
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### IPC Stories — persistent worker routing (the full vision)
|
|
636
|
+
|
|
637
|
+
*Starts after LAB-FORGE-5 confirms handoff format correctness.*
|
|
638
|
+
|
|
639
|
+
```
|
|
640
|
+
IPC-1 (forge daemon: agent availability API at /api/workers/available)
|
|
641
|
+
IPC-2 (forge: worker-inbox/ directory structure + stop hook lab inbox check) ┐ parallel
|
|
642
|
+
IPC-3 (forge: inbox task file format, worktree_path field, context-reset prompt)┘
|
|
643
|
+
↓
|
|
644
|
+
IPC-4 (lab: Dispatcher routing — availability check → inbox write vs degraded spawn)
|
|
645
|
+
IPC-5 (lab: sentinel inbox watcher + .picked-up detection + timeout policy + orphan fallback)
|
|
646
|
+
↓
|
|
647
|
+
IPC-6 (lab: integration test — warm worker story end-to-end)
|
|
648
|
+
↓
|
|
649
|
+
IPC-7 (forge: background worker lifecycle — daemon-managed processes, forge attach)
|
|
650
|
+
Spec note: `forge attach` on Windows requires explicit design. tmux is not native on Windows.
|
|
651
|
+
Candidates: Windows Terminal tab re-attach, named pipe, or Node.js/Bun PTY multiplexer.
|
|
652
|
+
IPC-7's spec must choose and document the mechanism before implementation starts.
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
```
|
|
656
|
+
PLAT-1 (Heimdall — pre-tool hook interceptor) ─── parallel with IPC-1 through IPC-6
|
|
657
|
+
prerequisite for IPC-7
|
|
658
|
+
Applicability note: Heimdall also applies to LAB-FORGE degraded spawn (which also runs
|
|
659
|
+
with --dangerously-skip-permissions). LAB-FORGE-3 (SubagentManager personality prefix
|
|
660
|
+
injection) must write .claude/settings.local.json to the worktree at spawn time, the same
|
|
661
|
+
as IPC workers. Heimdall is not IPC-7-only — it applies to every worker that runs
|
|
662
|
+
with --dangerously-skip-permissions, supervised or not.
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
IPC-7 is the final piece: daemon-managed background workers replace human-spawned terminal tabs. After IPC-7, forge workers are always running as part of lab, with no human startup required.
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
## What Stays Separate
|
|
670
|
+
|
|
671
|
+
- **Codebases and repositories.** Deployment merger, not code merger. Forge's bash daemon, worker loop, personality files, and filesystem-as-state remain in the forge repo. Lab's sentinel, hub, relay, and review chain remain in the lab repo. Lab declares forge as an npm dependency.
|
|
672
|
+
- **vibe-forge standalone.** Continues to ship and work independently. Forge-only users install and use forge without lab. Unchanged.
|
|
673
|
+
- **Forge's internal task model.** `backlog/`, `in-progress/`, `completed/` filesystem is unchanged for forge-native tasks. Lab stories arrive via `worker-inbox/` — a separate path that does not disturb forge's own task queue.
|
|
674
|
+
|
|
675
|
+
---
|
|
676
|
+
|
|
677
|
+
## What This Is Not
|
|
678
|
+
|
|
679
|
+
- Forge is not being rewritten to fit lab's stack. Language boundary preserved.
|
|
680
|
+
- Lab is not adopting bash. Lab's sentinel, hub, and relay remain Python/TypeScript.
|
|
681
|
+
- The release manager is never a forge worker. It must remain `lab/agent-7-release-manager`.
|
|
682
|
+
- Forge workers in lab's pipeline are not headless subprocesses. They are real Claude Code sessions, observable on demand via `forge attach`.
|
|
683
|
+
- Human presence is not required for the pipeline to run. Workers run as background services. Human presence enables visibility, not operation.
|
|
684
|
+
- Background workers with `--dangerously-skip-permissions` are not ungated. Heimdall provides pre-execution policy enforcement at tool-call time. Lab's review chain provides output correctness validation at merge time. Both gates are active.
|