vibe-coding-master 0.0.11 → 0.0.12
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/README.md +15 -13
- package/dist/backend/services/project-service.js +2 -2
- package/dist/backend/services/task-service.js +30 -4
- package/dist/backend/templates/harness/claude-root.js +2 -2
- package/dist/cli/vcmctl.js +1 -1
- package/docs/cc-best-practices.md +14 -15
- package/docs/product-design.md +17 -16
- package/docs/v1-architecture-design.md +13 -9
- package/docs/v1-implementation-plan.md +14 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -207,7 +207,7 @@ Translation settings are local and stored in:
|
|
|
207
207
|
~/.vcm/settings.json
|
|
208
208
|
```
|
|
209
209
|
|
|
210
|
-
The same file stores recent repository paths. The translation API key is stored locally under `translation.secrets.apiKey`; it is not written to the connected repository, `.ai/handoffs`, raw terminal logs, or git diffs.
|
|
210
|
+
The same file stores recent repository paths. The translation API key is stored locally under `translation.secrets.apiKey`; it is not written to the connected repository, `.ai/vcm/handoffs`, raw terminal logs, or git diffs.
|
|
211
211
|
|
|
212
212
|
The sidebar `Settings` section also stores the UI theme preference in this file. The default is `system`, which follows the OS/browser color-scheme preference; users can cycle between `System`, `Light`, and `Dark`.
|
|
213
213
|
|
|
@@ -283,18 +283,18 @@ Examples that roles can run inside their terminal:
|
|
|
283
283
|
```bash
|
|
284
284
|
vcmctl send --to coder --type task --body-file /tmp/message.md
|
|
285
285
|
vcmctl reply --type blocked --body "Need clarification."
|
|
286
|
-
vcmctl result --body-file /tmp/result.md --artifact .ai/handoffs/
|
|
286
|
+
vcmctl result --body-file /tmp/result.md --artifact .ai/vcm/handoffs/implementation-log.md
|
|
287
287
|
vcmctl inbox
|
|
288
288
|
```
|
|
289
289
|
|
|
290
|
-
|
|
290
|
+
Runtime message and handoff files:
|
|
291
291
|
|
|
292
292
|
```text
|
|
293
293
|
.ai/vcm/messages/<task>.jsonl # under the task runtime repo
|
|
294
294
|
.ai/vcm/orchestration/<task>.json # under the task runtime repo
|
|
295
|
-
.ai/handoffs
|
|
296
|
-
.ai/handoffs
|
|
297
|
-
.ai/handoffs
|
|
295
|
+
.ai/vcm/handoffs/messages/<message-id>.md
|
|
296
|
+
.ai/vcm/handoffs/role-commands/
|
|
297
|
+
.ai/vcm/handoffs/logs/
|
|
298
298
|
```
|
|
299
299
|
|
|
300
300
|
The backend also keeps a compatibility role-command dispatch endpoint, but the primary workflow is PM-mediated `vcmctl` messaging.
|
|
@@ -350,17 +350,19 @@ For a connected repository, VCM uses:
|
|
|
350
350
|
<taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
|
|
351
351
|
<taskRepoRoot>/.ai/vcm/orchestration/<task>.json
|
|
352
352
|
<taskRepoRoot>/.ai/vcm/translation/<task>/
|
|
353
|
-
<taskRepoRoot>/.ai/handoffs
|
|
354
|
-
<taskRepoRoot>/.ai/handoffs
|
|
355
|
-
<taskRepoRoot>/.ai/handoffs
|
|
356
|
-
<taskRepoRoot>/.ai/handoffs
|
|
357
|
-
<taskRepoRoot>/.ai/handoffs
|
|
358
|
-
<taskRepoRoot>/.ai/handoffs
|
|
359
|
-
<taskRepoRoot>/.ai/handoffs
|
|
353
|
+
<taskRepoRoot>/.ai/vcm/handoffs/architecture-plan.md
|
|
354
|
+
<taskRepoRoot>/.ai/vcm/handoffs/implementation-log.md
|
|
355
|
+
<taskRepoRoot>/.ai/vcm/handoffs/validation-log.md
|
|
356
|
+
<taskRepoRoot>/.ai/vcm/handoffs/review-report.md
|
|
357
|
+
<taskRepoRoot>/.ai/vcm/handoffs/docs-sync-report.md
|
|
358
|
+
<taskRepoRoot>/.ai/vcm/handoffs/role-commands/{architect,coder,reviewer}.md
|
|
359
|
+
<taskRepoRoot>/.ai/vcm/handoffs/logs/{project-manager,architect,coder,reviewer}.log
|
|
360
360
|
```
|
|
361
361
|
|
|
362
362
|
The project config is stored under `~/.vcm` so it is durable local app state and is not hidden inside a Git-ignored repository directory. For worktree-backed tasks, `taskRepoRoot` is `<baseRepoRoot>/.ai/vcm/worktrees/<task>`; for inline tasks, `taskRepoRoot` is the connected base repo.
|
|
363
363
|
|
|
364
|
+
Because handoffs are scoped to `taskRepoRoot` without an extra task-name directory, VCM allows only one active inline task per connected repository. Use the default worktree mode for parallel tasks.
|
|
365
|
+
|
|
364
366
|
## Packaging
|
|
365
367
|
|
|
366
368
|
The npm package publishes built output, not raw TypeScript entry files. `package.json` includes:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { ROLE_NAMES } from "../../shared/constants.js";
|
|
3
3
|
import { VcmError } from "../errors.js";
|
|
4
|
-
const DEFAULT_HANDOFF_ROOT = ".ai/handoffs";
|
|
4
|
+
const DEFAULT_HANDOFF_ROOT = ".ai/vcm/handoffs";
|
|
5
5
|
const DEFAULT_STATE_ROOT = ".ai/vcm";
|
|
6
6
|
export function createProjectService(deps) {
|
|
7
7
|
let currentProject = null;
|
|
@@ -116,7 +116,7 @@ function normalizeProjectConfig(input, repoRoot) {
|
|
|
116
116
|
version: 1,
|
|
117
117
|
repoRoot,
|
|
118
118
|
defaultRoles: input.defaultRoles?.length ? input.defaultRoles : fallback.defaultRoles,
|
|
119
|
-
handoffRoot:
|
|
119
|
+
handoffRoot: DEFAULT_HANDOFF_ROOT,
|
|
120
120
|
stateRoot: DEFAULT_STATE_ROOT,
|
|
121
121
|
terminalBackend: "node-pty",
|
|
122
122
|
claudeCommand: input.claudeCommand || fallback.claudeCommand
|
|
@@ -30,6 +30,17 @@ export function createTaskService(deps) {
|
|
|
30
30
|
hint: "Apply VCM Harness first so .gitignore contains the VCM managed block."
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
if (!shouldCreateWorktree) {
|
|
34
|
+
const activeInlineTask = await findActiveInlineTask(deps.fs, repoRoot, config.stateRoot);
|
|
35
|
+
if (activeInlineTask) {
|
|
36
|
+
throw new VcmError({
|
|
37
|
+
code: "INLINE_TASK_EXISTS",
|
|
38
|
+
message: `An inline task already exists: ${activeInlineTask.taskSlug}`,
|
|
39
|
+
statusCode: 409,
|
|
40
|
+
hint: "Close the existing inline task first, or enable Create worktree and branch for this task."
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
33
44
|
if (shouldCreateWorktree && worktreePath) {
|
|
34
45
|
if (await deps.git.branchExists(repoRoot, taskBranch)) {
|
|
35
46
|
throw new VcmError({
|
|
@@ -75,7 +86,7 @@ export function createTaskService(deps) {
|
|
|
75
86
|
repoRoot,
|
|
76
87
|
worktreePath,
|
|
77
88
|
branch: taskBranch,
|
|
78
|
-
handoffDir:
|
|
89
|
+
handoffDir: config.handoffRoot,
|
|
79
90
|
status: "created",
|
|
80
91
|
specPath: input.specPath,
|
|
81
92
|
cleanupStatus: "active"
|
|
@@ -146,7 +157,7 @@ export function createTaskService(deps) {
|
|
|
146
157
|
const config = await deps.projectService.loadConfig(repoRoot);
|
|
147
158
|
const task = await this.loadTask(repoRoot, taskSlug);
|
|
148
159
|
const taskRepoRoot = getTaskRuntimeRepoRoot(task);
|
|
149
|
-
const statePaths = getTaskStatePaths(repoRoot, taskRepoRoot, config.stateRoot, taskSlug);
|
|
160
|
+
const statePaths = getTaskStatePaths(repoRoot, taskRepoRoot, config.stateRoot, config.handoffRoot, taskSlug);
|
|
150
161
|
const removedStatePaths = [];
|
|
151
162
|
const cleanedAt = now();
|
|
152
163
|
if (task.worktreePath) {
|
|
@@ -187,13 +198,28 @@ async function ensureTaskRuntimeStateDirs(fs, taskRepoRoot, stateRoot) {
|
|
|
187
198
|
await fs.ensureDir(path.join(taskRepoRoot, stateRoot, "orchestration"));
|
|
188
199
|
await fs.ensureDir(path.join(taskRepoRoot, stateRoot, "translation"));
|
|
189
200
|
}
|
|
190
|
-
function
|
|
201
|
+
async function findActiveInlineTask(fs, repoRoot, stateRoot) {
|
|
202
|
+
const tasksDir = path.join(repoRoot, stateRoot, "tasks");
|
|
203
|
+
if (!(await fs.pathExists(tasksDir))) {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
const entries = await fs.readDir(tasksDir);
|
|
207
|
+
for (const entry of entries.filter((candidate) => candidate.endsWith(".json"))) {
|
|
208
|
+
const task = await fs.readJson(path.join(tasksDir, entry));
|
|
209
|
+
if (!task.worktreePath && task.cleanupStatus !== "cleaned") {
|
|
210
|
+
return task;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return undefined;
|
|
214
|
+
}
|
|
215
|
+
function getTaskStatePaths(baseRepoRoot, taskRepoRoot, stateRoot, handoffRoot, taskSlug) {
|
|
191
216
|
return [
|
|
192
217
|
path.join(baseRepoRoot, stateRoot, "tasks", `${taskSlug}.json`),
|
|
193
218
|
path.join(taskRepoRoot, stateRoot, "sessions", `${taskSlug}.json`),
|
|
194
219
|
path.join(taskRepoRoot, stateRoot, "messages", `${taskSlug}.jsonl`),
|
|
195
220
|
path.join(taskRepoRoot, stateRoot, "orchestration", `${taskSlug}.json`),
|
|
196
|
-
path.join(taskRepoRoot, stateRoot, "translation", taskSlug)
|
|
221
|
+
path.join(taskRepoRoot, stateRoot, "translation", taskSlug),
|
|
222
|
+
path.join(taskRepoRoot, handoffRoot)
|
|
197
223
|
];
|
|
198
224
|
}
|
|
199
225
|
function assertTaskWorktreePath(repoRoot, stateRoot, worktreePath) {
|
|
@@ -3,9 +3,9 @@ export function renderRootClaudeHarnessRules() {
|
|
|
3
3
|
|
|
4
4
|
- This repository uses VibeCodingMaster for multi-session Claude Code work.
|
|
5
5
|
- User-facing work starts with the project-manager role.
|
|
6
|
-
- Canonical task handoffs live under .ai/handoffs
|
|
6
|
+
- Canonical task handoffs live under .ai/vcm/handoffs/ inside the current task runtime repo.
|
|
7
7
|
- Use only the current task's handoff directory for task-specific artifacts.
|
|
8
|
-
- Do not create or write .ai/handoffs
|
|
8
|
+
- Do not create or write task handoffs outside .ai/vcm/handoffs/ for the current task.
|
|
9
9
|
- Use vcmctl for role-to-role messaging instead of asking the user to copy prompts.
|
|
10
10
|
- Non-PM roles only reply to project-manager; they do not message other roles directly.
|
|
11
11
|
- High-risk decisions involving schema, auth, permissions, payment, billing, security, data deletion, or unclear user intent must stop for project-manager/user approval.
|
package/dist/cli/vcmctl.js
CHANGED
|
@@ -131,7 +131,7 @@ function printHelp() {
|
|
|
131
131
|
Usage:
|
|
132
132
|
vcmctl send --to coder --type task --body-file /tmp/message.md
|
|
133
133
|
vcmctl reply --type blocked --body "Need clarification."
|
|
134
|
-
vcmctl result --body-file /tmp/result.md --artifact .ai/handoffs/
|
|
134
|
+
vcmctl result --body-file /tmp/result.md --artifact .ai/vcm/handoffs/implementation-log.md
|
|
135
135
|
vcmctl inbox
|
|
136
136
|
`);
|
|
137
137
|
}
|
|
@@ -97,13 +97,12 @@ repo/
|
|
|
97
97
|
|
|
98
98
|
.ai/
|
|
99
99
|
vcm/ # ignored local VCM control state
|
|
100
|
-
|
|
101
|
-
handoffs/
|
|
102
|
-
<task-slug>/
|
|
100
|
+
handoffs/
|
|
103
101
|
architecture-plan.md
|
|
104
102
|
implementation-log.md
|
|
105
103
|
validation-log.md
|
|
106
104
|
review-report.md
|
|
105
|
+
task-specs/
|
|
107
106
|
state/
|
|
108
107
|
progress.md
|
|
109
108
|
decisions.md
|
|
@@ -213,7 +212,7 @@ Role-specific behavior lives in `.claude/agents/`.
|
|
|
213
212
|
- Default core roles are `project-manager`, `architect`, `coder`, and `reviewer`.
|
|
214
213
|
- The `project-manager` role owns user communication, task routing, role commands, handoff verification, final status reporting, and PR preparation after required gates pass.
|
|
215
214
|
- Do not let one coding session own architecture/plan decisions, implementation, final testing responsibility, and review.
|
|
216
|
-
- Role outputs are exchanged through `.ai/handoffs
|
|
215
|
+
- Role outputs are exchanged through `.ai/vcm/handoffs/`, not through chat history.
|
|
217
216
|
- When the required role route includes `architect`, coding must not start until the architecture and plan artifact exists.
|
|
218
217
|
- If the current session was not started with the required role, stop and ask the user to restart with `claude --agent <role>`; do not pretend to be that role inside the wrong session.
|
|
219
218
|
- Critical global rules may be repeated in role agent files for defense in depth, but repeated rules must use stable rule IDs and be checked by `tools/check-agent-rules`. Do not maintain untracked manual copies.
|
|
@@ -628,7 +627,7 @@ Role command examples:
|
|
|
628
627
|
```text
|
|
629
628
|
architect command:
|
|
630
629
|
read the task spec, architecture docs, module map, and relevant module-local CLAUDE.md
|
|
631
|
-
produce .ai/handoffs
|
|
630
|
+
produce .ai/vcm/handoffs/architecture-plan.md
|
|
632
631
|
define file responsibilities, public contracts, test contracts, phases, validation, and Replan triggers
|
|
633
632
|
do not edit production code
|
|
634
633
|
|
|
@@ -726,8 +725,8 @@ architect
|
|
|
726
725
|
owns architecture and plan
|
|
727
726
|
defines module boundaries, file responsibilities, public contracts, dependency direction, risk, and phases
|
|
728
727
|
owns post-review docs sync and architecture drift checks before PM final acceptance
|
|
729
|
-
outputs .ai/handoffs
|
|
730
|
-
outputs .ai/handoffs
|
|
728
|
+
outputs .ai/vcm/handoffs/architecture-plan.md
|
|
729
|
+
outputs .ai/vcm/handoffs/docs-sync-report.md when a post-review docs sync gate is required
|
|
731
730
|
must not implement production code
|
|
732
731
|
|
|
733
732
|
coder
|
|
@@ -743,7 +742,7 @@ reviewer
|
|
|
743
742
|
checks, designs, and adds missing tests when needed
|
|
744
743
|
may directly apply small, local, low-risk review fixes
|
|
745
744
|
owns complex tests, E2E coverage, regression matrix, and release-level validation recommendations
|
|
746
|
-
outputs .ai/handoffs
|
|
745
|
+
outputs .ai/vcm/handoffs/review-report.md
|
|
747
746
|
must escalate larger implementation issues to coder
|
|
748
747
|
must escalate architecture, public contract, design, or documentation drift issues to architect
|
|
749
748
|
```
|
|
@@ -781,7 +780,7 @@ Role sessions communicate through files, not memory from previous chats.
|
|
|
781
780
|
Required handoff directory:
|
|
782
781
|
|
|
783
782
|
```text
|
|
784
|
-
.ai/handoffs
|
|
783
|
+
.ai/vcm/handoffs/
|
|
785
784
|
role-commands/
|
|
786
785
|
architect.md
|
|
787
786
|
coder.md
|
|
@@ -875,7 +874,7 @@ escalate to architect:
|
|
|
875
874
|
the implementation reveals that the architecture plan is invalid
|
|
876
875
|
```
|
|
877
876
|
|
|
878
|
-
For a task with a handoff directory, `.ai/handoffs
|
|
877
|
+
For a task with a handoff directory, `.ai/vcm/handoffs/validation-log.md` is the authoritative validation record for that task. `.ai/state/validation-log.md` is only a rolling index of recent validation results across tasks.
|
|
879
878
|
|
|
880
879
|
For complex or high-risk work, the next role must not start until the required previous artifact exists and is coherent.
|
|
881
880
|
|
|
@@ -1038,7 +1037,7 @@ You are the architecture and planning role for this project.
|
|
|
1038
1037
|
|
|
1039
1038
|
# Outputs
|
|
1040
1039
|
|
|
1041
|
-
- `.ai/handoffs
|
|
1040
|
+
- `.ai/vcm/handoffs/architecture-plan.md`
|
|
1042
1041
|
|
|
1043
1042
|
# Do Not
|
|
1044
1043
|
|
|
@@ -1489,8 +1488,8 @@ Branch rules:
|
|
|
1489
1488
|
Close Task rules:
|
|
1490
1489
|
|
|
1491
1490
|
- after task completion, use VCM `Close Task` only when the user is ready to delete task-local state
|
|
1492
|
-
- for worktree-backed tasks, `Close Task` deletes the task worktree, deletes the task branch by default, and removes VCM task/session/message/orchestration metadata
|
|
1493
|
-
- `Close Task`
|
|
1491
|
+
- for worktree-backed tasks, `Close Task` deletes the task worktree, deletes the task branch by default, and removes VCM task/session/message/orchestration/handoff metadata
|
|
1492
|
+
- `Close Task` stops VCM-managed running role sessions, but it does not check uncommitted changes; finish, commit, or preserve anything important before using it
|
|
1494
1493
|
|
|
1495
1494
|
Small commits:
|
|
1496
1495
|
|
|
@@ -1613,7 +1612,7 @@ State files:
|
|
|
1613
1612
|
|
|
1614
1613
|
Validation log authority:
|
|
1615
1614
|
|
|
1616
|
-
- `.ai/handoffs
|
|
1615
|
+
- `.ai/vcm/handoffs/validation-log.md` is authoritative for one task.
|
|
1617
1616
|
- `.ai/state/validation-log.md` is a rolling index across tasks and should point to the task-level log when one exists.
|
|
1618
1617
|
- Final reports and review reports should cite the task-level validation log, not scattered chat output.
|
|
1619
1618
|
|
|
@@ -1868,7 +1867,7 @@ behavior is correct
|
|
|
1868
1867
|
- [ ] For T2+ work, architect performed post-review docs sync / architecture drift check before final PM acceptance.
|
|
1869
1868
|
- [ ] Docs updates or a docs-sync-report explain why affected architecture/module/testing/security/dependency docs are current.
|
|
1870
1869
|
- [ ] The project manager prepared final acceptance, commit, and PR only after reviewer and docs-sync gates passed or an exception was approved.
|
|
1871
|
-
- [ ] Task-level validation evidence is recorded in `.ai/handoffs
|
|
1870
|
+
- [ ] Task-level validation evidence is recorded in `.ai/vcm/handoffs/validation-log.md` when a handoff directory exists.
|
|
1872
1871
|
|
|
1873
1872
|
## Architecture
|
|
1874
1873
|
|
package/docs/product-design.md
CHANGED
|
@@ -111,13 +111,14 @@ Task creation flow:
|
|
|
111
111
|
New Task submit
|
|
112
112
|
-> validate task name
|
|
113
113
|
-> verify .ai/vcm/ is ignored
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
114
|
+
-> if Create worktree and branch is selected:
|
|
115
|
+
-> derive branch feature/<task-name>
|
|
116
|
+
-> derive worktree path .ai/vcm/worktrees/<task-name>
|
|
117
|
+
-> verify the base repo is clean
|
|
118
|
+
-> git worktree add -b feature/<task-name> .ai/vcm/worktrees/<task-name> <base-ref>
|
|
119
|
+
-> otherwise:
|
|
120
|
+
-> use the connected repo path and current branch
|
|
121
|
+
-> reject if another inline task is already active
|
|
121
122
|
-> create task metadata
|
|
122
123
|
-> create handoff structure inside the task runtime repo
|
|
123
124
|
-> open the task workspace with role session cwd = task runtime repo
|
|
@@ -169,8 +170,8 @@ The architect owns:
|
|
|
169
170
|
|
|
170
171
|
Outputs:
|
|
171
172
|
|
|
172
|
-
- `.ai/handoffs
|
|
173
|
-
- `.ai/handoffs
|
|
173
|
+
- `.ai/vcm/handoffs/architecture-plan.md`
|
|
174
|
+
- `.ai/vcm/handoffs/docs-sync-report.md`
|
|
174
175
|
|
|
175
176
|
### Coder
|
|
176
177
|
|
|
@@ -183,8 +184,8 @@ The coder owns:
|
|
|
183
184
|
|
|
184
185
|
Outputs:
|
|
185
186
|
|
|
186
|
-
- `.ai/handoffs
|
|
187
|
-
- `.ai/handoffs
|
|
187
|
+
- `.ai/vcm/handoffs/implementation-log.md`
|
|
188
|
+
- `.ai/vcm/handoffs/validation-log.md`
|
|
188
189
|
|
|
189
190
|
### Reviewer
|
|
190
191
|
|
|
@@ -198,7 +199,7 @@ The reviewer owns:
|
|
|
198
199
|
|
|
199
200
|
Output:
|
|
200
201
|
|
|
201
|
-
- `.ai/handoffs
|
|
202
|
+
- `.ai/vcm/handoffs/review-report.md`
|
|
202
203
|
|
|
203
204
|
## 6. Information Architecture
|
|
204
205
|
|
|
@@ -393,7 +394,7 @@ Role sessions get VCM behavior from `CLAUDE.md` and `.claude/agents/*.md`, not f
|
|
|
393
394
|
Each task creates:
|
|
394
395
|
|
|
395
396
|
```text
|
|
396
|
-
.ai/handoffs
|
|
397
|
+
.ai/vcm/handoffs/
|
|
397
398
|
role-commands/
|
|
398
399
|
architect.md
|
|
399
400
|
coder.md
|
|
@@ -412,7 +413,7 @@ Each task creates:
|
|
|
412
413
|
<message-id>.md
|
|
413
414
|
```
|
|
414
415
|
|
|
415
|
-
The product treats handoff files as
|
|
416
|
+
The product treats handoff files as task-local coordination facts. The terminal is useful for live interaction, but handoff files and message history are the source of truth during a task. They live under `.ai/vcm/`, are ignored by Git, and are removed by `Close Task`; final decisions that should survive must be copied into normal project docs, source, commit messages, or PR text.
|
|
416
417
|
|
|
417
418
|
The main UI no longer has a dedicated artifact panel. Artifact APIs still exist for status checks, role command compatibility, and future UI work.
|
|
418
419
|
|
|
@@ -584,10 +585,10 @@ Task worktree local files:
|
|
|
584
585
|
.ai/vcm/worktrees/<task>/.ai/vcm/messages/<task>.jsonl
|
|
585
586
|
.ai/vcm/worktrees/<task>/.ai/vcm/orchestration/<task>.json
|
|
586
587
|
.ai/vcm/worktrees/<task>/.ai/vcm/translation/<task>/
|
|
587
|
-
.ai/vcm/worktrees/<task>/.ai/handoffs
|
|
588
|
+
.ai/vcm/worktrees/<task>/.ai/vcm/handoffs/
|
|
588
589
|
```
|
|
589
590
|
|
|
590
|
-
For tasks created without a worktree, the task runtime repo is the connected base repo, so the runtime state resolves under the base repo's `.ai/vcm/`.
|
|
591
|
+
For tasks created without a worktree, the task runtime repo is the connected base repo, so the runtime state resolves under the base repo's `.ai/vcm/`. Because `.ai/vcm/handoffs/` has no task-name segment, VCM allows only one active inline task in a connected repo.
|
|
591
592
|
|
|
592
593
|
External Claude transcripts:
|
|
593
594
|
|
|
@@ -28,7 +28,7 @@ browser
|
|
|
28
28
|
-> claude --agent <role>
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
The app is local-first. It writes project control state under `.ai/vcm/`, handoff artifacts under `.ai/handoffs/` inside the active task worktree, app settings under `~/.vcm/settings.json`, and reads Claude transcript files under `~/.claude/projects/`.
|
|
31
|
+
The app is local-first. It writes project control state under `.ai/vcm/`, handoff artifacts under `.ai/vcm/handoffs/` inside the active task worktree, app settings under `~/.vcm/settings.json`, and reads Claude transcript files under `~/.claude/projects/`.
|
|
32
32
|
|
|
33
33
|
## 2. Processes And Ports
|
|
34
34
|
|
|
@@ -295,11 +295,13 @@ Task runtime state, source changes, and handoff artifacts live in the task runti
|
|
|
295
295
|
<baseRepoRoot>/.ai/vcm/worktrees/<task>/.ai/vcm/messages/<task>.jsonl
|
|
296
296
|
<baseRepoRoot>/.ai/vcm/worktrees/<task>/.ai/vcm/orchestration/<task>.json
|
|
297
297
|
<baseRepoRoot>/.ai/vcm/worktrees/<task>/.ai/vcm/translation/<task>/
|
|
298
|
-
<baseRepoRoot>/.ai/vcm/worktrees/<task>/.ai/handoffs
|
|
298
|
+
<baseRepoRoot>/.ai/vcm/worktrees/<task>/.ai/vcm/handoffs/
|
|
299
299
|
```
|
|
300
300
|
|
|
301
301
|
For inline tasks, `taskRepoRoot` is the connected base repo, so these same runtime paths resolve under the connected repo's `.ai/vcm/`.
|
|
302
302
|
|
|
303
|
+
Because the handoff directory is `<taskRepoRoot>/.ai/vcm/handoffs/` without a task slug segment, VCM rejects creating a second active inline task in the same connected repository. Parallel tasks should use the default worktree mode.
|
|
304
|
+
|
|
303
305
|
This split lets VCM list tasks from the base repo after worktrees are created, while each task's runtime state follows the same root as the role sessions.
|
|
304
306
|
|
|
305
307
|
### 6.2 Git Ignore Requirement
|
|
@@ -327,9 +329,10 @@ POST /api/tasks
|
|
|
327
329
|
-> assert worktreePath does not already exist
|
|
328
330
|
-> assert base repo has no uncommitted changes
|
|
329
331
|
-> git worktree add -b feature/<taskSlug> <worktreePath> <baseRef>
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
332
|
+
-> otherwise:
|
|
333
|
+
-> read current base repo branch
|
|
334
|
+
-> leave worktreePath undefined
|
|
335
|
+
-> reject when another inline task is already active
|
|
333
336
|
-> create handoff structure in taskRepoRoot
|
|
334
337
|
-> write central task metadata under baseRepoRoot/.ai/vcm/tasks/<task>.json
|
|
335
338
|
```
|
|
@@ -349,6 +352,7 @@ POST /api/tasks/:taskSlug/cleanup
|
|
|
349
352
|
-> when worktreePath exists, delete the task branch by default
|
|
350
353
|
-> delete base task metadata
|
|
351
354
|
-> delete task runtime session/message/orchestration/translation metadata
|
|
355
|
+
-> delete task runtime handoff directory
|
|
352
356
|
```
|
|
353
357
|
|
|
354
358
|
Close Task is intentionally destructive after user confirmation. It actively stops VCM-managed running role sessions, but it does not preflight running sessions or uncommitted worktree changes. Tasks created without a worktree remove VCM metadata only because there is no VCM-owned branch/worktree to delete.
|
|
@@ -396,7 +400,7 @@ Task cleanup is orchestrated by `src/backend/api/task-routes.ts` because it coor
|
|
|
396
400
|
Handoff directory:
|
|
397
401
|
|
|
398
402
|
```text
|
|
399
|
-
<taskRepoRoot>/.ai/handoffs
|
|
403
|
+
<taskRepoRoot>/.ai/vcm/handoffs/
|
|
400
404
|
role-commands/
|
|
401
405
|
architect.md
|
|
402
406
|
coder.md
|
|
@@ -528,7 +532,7 @@ The runtime:
|
|
|
528
532
|
- spawns `node-pty`
|
|
529
533
|
- sets `TERM=xterm-256color`
|
|
530
534
|
- sets color-friendly env vars
|
|
531
|
-
- appends raw PTY output to `<taskRepoRoot>/.ai/handoffs
|
|
535
|
+
- appends raw PTY output to `<taskRepoRoot>/.ai/vcm/handoffs/logs/<role>.log`
|
|
532
536
|
- emits terminal output/input/exit events to WebSocket subscribers
|
|
533
537
|
- replays the log on terminal WebSocket subscribe
|
|
534
538
|
|
|
@@ -562,7 +566,7 @@ State:
|
|
|
562
566
|
```text
|
|
563
567
|
<taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
|
|
564
568
|
<taskRepoRoot>/.ai/vcm/orchestration/<task>.json
|
|
565
|
-
<taskRepoRoot>/.ai/handoffs
|
|
569
|
+
<taskRepoRoot>/.ai/vcm/handoffs/messages/<message-id>.md
|
|
566
570
|
```
|
|
567
571
|
|
|
568
572
|
Policy:
|
|
@@ -928,7 +932,7 @@ Current boundaries:
|
|
|
928
932
|
- Translation API key is local in `~/.vcm/settings.json`.
|
|
929
933
|
- Translation output is UI/runtime state only unless a user or role copies it into a file.
|
|
930
934
|
- `.ai/vcm` is local project control state and must be ignored by Git.
|
|
931
|
-
- Task handoff artifacts live
|
|
935
|
+
- Task handoff artifacts live under `.ai/vcm/handoffs/` as task-local runtime state and are removed by Close Task. Durable conclusions belong in normal project docs, code comments, commit messages, or PR text.
|
|
932
936
|
- Task worktrees are created only during task creation; VCM does not expose branch/worktree switching APIs.
|
|
933
937
|
- Sandbox isolation should come from a devContainer, Docker container, VM, or other user-controlled environment.
|
|
934
938
|
|
|
@@ -17,7 +17,7 @@ V1 is implemented as a local GUI app with:
|
|
|
17
17
|
- API-driven message bus.
|
|
18
18
|
- Translation panel based on Claude transcript JSONL tailing.
|
|
19
19
|
- npm packaging with built `dist` and `dist-frontend` output.
|
|
20
|
-
- Task creation creates one `feature/<task>` branch and one `.ai/vcm/worktrees/<task>` git worktree by default; users may clear `Create worktree and branch` to create an inline task in the connected repository/current branch.
|
|
20
|
+
- Task creation creates one `feature/<task>` branch and one `.ai/vcm/worktrees/<task>` git worktree by default; users may clear `Create worktree and branch` to create an inline task in the connected repository/current branch. Because handoffs are scoped as `.ai/vcm/handoffs/` under the task runtime repo, only one active inline task is allowed per connected repository.
|
|
21
21
|
|
|
22
22
|
## 2. Package And Build
|
|
23
23
|
|
|
@@ -210,7 +210,7 @@ Worktree fields:
|
|
|
210
210
|
- `cleanupStatus?: "active" | "cleaned"`
|
|
211
211
|
- `cleanedAt?: string`
|
|
212
212
|
|
|
213
|
-
`CreateTaskRequest` supports `createWorktree?: boolean`. It creates a worktree and branch by default, and skips both when `createWorktree === false`.
|
|
213
|
+
`CreateTaskRequest` supports `createWorktree?: boolean`. It creates a worktree and branch by default, and skips both when `createWorktree === false`. Inline creation rejects a second active inline task in the same connected repository.
|
|
214
214
|
|
|
215
215
|
### `src/shared/types/session.ts`
|
|
216
216
|
|
|
@@ -546,10 +546,11 @@ createTask(baseRepoRoot, { taskSlug })
|
|
|
546
546
|
-> assert worktree path does not exist
|
|
547
547
|
-> git.createWorktree({ baseRepoRoot, branch, worktreePath, baseRef: HEAD })
|
|
548
548
|
-> taskRepoRoot = worktreePath
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
549
|
+
-> otherwise:
|
|
550
|
+
-> branch = current base repo branch
|
|
551
|
+
-> worktreePath = undefined
|
|
552
|
+
-> taskRepoRoot = baseRepoRoot
|
|
553
|
+
-> reject if another inline task is already active
|
|
553
554
|
-> artifactService.ensureHandoffStructure({ repoRoot: taskRepoRoot, handoffDir })
|
|
554
555
|
-> artifactService.createArtifactTemplates({ repoRoot: taskRepoRoot, handoffDir })
|
|
555
556
|
-> ensure task runtime state dirs under <taskRepoRoot>/.ai/vcm/
|
|
@@ -567,7 +568,8 @@ cleanupTask(baseRepoRoot, taskSlug, options)
|
|
|
567
568
|
-> if worktreePath exists, verify it is under <baseRepoRoot>/.ai/vcm/worktrees/
|
|
568
569
|
-> if worktreePath exists, git.removeWorktree(baseRepoRoot, worktreePath, force=true)
|
|
569
570
|
-> if worktreePath exists, git.deleteBranch(baseRepoRoot, task.branch, force=true) by default
|
|
570
|
-
|
|
571
|
+
-> delete <baseRepoRoot>/.ai/vcm/tasks/<task>.json
|
|
572
|
+
-> delete <taskRepoRoot>/.ai/vcm/handoffs/
|
|
571
573
|
-> delete <taskRepoRoot>/.ai/vcm/sessions/<task>.json
|
|
572
574
|
-> delete <taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
|
|
573
575
|
-> delete <taskRepoRoot>/.ai/vcm/orchestration/<task>.json
|
|
@@ -599,13 +601,13 @@ In task-worktree mode, artifact paths are still repo-relative, but `repoRoot` mu
|
|
|
599
601
|
Primary role command path:
|
|
600
602
|
|
|
601
603
|
```text
|
|
602
|
-
.ai/handoffs
|
|
604
|
+
.ai/vcm/handoffs/role-commands/<role>.md
|
|
603
605
|
```
|
|
604
606
|
|
|
605
607
|
Legacy fallback:
|
|
606
608
|
|
|
607
609
|
```text
|
|
608
|
-
.ai/handoffs
|
|
610
|
+
.ai/vcm/handoffs/role-commands/<role>-command.md
|
|
609
611
|
```
|
|
610
612
|
|
|
611
613
|
### `src/backend/services/status-service.ts`
|
|
@@ -682,7 +684,7 @@ In task-worktree mode:
|
|
|
682
684
|
|
|
683
685
|
- message snapshots live under `task.worktreePath/.ai/vcm/messages`
|
|
684
686
|
- orchestration state lives under `task.worktreePath/.ai/vcm/orchestration`
|
|
685
|
-
- message body files live under `task.worktreePath/.ai/handoffs
|
|
687
|
+
- message body files live under `task.worktreePath/.ai/vcm/handoffs/messages`
|
|
686
688
|
- terminal delivery uses the runtime session for the role, whose cwd is the task worktree
|
|
687
689
|
|
|
688
690
|
### `src/backend/services/command-dispatcher.ts`
|
|
@@ -1196,7 +1198,7 @@ Messages:
|
|
|
1196
1198
|
|
|
1197
1199
|
```text
|
|
1198
1200
|
<taskRepoRoot>/.ai/vcm/messages/<task>.jsonl
|
|
1199
|
-
<taskRepoRoot>/.ai/handoffs
|
|
1201
|
+
<taskRepoRoot>/.ai/vcm/handoffs/messages/<message-id>.md
|
|
1200
1202
|
```
|
|
1201
1203
|
|
|
1202
1204
|
Orchestration:
|
|
@@ -1220,7 +1222,7 @@ Task worktrees:
|
|
|
1220
1222
|
Handoff artifacts:
|
|
1221
1223
|
|
|
1222
1224
|
```text
|
|
1223
|
-
.ai/handoffs
|
|
1225
|
+
.ai/vcm/handoffs/
|
|
1224
1226
|
```
|
|
1225
1227
|
|
|
1226
1228
|
Claude transcripts:
|