@0xtiby/toby 0.0.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.
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@0xtiby/toby",
3
+ "version": "0.0.1",
4
+ "description": "AI-assisted development loop engine CLI",
5
+ "type": "module",
6
+ "bin": {
7
+ "toby": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "prompts"
12
+ ],
13
+ "publishConfig": {
14
+ "access": "public"
15
+ },
16
+ "scripts": {
17
+ "build": "tsup",
18
+ "dev": "tsup --watch",
19
+ "test": "vitest run",
20
+ "bootstrap": "bash scripts/bootstrap.sh",
21
+ "setup:branch-protection": "bash scripts/setup-branch-protection.sh"
22
+ },
23
+ "dependencies": {
24
+ "@0xtiby/spawner": "latest",
25
+ "ink": "^5.0.1",
26
+ "ink-select-input": "^6.2.0",
27
+ "ink-spinner": "^5.0.0",
28
+ "ink-text-input": "^6.0.0",
29
+ "meow": "^13.2.0",
30
+ "react": "^18.3.1",
31
+ "zod": "^3.24.1"
32
+ },
33
+ "devDependencies": {
34
+ "@semantic-release/github": "^12.0.2",
35
+ "@types/react": "^18.3.1",
36
+ "ink-testing-library": "^4.0.0",
37
+ "semantic-release": "^25.0.2",
38
+ "tsup": "^8.0.0",
39
+ "typescript": "^5.4.0",
40
+ "vitest": "^2.0.0"
41
+ }
42
+ }
@@ -0,0 +1,94 @@
1
+ # Build Mode
2
+
3
+ You are in BUILD mode. Implement one task from the spec, validate, and commit.
4
+
5
+ **Spec:** `{{SPECS_DIR}}/{{SPEC_NAME}}.md`
6
+ **Iteration:** {{ITERATION}}
7
+ **Session:** {{SESSION}}
8
+ **Progress:** spec {{SPEC_INDEX}} of {{SPEC_COUNT}}
9
+ **All specs:** {{SPECS}}
10
+
11
+ ---
12
+
13
+ ## Path Discovery Rules (CRITICAL)
14
+
15
+ **NEVER guess or invent file paths.** Always verify paths exist before referencing them.
16
+
17
+ Before editing ANY file:
18
+ 1. Use Glob to find files matching a pattern
19
+ 2. Use Grep to search for specific code
20
+ 3. Verify the file exists before editing it
21
+
22
+ For new files: verify the parent directory exists first.
23
+
24
+ ---
25
+
26
+ ## Phase 1: Find Ready Task
27
+
28
+ Read the spec file at `{{SPECS_DIR}}/{{SPEC_NAME}}.md` and find the first task where:
29
+ - `status` is `"pending"`
30
+ - All tasks listed in `dependencies` have `status: "done"`
31
+
32
+ If no ready task exists:
33
+ 1. Check if all tasks are `"done"` → output `:::TOBY_DONE:::`
34
+ 2. Check if tasks are `"blocked"` → report blockers and output `:::TOBY_DONE:::`
35
+ 3. Otherwise → output `:::TOBY_DONE:::`
36
+
37
+ ## Phase 2: Implement Task
38
+
39
+ 1. Read the task's description, acceptance criteria, and files list
40
+ 2. Before making changes, search the codebase to:
41
+ - Verify functionality doesn't already exist
42
+ - Understand existing patterns
43
+ - Identify the actual files to modify
44
+ 3. Implement the task following the acceptance criteria
45
+ 4. Build small, validate early — tracer bullet mindset
46
+
47
+ ## Phase 3: Validate
48
+
49
+ Run project validation commands. Common patterns:
50
+ - Build: check the project compiles
51
+ - Type check: verify no type errors
52
+ - Lint: ensure code style
53
+ - Test: run relevant tests
54
+
55
+ If validation fails:
56
+ 1. First attempt: targeted fix based on error
57
+ 2. Second attempt: alternative approach
58
+ 3. Third attempt: revert changes, mark task as `"blocked"` in spec, and exit
59
+
60
+ ## Phase 4: Commit
61
+
62
+ When validation passes:
63
+
64
+ 1. Stage and commit changes:
65
+ ```bash
66
+ git add -A
67
+ git commit -m "$(cat <<'EOF'
68
+ feat({{SPEC_NAME}}): [task title]
69
+
70
+ Progress: [what was completed]
71
+ Next: [remaining tasks, or "none" if last]
72
+ EOF
73
+ )"
74
+ ```
75
+
76
+ 2. Update the spec: set the completed task's status to `"done"`
77
+
78
+ 3. Push:
79
+ ```bash
80
+ git push -u origin HEAD
81
+ ```
82
+
83
+ **STOP HERE.** Do not pick up another task. The loop engine handles continuation.
84
+ Do NOT output `:::TOBY_DONE:::` after completing a task — just stop.
85
+
86
+ ---
87
+
88
+ ## Guardrails
89
+
90
+ 1. **Single task** — implement ONE task, then STOP
91
+ 2. **Validate before commit** — never commit failing code
92
+ 3. **Update spec** — mark task as done after committing
93
+ 4. **Verify paths** — use Glob/Grep before editing files
94
+ 5. **Tracer bullet** — build small, test immediately
@@ -0,0 +1,124 @@
1
+ # Planning Mode: Spec → PRD
2
+
3
+ You are in PLANNING mode. Translate a spec into a structured PRD (Product Requirements Document) with actionable tasks.
4
+
5
+ **Spec:** `{{SPECS_DIR}}/{{SPEC_NAME}}.md`
6
+ **PRD output:** `{{PRD_PATH}}`
7
+ **Iteration:** {{ITERATION}}
8
+
9
+ ---
10
+
11
+ ## Path Discovery Rules (CRITICAL)
12
+
13
+ **NEVER guess or invent file paths.** Always verify paths exist before referencing them.
14
+
15
+ Before referencing ANY file path:
16
+ 1. Use Glob to find files matching a pattern
17
+ 2. Use Grep to search for specific code
18
+ 3. Verify the file exists before adding it to a task's files list
19
+
20
+ For new files (create): verify the parent directory exists first.
21
+
22
+ ---
23
+
24
+ ## If PRD exists: Refinement Mode
25
+
26
+ If `{{PRD_PATH}}` already exists, read it and refine:
27
+ - Check all spec requirements have corresponding tasks
28
+ - Verify file paths are accurate (re-run Glob/Grep)
29
+ - Split tasks that are too large (~2 min per task)
30
+ - Add missing dependencies
31
+ - Improve acceptance criteria specificity
32
+ - If no improvements needed, output: :::TOBY_DONE:::
33
+
34
+ ## If PRD does not exist: Creation Mode
35
+
36
+ ### Step 1: Read & Understand the Spec
37
+
38
+ Read the spec file at `{{SPECS_DIR}}/{{SPEC_NAME}}.md` and extract:
39
+ - Problem statement (WHY)
40
+ - User stories (WHAT users can do)
41
+ - Data model (entities, relationships)
42
+ - UI/UX flows (screens, interactions)
43
+ - Acceptance criteria (verification)
44
+
45
+ ### Step 2: Explore Codebase
46
+
47
+ Before creating tasks, validate assumptions against actual code:
48
+ - **Find files to modify:** Search for existing files related to the spec
49
+ - **Identify patterns:** Look at similar features for structure to follow
50
+ - **Check reusable code:** Find existing utilities, helpers, components
51
+ - **Verify data model:** Check current database schema or data structures
52
+
53
+ ### Step 3: Create PRD
54
+
55
+ Write the PRD to `{{PRD_PATH}}` as a JSON file with this exact structure:
56
+
57
+ ```json
58
+ {
59
+ "spec": "{{SPEC_NAME}}.md",
60
+ "createdAt": "<ISO 8601 timestamp>",
61
+ "tasks": [
62
+ {
63
+ "id": "task-001",
64
+ "title": "[Action verb] [specific deliverable]",
65
+ "description": "[What to implement and why]",
66
+ "acceptanceCriteria": [
67
+ "[Specific, testable criterion 1]",
68
+ "[Specific, testable criterion 2]"
69
+ ],
70
+ "files": [
71
+ "path/to/file.ts (modify) — verified via Glob",
72
+ "path/to/new-file.ts (create) — parent dir verified"
73
+ ],
74
+ "dependencies": [],
75
+ "status": "pending",
76
+ "priority": 1
77
+ }
78
+ ]
79
+ }
80
+ ```
81
+
82
+ ### Task Design Rules
83
+
84
+ **Granularity:** Each task should take ~2 minutes. If longer, break it down.
85
+
86
+ **Tracer bullet approach:** The first tasks should form a minimal end-to-end vertical slice:
87
+ - Wrong: Schema → all queries → all actions → all UI
88
+ - Right: Schema + one query + one action + one UI = tracer bullet, then expand
89
+
90
+ **Task structure:**
91
+ 1. **Tracer phase** (1+ tasks) — minimal e2e slice
92
+ 2. Remaining tasks expand from the tracer, ordered by dependencies
93
+ 3. Each task lists specific files with (modify) or (create) and verification method
94
+
95
+ **Dependencies:** Use task IDs. A task cannot start until all dependencies are `done`.
96
+
97
+ **Priority:** Lower number = higher priority. Tracer tasks get priority 1.
98
+
99
+ ### Step 4: Verify & Output
100
+
101
+ After writing the PRD:
102
+ 1. Re-read the file to confirm it's valid JSON
103
+ 2. Verify task count covers all spec requirements
104
+ 3. Output a summary:
105
+
106
+ ```
107
+ ## PRD Created for: {{SPEC_NAME}}
108
+
109
+ Tasks: [count]
110
+ Tracer tasks: [count]
111
+ Dependencies: [count] relationships
112
+
113
+ Ready to build: task-001, task-002 (no dependencies)
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Guardrails
119
+
120
+ 1. **DO NOT implement** — only create the PRD
121
+ 2. **~2 minute tasks** — break down larger work
122
+ 3. **Verify file paths** — use Glob/Grep before referencing
123
+ 4. **Valid JSON** — the PRD must be parseable
124
+ 5. **All spec requirements covered** — every user story needs tasks
@@ -0,0 +1,76 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { readFileSync, accessSync } from "node:fs";
3
+ import { join } from "node:path";
4
+
5
+ const PROMPTS_DIR = join(import.meta.dirname, ".");
6
+
7
+ const PROMPT_FILES = ["PROMPT_PLAN.md", "PROMPT_BUILD.md"] as const;
8
+
9
+ function readPrompt(name: string): string {
10
+ return readFileSync(join(PROMPTS_DIR, name), "utf-8");
11
+ }
12
+
13
+ function extractVars(content: string): string[] {
14
+ const matches = content.matchAll(/\{\{(\w+)\}\}/g);
15
+ return [...new Set([...matches].map((m) => m[1]))];
16
+ }
17
+
18
+ describe("prompt files", () => {
19
+ it.each(PROMPT_FILES)("%s exists and is readable", (file) => {
20
+ expect(() => accessSync(join(PROMPTS_DIR, file))).not.toThrow();
21
+ });
22
+
23
+ it.each(PROMPT_FILES)("%s is non-empty markdown", (file) => {
24
+ const content = readPrompt(file);
25
+ expect(content.length).toBeGreaterThan(0);
26
+ expect(content).toContain("#");
27
+ });
28
+
29
+ it.each(PROMPT_FILES)("%s contains :::TOBY_DONE::: sentinel", (file) => {
30
+ const content = readPrompt(file);
31
+ expect(content).toContain(":::TOBY_DONE:::");
32
+ });
33
+
34
+ it.each(PROMPT_FILES)("%s uses {{VAR_NAME}} syntax", (file) => {
35
+ const content = readPrompt(file);
36
+ // No single-brace vars like {VAR}
37
+ const singleBrace = content.match(/(?<!\{)\{([A-Z_]+)\}(?!\})/g);
38
+ expect(singleBrace).toBeNull();
39
+ });
40
+
41
+ it.each(PROMPT_FILES)("%s does not start with frontmatter", (file) => {
42
+ const content = readPrompt(file);
43
+ expect(content.startsWith("---")).toBe(false);
44
+ });
45
+
46
+ it.each(PROMPT_FILES)("%s does not contain dead vars", (file) => {
47
+ const content = readPrompt(file);
48
+ const deadVars = ["BRANCH", "WORKTREE", "EPIC_NAME", "IS_LAST_SPEC", "IS_EPIC", "SPEC_CONTENT"];
49
+ for (const v of deadVars) {
50
+ expect(content).not.toContain(`{{${v}}}`);
51
+ }
52
+ });
53
+ });
54
+
55
+ describe("PROMPT_PLAN.md variables", () => {
56
+ const vars = extractVars(readPrompt("PROMPT_PLAN.md"));
57
+
58
+ it.each(["SPEC_NAME", "ITERATION", "PRD_PATH", "SPECS_DIR"])(
59
+ "contains %s",
60
+ (v) => {
61
+ expect(vars).toContain(v);
62
+ },
63
+ );
64
+ });
65
+
66
+ describe("PROMPT_BUILD.md variables", () => {
67
+ const vars = extractVars(readPrompt("PROMPT_BUILD.md"));
68
+
69
+ it.each(["SPEC_NAME", "ITERATION", "SPECS_DIR", "SPEC_INDEX", "SPEC_COUNT", "SESSION", "SPECS"])(
70
+ "contains %s",
71
+ (v) => {
72
+ expect(vars).toContain(v);
73
+ },
74
+ );
75
+ });
76
+