@goodtek/vibeops 0.7.22 → 1.1.1

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.
Files changed (144) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +51 -380
  3. package/dist/bootstrap/installer.js +42 -20
  4. package/dist/bootstrap/manifest.js +23 -3
  5. package/dist/cli.js +69 -154
  6. package/dist/commands/init.js +279 -114
  7. package/dist/commands/llm.js +177 -0
  8. package/dist/commands/status.js +181 -8
  9. package/dist/commands/task-add.js +89 -162
  10. package/dist/commands/task-done.js +112 -73
  11. package/dist/lib/config.js +77 -113
  12. package/dist/lib/env.js +32 -0
  13. package/dist/lib/git-config.js +21 -0
  14. package/dist/lib/git-host.js +12 -0
  15. package/dist/lib/git-policy.js +67 -0
  16. package/dist/lib/git-remote.js +108 -0
  17. package/dist/lib/git.js +44 -1
  18. package/dist/lib/init-clients.js +55 -0
  19. package/dist/lib/llm-complete.js +18 -19
  20. package/dist/lib/llm-connect.js +150 -0
  21. package/dist/lib/llm-preference.js +102 -0
  22. package/dist/lib/llm-status.js +19 -0
  23. package/dist/lib/paths.js +7 -3
  24. package/dist/lib/plan-llm-openai.js +0 -63
  25. package/dist/lib/pr-create.js +66 -0
  26. package/dist/lib/resolve-task.js +34 -0
  27. package/dist/lib/task-add-llm.js +53 -233
  28. package/dist/lib/task-context.js +68 -0
  29. package/dist/lib/task-done-llm.js +155 -0
  30. package/dist/lib/task-pr-llm.js +50 -0
  31. package/dist/lib/task-push-pr.js +131 -0
  32. package/dist/lib/task-scaffold.js +39 -43
  33. package/dist/lib/task-start.js +100 -0
  34. package/dist/lib/task-summary.js +12 -239
  35. package/dist/lib/task.js +30 -24
  36. package/dist/types/config.js +0 -16
  37. package/package.json +14 -14
  38. package/templates/.cursor/rules/02-git-safety.mdc +12 -0
  39. package/templates/AGENTS.md +27 -87
  40. package/templates/clients/claude/CLAUDE.md +28 -0
  41. package/templates/clients/cursor/.cursor/rules/01-task-source-of-truth.mdc +12 -0
  42. package/templates/clients/cursor/.cursor/rules/02-git-safety.mdc +11 -0
  43. package/templates/clients/cursor/.cursor/rules/03-docs-on-done.mdc +13 -0
  44. package/templates/core/AGENTS.md +44 -0
  45. package/templates/core/docs/logs/README.md +7 -0
  46. package/templates/core/docs/project/03-architecture.md +15 -0
  47. package/templates/core/docs/project/05-current-state.md +15 -0
  48. package/templates/core/docs/project/06-decisions.md +9 -0
  49. package/templates/core/docs/tasks/TASK-000-template.md +37 -0
  50. package/templates/skills-shared/implement-task/SKILL.md +22 -0
  51. package/templates/skills-shared/plan-task/SKILL.md +19 -0
  52. package/dist/agent/loader.js +0 -71
  53. package/dist/agent/prompt.js +0 -66
  54. package/dist/commands/agent-list.js +0 -32
  55. package/dist/commands/agent-prompt.js +0 -59
  56. package/dist/commands/agent-show.js +0 -26
  57. package/dist/commands/done.js +0 -160
  58. package/dist/commands/github-init.js +0 -554
  59. package/dist/commands/github-status.js +0 -164
  60. package/dist/commands/next.js +0 -283
  61. package/dist/commands/notion-init.js +0 -764
  62. package/dist/commands/notion-sync.js +0 -405
  63. package/dist/commands/notion-test.js +0 -595
  64. package/dist/commands/plan.js +0 -146
  65. package/dist/commands/rollback.js +0 -126
  66. package/dist/commands/start.js +0 -129
  67. package/dist/commands/task-check.js +0 -155
  68. package/dist/commands/task-generate.js +0 -206
  69. package/dist/commands/task-pull.js +0 -277
  70. package/dist/commands/task-rollback.js +0 -174
  71. package/dist/commands/task-start.js +0 -102
  72. package/dist/commands/task-status.js +0 -122
  73. package/dist/lib/brief.js +0 -356
  74. package/dist/lib/cursor-task-prompt.js +0 -60
  75. package/dist/lib/done-follow-up.js +0 -308
  76. package/dist/lib/github-cli.js +0 -247
  77. package/dist/lib/guide-state.js +0 -69
  78. package/dist/lib/mvp-artifacts.js +0 -204
  79. package/dist/lib/mvp-constants.js +0 -15
  80. package/dist/lib/mvp-diff-summary.js +0 -43
  81. package/dist/lib/mvp-done-summary.js +0 -335
  82. package/dist/lib/notion-client.js +0 -459
  83. package/dist/lib/notion-discovery.js +0 -671
  84. package/dist/lib/notion-env.js +0 -140
  85. package/dist/lib/notion-mappers.js +0 -148
  86. package/dist/lib/notion-schema.js +0 -272
  87. package/dist/lib/notion-sync.js +0 -337
  88. package/dist/lib/notion-target.js +0 -247
  89. package/dist/lib/package-json.js +0 -133
  90. package/dist/lib/plan-apply-planner.js +0 -131
  91. package/dist/lib/plan-codex-pkce.js +0 -234
  92. package/dist/lib/plan-llm-models.js +0 -237
  93. package/dist/lib/plan-llm-normalize.js +0 -146
  94. package/dist/lib/plan-llm-session.js +0 -682
  95. package/dist/lib/plan-post-apply-setup.js +0 -116
  96. package/dist/lib/project-docs.js +0 -95
  97. package/dist/lib/prompt-builder.js +0 -135
  98. package/dist/lib/resolve-command-task.js +0 -40
  99. package/dist/lib/task-add-build-prompt.js +0 -39
  100. package/dist/lib/task-add-cursor.js +0 -81
  101. package/dist/lib/task-generator.js +0 -183
  102. package/dist/lib/task-merge.js +0 -220
  103. package/dist/lib/task-prompt.js +0 -23
  104. package/dist/lib/task-pull.js +0 -354
  105. package/dist/lib/task-status-brief.js +0 -132
  106. package/dist/lib/workflow-guide.js +0 -485
  107. package/dist/status/collector.js +0 -103
  108. package/dist/status/format.js +0 -181
  109. package/dist/types/brief.js +0 -126
  110. package/templates/.cursor/rules/00-project-governance.mdc +0 -28
  111. package/templates/.cursor/rules/01-agent-orchestration.mdc +0 -48
  112. package/templates/.cursor/rules/02-task-workflow.mdc +0 -38
  113. package/templates/.cursor/rules/03-git-safety.mdc +0 -30
  114. package/templates/.cursor/rules/04-docs-update.mdc +0 -22
  115. package/templates/.vibeops/agents/architect.md +0 -47
  116. package/templates/.vibeops/agents/builder.md +0 -38
  117. package/templates/.vibeops/agents/docs.md +0 -54
  118. package/templates/.vibeops/agents/orchestrator.md +0 -40
  119. package/templates/.vibeops/agents/planner.md +0 -60
  120. package/templates/.vibeops/agents/recovery.md +0 -49
  121. package/templates/.vibeops/agents/reviewer.md +0 -47
  122. package/templates/.vibeops/agents/tester.md +0 -43
  123. package/templates/.vibeops/prompts/create-plan.md +0 -33
  124. package/templates/.vibeops/prompts/generate-tasks.md +0 -41
  125. package/templates/.vibeops/prompts/implement-task.md +0 -39
  126. package/templates/.vibeops/prompts/review-task.md +0 -34
  127. package/templates/.vibeops/prompts/rollback.md +0 -32
  128. package/templates/.vibeops/prompts/start-project.md +0 -39
  129. package/templates/.vibeops/workflows/notion-sync.md +0 -53
  130. package/templates/.vibeops/workflows/project-start.md +0 -73
  131. package/templates/.vibeops/workflows/rollback.md +0 -45
  132. package/templates/.vibeops/workflows/task-lifecycle.md +0 -71
  133. package/templates/docs/logs/README.md +0 -38
  134. package/templates/docs/project/00-overview.md +0 -27
  135. package/templates/docs/project/01-requirements.md +0 -30
  136. package/templates/docs/project/02-mvp-scope.md +0 -36
  137. package/templates/docs/project/03-architecture.md +0 -34
  138. package/templates/docs/project/04-tech-stack.md +0 -29
  139. package/templates/docs/project/05-current-state.md +0 -35
  140. package/templates/docs/project/06-decisions.md +0 -20
  141. package/templates/docs/project/07-backlog.md +0 -23
  142. package/templates/docs/project/08-env.md +0 -29
  143. package/templates/docs/project/09-deployment.md +0 -28
  144. package/templates/docs/tasks/TASK-000-template.md +0 -72
