@goodtek/vibeops 0.4.0 → 1.0.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/CHANGELOG.md +198 -1
- package/README.md +62 -402
- package/dist/bootstrap/installer.js +4 -16
- package/dist/cli.js +52 -244
- package/dist/commands/init.js +3 -3
- package/dist/commands/status.js +145 -8
- package/dist/commands/task-add.js +100 -0
- package/dist/commands/task-done.js +117 -74
- package/dist/lib/config.js +2 -118
- package/dist/lib/git.js +190 -8
- package/dist/lib/llm-complete.js +62 -0
- package/dist/lib/paths.js +7 -3
- package/dist/lib/plan-llm-openai.js +0 -63
- package/dist/lib/resolve-task.js +34 -0
- package/dist/lib/slug.js +11 -0
- package/dist/lib/task-add-llm.js +81 -0
- package/dist/lib/task-context.js +68 -0
- package/dist/lib/task-done-llm.js +148 -0
- package/dist/lib/task-merge.js +115 -0
- package/dist/lib/task-scaffold.js +70 -92
- package/dist/lib/task-start.js +72 -0
- package/dist/lib/task-summary.js +12 -239
- package/dist/lib/task.js +80 -37
- package/dist/types/config.js +0 -16
- package/package.json +3 -4
- package/templates/.cursor/rules/01-task-source-of-truth.mdc +12 -0
- package/templates/.cursor/rules/02-git-safety.mdc +11 -0
- package/templates/.cursor/rules/03-docs-on-done.mdc +13 -0
- package/templates/.cursor/skills/implement-task/SKILL.md +22 -0
- package/templates/.cursor/skills/plan-task/SKILL.md +19 -0
- package/templates/AGENTS.md +26 -87
- package/templates/docs/logs/README.md +4 -35
- package/templates/docs/project/03-architecture.md +10 -29
- package/templates/docs/project/05-current-state.md +7 -27
- package/templates/docs/project/06-decisions.md +6 -17
- package/templates/docs/tasks/TASK-000-template.md +9 -44
- package/dist/agent/loader.js +0 -71
- package/dist/agent/prompt.js +0 -66
- package/dist/commands/agent-list.js +0 -32
- package/dist/commands/agent-prompt.js +0 -59
- package/dist/commands/agent-show.js +0 -26
- package/dist/commands/github-init.js +0 -554
- package/dist/commands/github-status.js +0 -164
- package/dist/commands/notion-init.js +0 -764
- package/dist/commands/notion-sync.js +0 -405
- package/dist/commands/notion-test.js +0 -595
- package/dist/commands/plan.js +0 -343
- package/dist/commands/task-check.js +0 -155
- package/dist/commands/task-generate.js +0 -206
- package/dist/commands/task-pull.js +0 -277
- package/dist/commands/task-rollback.js +0 -174
- package/dist/commands/task-start.js +0 -102
- package/dist/lib/brief.js +0 -356
- package/dist/lib/github-cli.js +0 -247
- package/dist/lib/notion-client.js +0 -459
- package/dist/lib/notion-discovery.js +0 -671
- package/dist/lib/notion-env.js +0 -140
- package/dist/lib/notion-mappers.js +0 -148
- package/dist/lib/notion-schema.js +0 -272
- package/dist/lib/notion-sync.js +0 -337
- package/dist/lib/notion-target.js +0 -247
- package/dist/lib/package-json.js +0 -133
- package/dist/lib/plan-apply-planner.js +0 -131
- package/dist/lib/plan-codex-pkce.js +0 -234
- package/dist/lib/plan-llm-models.js +0 -237
- package/dist/lib/plan-llm-normalize.js +0 -146
- package/dist/lib/plan-llm-session.js +0 -682
- package/dist/lib/plan-post-apply-setup.js +0 -116
- package/dist/lib/project-docs.js +0 -95
- package/dist/lib/prompt-builder.js +0 -135
- package/dist/lib/task-generator.js +0 -183
- package/dist/lib/task-prompt.js +0 -23
- package/dist/lib/task-pull.js +0 -354
- package/dist/status/collector.js +0 -103
- package/dist/status/format.js +0 -177
- package/dist/types/brief.js +0 -126
- package/templates/.cursor/rules/00-project-governance.mdc +0 -28
- package/templates/.cursor/rules/01-agent-orchestration.mdc +0 -48
- package/templates/.cursor/rules/02-task-workflow.mdc +0 -38
- package/templates/.cursor/rules/03-git-safety.mdc +0 -30
- package/templates/.cursor/rules/04-docs-update.mdc +0 -22
- package/templates/.vibeops/agents/architect.md +0 -47
- package/templates/.vibeops/agents/builder.md +0 -38
- package/templates/.vibeops/agents/docs.md +0 -54
- package/templates/.vibeops/agents/orchestrator.md +0 -40
- package/templates/.vibeops/agents/planner.md +0 -60
- package/templates/.vibeops/agents/recovery.md +0 -49
- package/templates/.vibeops/agents/reviewer.md +0 -47
- package/templates/.vibeops/agents/tester.md +0 -43
- package/templates/.vibeops/prompts/create-plan.md +0 -33
- package/templates/.vibeops/prompts/generate-tasks.md +0 -41
- package/templates/.vibeops/prompts/implement-task.md +0 -39
- package/templates/.vibeops/prompts/review-task.md +0 -34
- package/templates/.vibeops/prompts/rollback.md +0 -32
- package/templates/.vibeops/prompts/start-project.md +0 -39
- package/templates/.vibeops/workflows/notion-sync.md +0 -53
- package/templates/.vibeops/workflows/project-start.md +0 -73
- package/templates/.vibeops/workflows/rollback.md +0 -45
- package/templates/.vibeops/workflows/task-lifecycle.md +0 -71
- package/templates/docs/project/00-overview.md +0 -27
- package/templates/docs/project/01-requirements.md +0 -30
- package/templates/docs/project/02-mvp-scope.md +0 -36
- package/templates/docs/project/04-tech-stack.md +0 -29
- package/templates/docs/project/07-backlog.md +0 -23
- package/templates/docs/project/08-env.md +0 -29
- package/templates/docs/project/09-deployment.md +0 -28
package/dist/lib/task.js
CHANGED
|
@@ -2,6 +2,7 @@ import { readdir } from "node:fs/promises";
|
|
|
2
2
|
import { basename, extname, join } from "node:path";
|
|
3
3
|
import matter from "gray-matter";
|
|
4
4
|
import { isDirectory, readText, writeText } from "./filesystem.js";
|
|
5
|
+
import { readGitInfo } from "./git.js";
|
|
5
6
|
const KNOWN_STATUSES = new Set([
|
|
6
7
|
"planned",
|
|
7
8
|
"in_progress",
|
|
@@ -32,7 +33,8 @@ export function statusDisplay(status) {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
function extractIdFromFilename(file) {
|
|
35
|
-
const
|
|
36
|
+
const name = basename(file);
|
|
37
|
+
const m = /^(TASK-\d+)/i.exec(name);
|
|
36
38
|
return m ? m[1].toUpperCase() : basename(file, ".md");
|
|
37
39
|
}
|
|
38
40
|
function extractTitleFromBody(body) {
|
|
@@ -125,55 +127,71 @@ export function countTasks(tasks) {
|
|
|
125
127
|
counts[t.status]++;
|
|
126
128
|
return counts;
|
|
127
129
|
}
|
|
130
|
+
export function pickInProgressTask(tasks) {
|
|
131
|
+
return tasks.find((t) => t.status === "in_progress") ?? null;
|
|
132
|
+
}
|
|
128
133
|
export function pickNextTask(tasks) {
|
|
129
|
-
const inProgress = tasks
|
|
134
|
+
const inProgress = pickInProgressTask(tasks);
|
|
130
135
|
if (inProgress)
|
|
131
136
|
return inProgress;
|
|
132
137
|
const review = tasks.find((t) => t.status === "review");
|
|
133
138
|
if (review)
|
|
134
139
|
return review;
|
|
135
|
-
const planned = tasks.
|
|
136
|
-
return planned ?? null;
|
|
140
|
+
const planned = tasks.filter((t) => t.status === "planned");
|
|
141
|
+
return planned[0] ?? null;
|
|
142
|
+
}
|
|
143
|
+
const TEMPLATE_TASK_ID = "TASK-000";
|
|
144
|
+
export function filterActionableTasks(tasks) {
|
|
145
|
+
return tasks.filter((t) => t.id.toUpperCase() !== TEMPLATE_TASK_ID);
|
|
146
|
+
}
|
|
147
|
+
function taskSortKey(id) {
|
|
148
|
+
const m = /^TASK-(\d+)$/i.exec(id.trim());
|
|
149
|
+
return m ? Number.parseInt(m[1], 10) : 0;
|
|
150
|
+
}
|
|
151
|
+
/** Latest finished TASK by numeric id (TASK-mvp sorts after numbered tasks). */
|
|
152
|
+
export function pickLatestDoneTask(tasks) {
|
|
153
|
+
const done = filterActionableTasks(tasks).filter((t) => t.status === "done");
|
|
154
|
+
if (done.length === 0)
|
|
155
|
+
return null;
|
|
156
|
+
return [...done].sort((a, b) => taskSortKey(b.id) - taskSortKey(a.id))[0];
|
|
157
|
+
}
|
|
158
|
+
export async function loadActionableTasks(tasksDir) {
|
|
159
|
+
return filterActionableTasks(await scanTasks(tasksDir));
|
|
160
|
+
}
|
|
161
|
+
/** True when HEAD is on the TASK's recorded task branch. */
|
|
162
|
+
export function isOnTaskBranch(gitBranch, ctx) {
|
|
163
|
+
return (typeof gitBranch === "string" &&
|
|
164
|
+
ctx !== null &&
|
|
165
|
+
gitBranch === ctx.taskBranch);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Prefer the TASK for the current `task/*` branch so `next` does not jump to the
|
|
169
|
+
* next Planned TASK while merge / `vibeops done` is still pending.
|
|
170
|
+
*/
|
|
171
|
+
export async function pickActiveTask(tasksDir, cwd) {
|
|
172
|
+
const actionable = await loadActionableTasks(tasksDir);
|
|
173
|
+
const git = await readGitInfo(cwd);
|
|
174
|
+
if (git.isRepo && typeof git.branch === "string" && git.branch.startsWith("task/")) {
|
|
175
|
+
for (const t of actionable) {
|
|
176
|
+
const ctx = await readGitContext(t.filePath);
|
|
177
|
+
if (isOnTaskBranch(git.branch, ctx))
|
|
178
|
+
return t;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return pickNextTask(actionable);
|
|
137
182
|
}
|
|
138
183
|
export async function findTaskFile(tasksDir, taskId) {
|
|
139
184
|
const all = await scanTasks(tasksDir);
|
|
140
|
-
const target = taskId
|
|
185
|
+
const target = normalizeTaskRef(taskId);
|
|
141
186
|
for (const t of all) {
|
|
142
187
|
if (t.id.toUpperCase() === target)
|
|
143
188
|
return t.filePath;
|
|
144
189
|
}
|
|
145
190
|
return null;
|
|
146
191
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
* scaffolding file is included — callers can subtract its `0` if they want to
|
|
151
|
-
* skip the placeholder).
|
|
152
|
-
*
|
|
153
|
-
* Returns 0 if no TASK files exist or the directory is missing.
|
|
154
|
-
*/
|
|
155
|
-
export async function highestTaskNumber(tasksDir) {
|
|
156
|
-
if (!(await isDirectory(tasksDir)))
|
|
157
|
-
return 0;
|
|
158
|
-
const entries = await readdir(tasksDir, { withFileTypes: true });
|
|
159
|
-
let max = 0;
|
|
160
|
-
for (const e of entries) {
|
|
161
|
-
if (!e.isFile() || !e.name.endsWith(".md"))
|
|
162
|
-
continue;
|
|
163
|
-
const m = /^TASK-(\d+)/i.exec(e.name);
|
|
164
|
-
if (!m)
|
|
165
|
-
continue;
|
|
166
|
-
const n = Number.parseInt(m[1], 10);
|
|
167
|
-
if (Number.isFinite(n) && n > max)
|
|
168
|
-
max = n;
|
|
169
|
-
}
|
|
170
|
-
return max;
|
|
171
|
-
}
|
|
172
|
-
export async function nextTaskNumber(tasksDir) {
|
|
173
|
-
return (await highestTaskNumber(tasksDir)) + 1;
|
|
174
|
-
}
|
|
175
|
-
export function formatTaskId(n, width = 3) {
|
|
176
|
-
return `TASK-${String(n).padStart(width, "0")}`;
|
|
192
|
+
function normalizeTaskRef(ref) {
|
|
193
|
+
const t = ref.trim().toUpperCase();
|
|
194
|
+
return t.startsWith("TASK-") ? t : `TASK-${t}`;
|
|
177
195
|
}
|
|
178
196
|
const TASK_FILENAME_RE = /^TASK-(\d+)(?:-(.+))?$/i;
|
|
179
197
|
export function parseTaskFilename(filePath) {
|
|
@@ -235,6 +253,18 @@ export function isPlaceholderContent(content) {
|
|
|
235
253
|
return true; // legacy Korean placeholder
|
|
236
254
|
if (/^_*\(none\)_*$/i.test(trimmed))
|
|
237
255
|
return true;
|
|
256
|
+
if (/^\(not yet\)$/i.test(trimmed))
|
|
257
|
+
return true;
|
|
258
|
+
if (/^\(scaffold/i.test(trimmed))
|
|
259
|
+
return true;
|
|
260
|
+
if (/^pending\.?$/i.test(trimmed))
|
|
261
|
+
return true;
|
|
262
|
+
if (/^tbd\.?$/i.test(trimmed))
|
|
263
|
+
return true;
|
|
264
|
+
if (/^todo\.?$/i.test(trimmed))
|
|
265
|
+
return true;
|
|
266
|
+
if (/^-{1,3}$/.test(trimmed))
|
|
267
|
+
return true;
|
|
238
268
|
return false;
|
|
239
269
|
}
|
|
240
270
|
export function hasNonEmptySection(body, title) {
|
|
@@ -306,6 +336,13 @@ export async function updateInlineStatus(filePath, next) {
|
|
|
306
336
|
await writeText(filePath, updated);
|
|
307
337
|
}
|
|
308
338
|
}
|
|
339
|
+
export async function updateTaskSection(filePath, title, content) {
|
|
340
|
+
const raw = await readText(filePath);
|
|
341
|
+
const updated = replaceSectionContent(raw, title, content);
|
|
342
|
+
if (updated !== raw) {
|
|
343
|
+
await writeText(filePath, updated);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
309
346
|
function renderGitContextBlock(ctx) {
|
|
310
347
|
const lines = [
|
|
311
348
|
`- Base Branch: \`${ctx.baseBranch}\``,
|
|
@@ -325,8 +362,8 @@ export async function upsertGitContext(filePath, ctx) {
|
|
|
325
362
|
if (locateSection(raw, "Git Context")) {
|
|
326
363
|
updated = replaceSectionContent(raw, "Git Context", block);
|
|
327
364
|
}
|
|
328
|
-
else if (locateSection(raw, "
|
|
329
|
-
updated = insertSectionAfter(raw, "
|
|
365
|
+
else if (locateSection(raw, "Test Plan")) {
|
|
366
|
+
updated = insertSectionAfter(raw, "Test Plan", "Git Context", block);
|
|
330
367
|
}
|
|
331
368
|
else if (locateSection(raw, "Status")) {
|
|
332
369
|
updated = insertSectionAfter(raw, "Status", "Git Context", block);
|
|
@@ -345,6 +382,12 @@ const GIT_CTX_RE = {
|
|
|
345
382
|
startedAt: /^-\s+Started At:\s*`([^`]+)`/m,
|
|
346
383
|
doneAt: /^-\s+Done At:\s*`([^`]+)`/m,
|
|
347
384
|
};
|
|
385
|
+
export async function markGitContextDone(filePath) {
|
|
386
|
+
const ctx = await readGitContext(filePath);
|
|
387
|
+
if (ctx === null)
|
|
388
|
+
return;
|
|
389
|
+
await upsertGitContext(filePath, { ...ctx, doneAt: new Date().toISOString() });
|
|
390
|
+
}
|
|
348
391
|
export async function readGitContext(filePath) {
|
|
349
392
|
const raw = await readText(filePath);
|
|
350
393
|
const content = readSection(raw, "Git Context");
|
package/dist/types/config.js
CHANGED
|
@@ -1,17 +1 @@
|
|
|
1
1
|
export const VIBEOPS_CONFIG_SCHEMA_VERSION = 1;
|
|
2
|
-
export const DEFAULT_NOTION_CONFIG = {
|
|
3
|
-
enabled: false,
|
|
4
|
-
projectsTargetId: "",
|
|
5
|
-
tasksTargetId: "",
|
|
6
|
-
projectsDatabaseId: "",
|
|
7
|
-
tasksDatabaseId: "",
|
|
8
|
-
};
|
|
9
|
-
export const DEFAULT_GITHUB_CONFIG = {
|
|
10
|
-
enabled: false,
|
|
11
|
-
mode: "gh-cli",
|
|
12
|
-
owner: "",
|
|
13
|
-
repo: "",
|
|
14
|
-
remote: "origin",
|
|
15
|
-
visibility: "",
|
|
16
|
-
url: "",
|
|
17
|
-
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodtek/vibeops",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Minimal CLI rails for Cursor-based TASK-driven vibe coding.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "VibeOps contributors",
|
|
7
7
|
"license": "MIT",
|
|
@@ -35,13 +35,11 @@
|
|
|
35
35
|
"coding",
|
|
36
36
|
"cli",
|
|
37
37
|
"task",
|
|
38
|
-
"notion",
|
|
39
38
|
"vibeops",
|
|
40
39
|
"workflow"
|
|
41
40
|
],
|
|
42
41
|
"dependencies": {
|
|
43
42
|
"@inquirer/prompts": "^8.4.3",
|
|
44
|
-
"@notionhq/client": "^5.20.0",
|
|
45
43
|
"commander": "^12.1.0",
|
|
46
44
|
"gray-matter": "^4.0.3"
|
|
47
45
|
},
|
|
@@ -56,6 +54,7 @@
|
|
|
56
54
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
57
55
|
"start": "node dist/cli.js",
|
|
58
56
|
"smoke": "pnpm typecheck && pnpm build && node scripts/smoke.mjs",
|
|
57
|
+
"clean": "rm -rf dist",
|
|
59
58
|
"publish:dry": "pnpm publish --dry-run --no-git-checks"
|
|
60
59
|
}
|
|
61
60
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: TASK markdown is the execution source of truth; one TASK at a time
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TASK-driven work
|
|
7
|
+
|
|
8
|
+
- Implement **one TASK** only (`docs/tasks/TASK-NNN-*.md`).
|
|
9
|
+
- Read the **entire** current TASK file before changing code or docs.
|
|
10
|
+
- Work only inside **Scope** and **Acceptance Criteria**.
|
|
11
|
+
- Do not start another TASK id unless the human asks.
|
|
12
|
+
- If chat and TASK docs disagree, **fix the docs first**, then implement.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Git safety for task branches and commits
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Git safety
|
|
7
|
+
|
|
8
|
+
- Use branch pattern `task/*` created by `vibeops task add`.
|
|
9
|
+
- Include the TASK id in commit messages, e.g. `feat(task-015): short title`.
|
|
10
|
+
- **No force-push** to shared branches (`main`, `master`).
|
|
11
|
+
- Do not merge or push unless the human runs `vibeops task done` or asks explicitly.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Update TASK Result and project memory when finishing work
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Docs when finishing a TASK
|
|
7
|
+
|
|
8
|
+
Before `vibeops task done`:
|
|
9
|
+
|
|
10
|
+
1. Fill **Result** and **Test Result** in the TASK file (paths, commands, outcomes — facts only).
|
|
11
|
+
2. If architecture or decisions changed, note them in the TASK; `task done` updates `docs/project/*`.
|
|
12
|
+
|
|
13
|
+
Do not mark a TASK complete with placeholder `(not yet)` sections.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: implement-task
|
|
3
|
+
description: Implements the current VibeOps TASK per Scope and Acceptance Criteria. Use when building features for docs/tasks/TASK-NNN.md.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Implement a TASK
|
|
8
|
+
|
|
9
|
+
## Read first
|
|
10
|
+
|
|
11
|
+
1. `AGENTS.md` and `.cursor/rules/`
|
|
12
|
+
2. `docs/project/05-current-state.md`, `03-architecture.md`, `06-decisions.md`
|
|
13
|
+
3. The TASK file referenced by the human
|
|
14
|
+
|
|
15
|
+
## Instructions
|
|
16
|
+
|
|
17
|
+
1. Work **only** within Scope and Acceptance Criteria.
|
|
18
|
+
2. Search the repo before adding files; match existing patterns.
|
|
19
|
+
3. Fill **Result** and **Test Result** with facts when done.
|
|
20
|
+
4. Do not run `vibeops task done` or merge — the human closes the TASK.
|
|
21
|
+
|
|
22
|
+
Tell the human to run `vibeops task done TASK-NNN` when ready.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plan-task
|
|
3
|
+
description: Refines a VibeOps TASK file (Goal, Scope, AC, Test Plan) via dialogue. Use when planning or editing docs/tasks/TASK-NNN.md before implementation.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Plan a TASK
|
|
8
|
+
|
|
9
|
+
The human opened a TASK file (e.g. `@docs/tasks/TASK-015-….md`).
|
|
10
|
+
|
|
11
|
+
## Instructions
|
|
12
|
+
|
|
13
|
+
1. Read the TASK file and `docs/project/05-current-state.md`.
|
|
14
|
+
2. Ask only what is missing to make **Scope**, **Acceptance Criteria**, and **Test Plan** verifiable.
|
|
15
|
+
3. Edit the TASK file in place — do not create a second TASK id.
|
|
16
|
+
4. Keep **Out of Scope** explicit.
|
|
17
|
+
5. Do not write application code in this step unless the human asks.
|
|
18
|
+
|
|
19
|
+
When planning is enough, tell the human to switch to Agent mode and implement per the TASK.
|
package/templates/AGENTS.md
CHANGED
|
@@ -1,98 +1,37 @@
|
|
|
1
|
-
# {{PROJECT_NAME}} — AI agent
|
|
1
|
+
# {{PROJECT_NAME}} — AI agent guide
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
This project runs **Cursor-based vibe coding** on rails. The execution input is **`docs/tasks/TASK-*.md`**, not chat history.
|
|
8
|
-
|
|
9
|
-
## Required reading before you code
|
|
10
|
-
|
|
11
|
-
Read the docs below **before you start implementing**. Order top to bottom.
|
|
12
|
-
|
|
13
|
-
| Document | Why |
|
|
14
|
-
| ------------------------------------------ | --------------------------------------------------------- |
|
|
15
|
-
| `docs/project/05-current-state.md` | Where the project is today and what comes next |
|
|
16
|
-
| `docs/project/00-overview.md` | Vision, terminology, MVP boundaries |
|
|
17
|
-
| `docs/project/02-mvp-scope.md` | What is in / out of MVP |
|
|
18
|
-
| `docs/project/03-architecture.md` | System, folders, data flow |
|
|
19
|
-
| `docs/project/04-tech-stack.md` | Tools used to build the project |
|
|
20
|
-
| `docs/project/06-decisions.md` | Decisions already made (avoid conflicts) |
|
|
21
|
-
| `docs/project/07-backlog.md` | TASK order and definition of done |
|
|
22
|
-
| **Current TASK file** `docs/tasks/TASK-NNN-*` | Scope and Acceptance Criteria for the current TASK |
|
|
23
|
-
|
|
24
|
-
`docs/project/01-requirements.md`, `08-env.md`, `09-deployment.md` are referenced as needed. **Always read the entire current TASK file.**
|
|
3
|
+
> Installed by **VibeOps**. Cursor reads this repo, not chat history.
|
|
25
4
|
|
|
26
5
|
## Source of truth
|
|
27
6
|
|
|
28
|
-
| What
|
|
29
|
-
|
|
30
|
-
|
|
|
31
|
-
| Project
|
|
32
|
-
| Change history
|
|
33
|
-
|
|
|
34
|
-
| **Not** a source of truth | Chat (Cursor history, Slack) |
|
|
35
|
-
|
|
36
|
-
## TASK-driven development rules
|
|
37
|
-
|
|
38
|
-
1. Implement **one TASK at a time**.
|
|
39
|
-
2. Stay inside the TASK's **Scope / Acceptance Criteria**.
|
|
40
|
-
3. Before adding new code, **search** for existing implementations or patterns and avoid duplication.
|
|
41
|
-
4. **Every mutating command** should support **`--dry-run`** (or an equivalent) so the plan can be previewed without side effects.
|
|
42
|
-
5. **Large refactors** happen only when a dedicated TASK calls for them.
|
|
43
|
-
6. **Notion / Git integrations** are only added when an explicit TASK assigns that responsibility.
|
|
44
|
-
7. When the work is finished, update docs per [Completion report](#completion-report) and `.cursor/rules/04-docs-update.mdc`.
|
|
45
|
-
|
|
46
|
-
Details live in `.cursor/rules/`.
|
|
47
|
-
|
|
48
|
-
## Agent roles
|
|
49
|
-
|
|
50
|
-
`.vibeops/agents/*.md` defines 8 agents for this project.
|
|
51
|
-
|
|
52
|
-
- `orchestrator` — picks the next TASK and delegates to other agents.
|
|
53
|
-
- `planner` — expands an idea into `docs/project/{00,01,02,07}`.
|
|
54
|
-
- `architect` — fills in `docs/project/{03,04}` (architecture, tech stack).
|
|
55
|
-
- `builder` — takes one TASK and edits code.
|
|
56
|
-
- `reviewer` — compares the diff against the Acceptance Criteria.
|
|
57
|
-
- `tester` — runs the Test Plan and fills in Test Result.
|
|
58
|
-
- `docs` — updates `05-current-state.md`, the TASK Result, and `docs/logs/`.
|
|
59
|
-
- `recovery` — diagnoses rollback options (destructive actions require `--confirm`).
|
|
60
|
-
|
|
61
|
-
## Forbidden
|
|
62
|
-
|
|
63
|
-
- Changing requirements or implementing things "loosely" based on chat alone.
|
|
64
|
-
- Editing code or config **without reading the current TASK file**.
|
|
65
|
-
- Mixing **multiple TASKs** in one session, or adding a large structure (e.g. `src/`) without a TASK.
|
|
66
|
-
- Features **outside the TASK Scope** or **outside the MVP**.
|
|
67
|
-
- Creating similar modules **without searching first**.
|
|
68
|
-
- Performing **large refactors** without a dedicated TASK.
|
|
69
|
-
- Adding **Notion / Git integration** that the TASK does not authorize.
|
|
70
|
-
- Calling the TASK done without updating **`05-current-state.md` / the TASK file / `docs/logs/YYYY-MM-DD.md`**.
|
|
71
|
-
|
|
72
|
-
## Cursor rule files
|
|
7
|
+
| What | Where |
|
|
8
|
+
|------|--------|
|
|
9
|
+
| Current work | `docs/tasks/TASK-NNN-*.md` |
|
|
10
|
+
| Project memory | `docs/project/05-current-state.md`, `03-architecture.md`, `06-decisions.md` |
|
|
11
|
+
| Change history | Git commits on task branches |
|
|
12
|
+
| **Not** trusted | Cursor chat, Slack |
|
|
73
13
|
|
|
74
|
-
|
|
75
|
-
| ----------------------------------------------------- | --------------------------------------------------------- |
|
|
76
|
-
| `.cursor/rules/00-project-governance.mdc` | Source of truth, one-TASK rule, MVP scope |
|
|
77
|
-
| `.cursor/rules/01-agent-orchestration.mdc` | Roles of the 8 agents and how they collaborate |
|
|
78
|
-
| `.cursor/rules/02-task-workflow.mdc` | How to start / run / finish a TASK, dry-run first |
|
|
79
|
-
| `.cursor/rules/03-git-safety.mdc` | Branch / rollback safety, no force-push |
|
|
80
|
-
| `.cursor/rules/04-docs-update.mdc` | Mandatory doc updates after implementation |
|
|
14
|
+
## Before you code
|
|
81
15
|
|
|
82
|
-
|
|
16
|
+
1. `docs/project/05-current-state.md`
|
|
17
|
+
2. `docs/project/03-architecture.md` and `06-decisions.md` when relevant
|
|
18
|
+
3. **The full current TASK file** under `docs/tasks/`
|
|
83
19
|
|
|
84
|
-
|
|
20
|
+
## Workflow (human + CLI)
|
|
85
21
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
22
|
+
```bash
|
|
23
|
+
vibeops init # once
|
|
24
|
+
vibeops task add # new TASK + branch
|
|
25
|
+
# Plan in Cursor Ask: @docs/tasks/TASK-NNN-….md
|
|
26
|
+
# Build in Cursor Agent: same file + Scope / Acceptance Criteria
|
|
27
|
+
vibeops task done # close TASK, update project docs, merge
|
|
28
|
+
vibeops status # briefing
|
|
29
|
+
```
|
|
91
30
|
|
|
92
|
-
|
|
31
|
+
## Rules
|
|
93
32
|
|
|
94
|
-
|
|
33
|
+
- **One TASK at a time** — stay inside Scope and Acceptance Criteria.
|
|
34
|
+
- **Search** before adding files; reuse existing patterns.
|
|
35
|
+
- When the TASK is finished, **Result** and **Test Result** must be filled before `vibeops task done`.
|
|
95
36
|
|
|
96
|
-
|
|
97
|
-
- Bootstrapped by: VibeOps `{{VIBEOPS_VERSION}}`
|
|
98
|
-
- Created at: `{{CREATED_AT}}`
|
|
37
|
+
Details: `.cursor/rules/`.
|
|
@@ -1,38 +1,7 @@
|
|
|
1
|
-
# Daily
|
|
1
|
+
# Daily logs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Append-only files: `docs/logs/YYYY-MM-DD.md`.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- Create the file on the day's first change. Additional changes the same day append entries to the same file.
|
|
7
|
-
- Logs are **fact-first**: decision summary, changed files, verification result, next work.
|
|
5
|
+
`vibeops task done` may append a short entry when a TASK closes.
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
## YYYY-MM-DD · TASK-NNN <short title>
|
|
13
|
-
|
|
14
|
-
### Decision summary
|
|
15
|
-
|
|
16
|
-
- ...
|
|
17
|
-
|
|
18
|
-
### Changed files
|
|
19
|
-
|
|
20
|
-
- new: ...
|
|
21
|
-
- update: ...
|
|
22
|
-
|
|
23
|
-
### Verification
|
|
24
|
-
|
|
25
|
-
| Command | Result |
|
|
26
|
-
| --- | --- |
|
|
27
|
-
| `...` | ... |
|
|
28
|
-
|
|
29
|
-
### Next work
|
|
30
|
-
|
|
31
|
-
- TASK-NNN — ...
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
## Non-goals
|
|
35
|
-
|
|
36
|
-
- Chitchat, opinions, self-praise.
|
|
37
|
-
- Copy-pasted TASK bodies.
|
|
38
|
-
- Secret values that should not be committed.
|
|
7
|
+
Keep entries factual: TASK id, paths touched, commands run.
|
|
@@ -1,34 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Architecture
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Living overview. Update when structure or major paths change (often via `vibeops task done`).
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## System
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Use an ASCII diagram to draw the "inside / outside the system" boundary.
|
|
9
|
-
Flows like user → frontend → backend → DB / external services.
|
|
10
|
-
-->
|
|
7
|
+
(describe stack and main folders as the project grows)
|
|
11
8
|
|
|
12
|
-
##
|
|
9
|
+
## Key paths
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## Data model
|
|
21
|
-
|
|
22
|
-
<!-- The 3 to 7 core entities and how they relate. Field-level detail belongs to a separate TASK. -->
|
|
23
|
-
|
|
24
|
-
## Data flow
|
|
25
|
-
|
|
26
|
-
<!-- The call sequence for the 1 to 2 most common user scenarios. -->
|
|
27
|
-
|
|
28
|
-
## External boundaries
|
|
29
|
-
|
|
30
|
-
<!-- Which external services / APIs we talk to. Auth method, public or private. -->
|
|
31
|
-
|
|
32
|
-
## Non-deterministic / failure paths
|
|
33
|
-
|
|
34
|
-
<!-- High-level behavior under network failures, concurrency, data loss. -->
|
|
11
|
+
| Area | Path |
|
|
12
|
+
|------|------|
|
|
13
|
+
| Application | (TBD) |
|
|
14
|
+
| TASK docs | `docs/tasks/` |
|
|
15
|
+
| Project memory | `docs/project/` |
|
|
@@ -1,35 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Current state
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Facts only. Updated by `vibeops task done` and humans.
|
|
4
4
|
|
|
5
5
|
## Stage
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- No code (`src/`, `package.json`, …) exists yet.
|
|
7
|
+
- Bootstrapped with VibeOps. No TASK started yet.
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## Active TASK
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
| ----------------- | ------------------------------------- | --------------------------- |
|
|
14
|
-
| Operating guide | `AGENTS.md`, `.cursor/rules/*` | Installed by VibeOps |
|
|
15
|
-
| Agent definitions | `.vibeops/agents/*` | 8 agents |
|
|
16
|
-
| Project docs | `docs/project/00 ~ 09` | Empty (waiting for plan) |
|
|
17
|
-
| TASK folder | `docs/tasks/` | Empty (waiting for generate) |
|
|
18
|
-
| Logs folder | `docs/logs/` | Empty |
|
|
11
|
+
(none)
|
|
19
12
|
|
|
20
|
-
##
|
|
13
|
+
## Next step
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
- `docs/tasks/TASK-001-*.md` (`task generate`).
|
|
24
|
-
- Any code at all.
|
|
25
|
-
- Notion connection (run `vibeops notion init` if desired).
|
|
26
|
-
|
|
27
|
-
## Next TASK
|
|
28
|
-
|
|
29
|
-
**The backlog is empty.** Run `vibeops plan --idea "<your idea>"` to fill in `docs/project/{00,01,02,07}`; the first TASK candidates fall out of that.
|
|
30
|
-
|
|
31
|
-
## Working rules (short summary)
|
|
32
|
-
|
|
33
|
-
- Implement **one TASK at a time**.
|
|
34
|
-
- Every mutating command should support `--dry-run` when possible.
|
|
35
|
-
- After implementation, update this document, the TASK file, and `docs/logs/YYYY-MM-DD.md` together.
|
|
15
|
+
Run `vibeops task add` to create the first TASK.
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Decisions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
> Append-only log. Add bullets when a TASK locks a choice — do not rewrite history.
|
|
4
4
|
|
|
5
|
-
## D-001 ·
|
|
5
|
+
## D-001 · VibeOps workflow
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
Large refactors do not happen without a dedicated TASK.
|
|
12
|
-
|
|
13
|
-
## D-003 · Notion is the human dashboard (metadata only)
|
|
14
|
-
|
|
15
|
-
No body sync. No realtime.
|
|
16
|
-
|
|
17
|
-
<!--
|
|
18
|
-
Add later decisions as `D-NNN · one-line summary`.
|
|
19
|
-
Keep each entry short — one paragraph that covers "why" and "result".
|
|
20
|
-
-->
|
|
7
|
+
- **Date:** {{CREATED_AT}}
|
|
8
|
+
- **Decision:** TASK-driven development with `vibeops task add` / `task done` and Cursor for plan/build.
|
|
9
|
+
- **Why:** Git `docs/tasks` beats chat as source of truth.
|