package/dist/lib/task.js CHANGED
@@ -34,9 +34,6 @@ export function statusDisplay(status) {
34
34
  }
35
35
  function extractIdFromFilename(file) {
36
36
  const name = basename(file);
37
- const mvp = /^TASK-mvp/i.exec(name);
38
- if (mvp)
39
- return "TASK-mvp";
40
37
  const m = /^(TASK-\d+)/i.exec(name);
41
38
  return m ? m[1].toUpperCase() : basename(file, ".md");
42
39
  }
@@ -103,7 +100,7 @@ export async function scanTasks(tasksDir) {
103
100
  return [];
104
101
  const entries = await readdir(tasksDir, { withFileTypes: true });
105
102
  const files = entries
106
- .filter((e) => e.isFile() && e.name.endsWith(".md") && /^TASK-(?:\d+|mvp)/i.test(e.name))
103
+ .filter((e) => e.isFile() && e.name.endsWith(".md") && /^TASK-\d+/i.test(e.name))
107
104
  .map((e) => join(tasksDir, e.name))
108
105
  .sort();
109
106
  const out = [];
@@ -141,19 +138,13 @@ export function pickNextTask(tasks) {
141
138
  if (review)
142
139
  return review;
143
140
  const planned = tasks.filter((t) => t.status === "planned");
144
- const mvp = planned.find((t) => t.id.toUpperCase() === "TASK-MVP");
145
- return mvp ?? planned[0] ?? null;
141
+ return planned[0] ?? null;
146
142
  }
147
143
  const TEMPLATE_TASK_ID = "TASK-000";
148
144
  export function filterActionableTasks(tasks) {
149
145
  return tasks.filter((t) => t.id.toUpperCase() !== TEMPLATE_TASK_ID);
150
146
  }
151
- export function isMvpTaskId(id) {
152
- return id.toUpperCase() === "TASK-MVP";
153
- }
154
147
  function taskSortKey(id) {
155
- if (isMvpTaskId(id))
156
- return 1_000_000;
157
148
  const m = /^TASK-(\d+)$/i.exec(id.trim());
158
149
  return m ? Number.parseInt(m[1], 10) : 0;
159
150
  }
@@ -191,26 +182,20 @@ export async function pickActiveTask(tasksDir, cwd) {
191
182
  }
192
183
  export async function findTaskFile(tasksDir, taskId) {
193
184
  const all = await scanTasks(tasksDir);
194
- const normalized = taskId.trim();
195
- const target = /^mvp$/i.test(normalized) || /^task-mvp$/i.test(normalized)
196
- ? "TASK-MVP"
197
- : normalized.toUpperCase();
185
+ const target = normalizeTaskRef(taskId);
198
186
  for (const t of all) {
199
187
  if (t.id.toUpperCase() === target)
200
188
  return t.filePath;
201
189
  }
202
190
  return null;
203
191
  }
192
+ function normalizeTaskRef(ref) {
193
+ const t = ref.trim().toUpperCase();
194
+ return t.startsWith("TASK-") ? t : `TASK-${t}`;
195
+ }
204
196
  const TASK_FILENAME_RE = /^TASK-(\d+)(?:-(.+))?$/i;
205
- const TASK_MVP_FILENAME_RE = /^TASK-mvp(?:-(.+))?$/i;
206
197
  export function parseTaskFilename(filePath) {
207
198
  const stem = basename(filePath, extname(filePath));
208
- const mvp = TASK_MVP_FILENAME_RE.exec(stem);
209
- if (mvp) {
210
- const tail = (mvp[1] ?? "").trim().toLowerCase();
211
- const slug = tail.length > 0 ? `mvp-${tail}` : "mvp";
212
- return { id: "TASK-mvp", number: "mvp", slug };
213
- }
214
199
  const m = TASK_FILENAME_RE.exec(stem);
215
200
  if (!m) {
216
201
  return { id: stem.toUpperCase(), number: "000", slug: stem.toLowerCase() };
@@ -368,6 +353,12 @@ function renderGitContextBlock(ctx) {
368
353
  if (typeof ctx.doneAt === "string" && ctx.doneAt.length > 0) {
369
354
  lines.push(`- Done At: \`${ctx.doneAt}\``);
370
355
  }
356
+ if (typeof ctx.mergeRequestUrl === "string" && ctx.mergeRequestUrl.length > 0) {
357
+ lines.push(`- Merge Request: ${ctx.mergeRequestUrl}`);
358
+ }
359
+ if (typeof ctx.pushedAt === "string" && ctx.pushedAt.length > 0) {
360
+ lines.push(`- Pushed At: \`${ctx.pushedAt}\``);
361
+ }
371
362
  return lines.join("\n");
372
363
  }
373
364
  export async function upsertGitContext(filePath, ctx) {
@@ -377,8 +368,8 @@ export async function upsertGitContext(filePath, ctx) {
377
368
  if (locateSection(raw, "Git Context")) {
378
369
  updated = replaceSectionContent(raw, "Git Context", block);
379
370
  }
380
- else if (locateSection(raw, "MVP Phase")) {
381
- updated = insertSectionAfter(raw, "MVP Phase", "Git Context", block);
371
+ else if (locateSection(raw, "Test Plan")) {
372
+ updated = insertSectionAfter(raw, "Test Plan", "Git Context", block);
382
373
  }
383
374
  else if (locateSection(raw, "Status")) {
384
375
  updated = insertSectionAfter(raw, "Status", "Git Context", block);
@@ -396,7 +387,15 @@ const GIT_CTX_RE = {
396
387
  taskBranch: /^-\s+Task Branch:\s*`([^`]+)`/m,
397
388
  startedAt: /^-\s+Started At:\s*`([^`]+)`/m,
398
389
  doneAt: /^-\s+Done At:\s*`([^`]+)`/m,
390
+ mergeRequestUrl: /^-\s+Merge Request:\s*(.+)$/m,
391
+ pushedAt: /^-\s+Pushed At:\s*`([^`]+)`/m,
399
392
  };
393
+ export async function markGitContextDone(filePath) {
394
+ const ctx = await readGitContext(filePath);
395
+ if (ctx === null)
396
+ return;
397
+ await upsertGitContext(filePath, { ...ctx, doneAt: new Date().toISOString() });
398
+ }
400
399
  export async function readGitContext(filePath) {
401
400
  const raw = await readText(filePath);
402
401
  const content = readSection(raw, "Git Context");
@@ -409,8 +408,15 @@ export async function readGitContext(filePath) {
409
408
  if (!baseBranch || !baseCommit || !taskBranch || !startedAt)
410
409
  return null;
411
410
  const doneAt = content.match(GIT_CTX_RE.doneAt)?.[1];
411
+ const mergeRequestUrl = content.match(GIT_CTX_RE.mergeRequestUrl)?.[1]?.trim();
412
+ const pushedAt = content.match(GIT_CTX_RE.pushedAt)?.[1];
412
413
  const ctx = { baseBranch, baseCommit, taskBranch, startedAt };
413
414
  if (typeof doneAt === "string" && doneAt.length > 0)
414
415
  ctx.doneAt = doneAt;
416
+ if (typeof mergeRequestUrl === "string" && mergeRequestUrl.length > 0) {
417
+ ctx.mergeRequestUrl = mergeRequestUrl;
418
+ }
419
+ if (typeof pushedAt === "string" && pushedAt.length > 0)
420
+ ctx.pushedAt = pushedAt;
415
421
  return ctx;
416
422
  }
@@ -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,8 +1,9 @@
1
1
  {
2
2
  "name": "@goodtek/vibeops",
3
- "version": "0.7.22",
4
- "description": "Workflow rails for Cursor-based vibe coding projects.",
3
+ "version": "1.1.1",
4
+ "description": "Minimal CLI rails for Cursor-based TASK-driven vibe coding.",
5
5
  "type": "module",
6
+ "packageManager": "pnpm@9.15.9",
6
7
  "author": "VibeOps contributors",
7
8
  "license": "MIT",
8
9
  "repository": {
@@ -29,20 +30,27 @@
29
30
  "engines": {
30
31
  "node": ">=20"
31
32
  },
33
+ "scripts": {
34
+ "dev": "tsx src/cli.ts",
35
+ "build": "tsc -p tsconfig.json",
36
+ "typecheck": "tsc -p tsconfig.json --noEmit",
37
+ "start": "node dist/cli.js",
38
+ "smoke": "pnpm typecheck && pnpm build && node scripts/smoke.mjs",
39
+ "clean": "rm -rf dist",
40
+ "prepack": "pnpm clean && pnpm build",
41
+ "publish:dry": "pnpm publish --dry-run --no-git-checks"
42
+ },
32
43
  "keywords": [
33
44
  "cursor",
34
45
  "ai",
35
46
  "coding",
36
47
  "cli",
37
48
  "task",
38
- "notion",
39
49
  "vibeops",
40
50
  "workflow"
41
51
  ],
42
52
  "dependencies": {
43
- "@goodtek/vibeops": "^0.3.0",
44
53
  "@inquirer/prompts": "^8.4.3",
45
- "@notionhq/client": "^5.20.0",
46
54
  "commander": "^12.1.0",
47
55
  "gray-matter": "^4.0.3"
48
56
  },
@@ -50,13 +58,5 @@
50
58
  "@types/node": "^20.14.0",
51
59
  "tsx": "^4.19.0",
52
60
  "typescript": "^5.5.4"
53
- },
54
- "scripts": {
55
- "dev": "tsx src/cli.ts",
56
- "build": "tsc -p tsconfig.json",
57
- "typecheck": "tsc -p tsconfig.json --noEmit",
58
- "start": "node dist/cli.js",
59
- "smoke": "pnpm typecheck && pnpm build && node scripts/smoke.mjs",
60
- "publish:dry": "pnpm publish --dry-run --no-git-checks"
61
61
  }
62
- }
62
+ }
@@ -0,0 +1,12 @@
1
+ ---
2
+ description: Git safety for task branches and merge requests
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # Git safety
7
+
8
+ - Branch policy lives in `.vibeops.json` (`integrationBranch`, `productionBranch`).
9
+ - `vibeops task add` creates `task/*` from the **integration** branch (e.g. `develop`).
10
+ - Include the TASK id in commit messages, e.g. `feat(task-015): short title`.
11
+ - **`vibeops task done`** pushes the branch and opens an MR/PR — it does **not** merge locally.
12
+ - Merge on GitHub/GitLab; CI deploys after merge. No force-push to shared branches.
@@ -1,98 +1,38 @@
1
- # {{PROJECT_NAME}} — AI agent operating guide
1
+ # {{PROJECT_NAME}} — AI agent guide
2
2
 
3
- > This file was installed by **VibeOps**. Every AI agent on this project (including Cursor) reads it before touching code.
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 | Where |
29
- | -------------------------- | ---------------------------------- |
30
- | AI execution input | Git `docs/tasks/*.md` |
31
- | Project design and status | Git `docs/project/*.md` |
32
- | Change history and rollback | Git commits / branches |
33
- | Human dashboard | Notion (metadata only, never body) |
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
- | File | Contents |
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
- ## Completion report
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
- When you finish a TASK, include at least the following in your chat response:
20
+ ## Workflow (human + CLI)
85
21
 
86
- 1. **TASK ID** (for example `TASK-001`).
87
- 2. **Summary** — 2 to 4 sentences on what was achieved.
88
- 3. **Changed files** — list of the main paths.
89
- 4. **Verification** — the commands you ran and their results.
90
- 5. **Doc updates** — confirm you updated `05-current-state.md`, the TASK's Result / Test Result, and `docs/logs/YYYY-MM-DD.md`.
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, push + open MR/PR
28
+ vibeops status # briefing
29
+ vibeops llm connect # set up LLM providers and pick default
30
+ ```
91
31
 
92
- Do not end the report with just "done".
32
+ ## Rules
93
33
 
94
- ## VibeOps metadata
34
+ - **One TASK at a time** — stay inside Scope and Acceptance Criteria.
35
+ - **Search** before adding files; reuse existing patterns.
36
+ - When the TASK is finished, **Result** and **Test Result** must be filled before `vibeops task done`.
95
37
 
96
- - Project name: `{{PROJECT_NAME}}`
97
- - Bootstrapped by: VibeOps `{{VIBEOPS_VERSION}}`
98
- - Created at: `{{CREATED_AT}}`
38
+ Details: `.cursor/rules/`.
@@ -0,0 +1,28 @@
1
+ # {{PROJECT_NAME}} — Claude Code
2
+
3
+ Read **`AGENTS.md`** first (VibeOps workflow and source of truth).
4
+
5
+ ## Skills (project)
6
+
7
+ | Skill | When |
8
+ |-------|------|
9
+ | `/plan-task` | Refine `docs/tasks/TASK-NNN-*.md` before coding |
10
+ | `/implement-task` | Build per TASK Scope and Acceptance Criteria |
11
+
12
+ Skills live in `.claude/skills/`.
13
+
14
+ ## Session start
15
+
16
+ 1. `docs/project/05-current-state.md`
17
+ 2. The **full** current `docs/tasks/TASK-NNN-*.md` file
18
+ 3. `docs/project/03-architecture.md` and `06-decisions.md` when relevant
19
+
20
+ ## Git
21
+
22
+ - Branch: `task/*` from `vibeops task add`
23
+ - Commit messages include the TASK id, e.g. `feat(task-015): short title`
24
+ - Do not merge to main unless the human runs `vibeops task done` or asks
25
+
26
+ ## Finishing
27
+
28
+ Fill **Result** and **Test Result** in the TASK file, then tell the human to run `vibeops task done TASK-NNN`.
@@ -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,44 @@
1
+ # {{PROJECT_NAME}} — AI agent guide
2
+
3
+ > Installed by **VibeOps**. Agents read this repo and `docs/tasks/`, not chat history.
4
+
5
+ ## Source of truth
6
+
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 | Chat history, Slack |
13
+
14
+ ## Before you code
15
+
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/`
19
+
20
+ ## Workflow (human + CLI)
21
+
22
+ ```bash
23
+ vibeops init # once (pick Cursor / Claude Code / Codex packs)
24
+ vibeops task add # new TASK + branch
25
+ # Plan: refine TASK file with your agent (see client skills below)
26
+ # Build: implement per TASK Scope / Acceptance Criteria
27
+ vibeops task done # close TASK, update project docs, merge
28
+ vibeops status # briefing
29
+ vibeops llm connect # LLM for task add / task done
30
+ ```
31
+
32
+ ## Client packs (installed at init)
33
+
34
+ | Tool | Rules / guide | Skills |
35
+ |------|----------------|--------|
36
+ | **Cursor** | `.cursor/rules/` | `.cursor/skills/` (`plan-task`, `implement-task`) |
37
+ | **Claude Code** | `CLAUDE.md` | `.claude/skills/` |
38
+ | **Codex CLI** | `AGENTS.md` (this file) | `.agents/skills/` |
39
+
40
+ ## Rules (all agents)
41
+
42
+ - **One TASK at a time** — stay inside Scope and Acceptance Criteria.
43
+ - **Search** before adding files; reuse existing patterns.
44
+ - Fill **Result** and **Test Result** before `vibeops task done`.
@@ -0,0 +1,7 @@
1
+ # Daily logs
2
+
3
+ Append-only files: `docs/logs/YYYY-MM-DD.md`.
4
+
5
+ `vibeops task done` may append a short entry when a TASK closes.
6
+
7
+ Keep entries factual: TASK id, paths touched, commands run.
@@ -0,0 +1,15 @@
1
+ # Architecture
2
+
3
+ > Living overview. Update when structure or major paths change (often via `vibeops task done`).
4
+
5
+ ## System
6
+
7
+ (describe stack and main folders as the project grows)
8
+
9
+ ## Key paths
10
+
11
+ | Area | Path |
12
+ |------|------|
13
+ | Application | (TBD) |
14
+ | TASK docs | `docs/tasks/` |
15
+ | Project memory | `docs/project/` |
@@ -0,0 +1,15 @@
1
+ # Current state
2
+
3
+ > Facts only. Updated by `vibeops task done` and humans.
4
+
5
+ ## Stage
6
+
7
+ - Bootstrapped with VibeOps. No TASK started yet.
8
+
9
+ ## Active TASK
10
+
11
+ (none)
12
+
13
+ ## Next step
14
+
15
+ Run `vibeops task add` to create the first TASK.
@@ -0,0 +1,9 @@
1
+ # Decisions
2
+
3
+ > Append-only log. Add bullets when a TASK locks a choice — do not rewrite history.
4
+
5
+ ## D-001 · VibeOps workflow
6
+
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.
@@ -0,0 +1,37 @@
1
+ # TASK-NNN · title
2
+
3
+ ## Status
4
+
5
+ Planned
6
+
7
+ ## Goal
8
+
9
+ (what becomes possible when this TASK ships)
10
+
11
+ ## Scope
12
+
13
+ -
14
+
15
+ ## Out of Scope
16
+
17
+ -
18
+
19
+ ## Acceptance Criteria
20
+
21
+ 1.
22
+
23
+ ## Test Plan
24
+
25
+ -
26
+
27
+ ## Git Context
28
+
29
+ (populated by `vibeops task add`)
30
+
31
+ ## Result
32
+
33
+ (not yet)
34
+
35
+ ## Test Result
36
+
37
+ (not yet)
@@ -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 your agent rules (e.g. `.cursor/rules/`, `CLAUDE.md`)
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 `AGENTS.md`, your agent rules, and the TASK file; read `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 implement per the TASK (Agent mode / Codex / Claude Code as they prefer).
@@ -1,71 +0,0 @@
1
- import { readdir } from "node:fs/promises";
2
- import { basename, extname, join } from "node:path";
3
- import matter from "gray-matter";
4
- import { isDirectory, readText } from "../lib/filesystem.js";
5
- function metaFromFile(filePath, data, body) {
6
- const fallbackName = basename(filePath, extname(filePath));
7
- const name = typeof data["name"] === "string" ? data["name"] : fallbackName;
8
- const role = typeof data["role"] === "string" ? data["role"] : extractFirstHeading(body);
9
- const description = typeof data["description"] === "string" ? data["description"] : undefined;
10
- return { name, role, description, filePath };
11
- }
12
- function extractFirstHeading(body) {
13
- for (const line of body.split("\n")) {
14
- const m = /^#\s+(.*)$/.exec(line.trim());
15
- if (m)
16
- return m[1].trim();
17
- }
18
- return "(no role)";
19
- }
20
- function frontmatterSlice(raw) {
21
- if (!raw.startsWith("---"))
22
- return "";
23
- const end = raw.indexOf("\n---", 3);
24
- if (end < 0)
25
- return "";
26
- return raw.slice(0, end + 4);
27
- }
28
- export async function loadAgent(filePath) {
29
- const raw = await readText(filePath);
30
- const parsed = matter(raw);
31
- const meta = metaFromFile(filePath, parsed.data, parsed.content);
32
- return {
33
- meta,
34
- body: parsed.content.trimStart(),
35
- rawFrontmatter: frontmatterSlice(raw),
36
- raw,
37
- };
38
- }
39
- export async function listAgents(agentsDir) {
40
- if (!(await isDirectory(agentsDir)))
41
- return [];
42
- const entries = await readdir(agentsDir, { withFileTypes: true });
43
- const files = entries
44
- .filter((e) => e.isFile() && e.name.endsWith(".md"))
45
- .map((e) => join(agentsDir, e.name))
46
- .sort();
47
- const records = [];
48
- for (const f of files) {
49
- try {
50
- records.push(await loadAgent(f));
51
- }
52
- catch {
53
- // skip malformed agent files
54
- }
55
- }
56
- return records;
57
- }
58
- export async function findAgent(agentsDir, name) {
59
- const all = await listAgents(agentsDir);
60
- const target = name.toLowerCase();
61
- for (const a of all) {
62
- if (a.meta.name.toLowerCase() === target)
63
- return a;
64
- }
65
- for (const a of all) {
66
- const filenameKey = basename(a.meta.filePath, extname(a.meta.filePath)).toLowerCase();
67
- if (filenameKey === target)
68
- return a;
69
- }
70
- return null;
71
- }