@kraftapps-ai/kai 1.0.0 → 1.1.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.
Files changed (3) hide show
  1. package/README.md +76 -115
  2. package/kai +165 -423
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,160 +1,121 @@
1
1
  # Kai
2
2
 
3
- Autonomous AI developer loop for [Claude Code](https://claude.ai/claude-code). Kai takes a list of user stories and implements them one by one — with a built-in reviewer that catches when the AI cuts corners.
3
+ Your AI product manager and development team. One command.
4
4
 
5
- ## How it works
6
-
7
- ```
8
- ┌─────────────┐ ┌──────────────┐ ┌──────────────┐
9
- │ kai.json │────▶│ Implementer │────▶│ Reviewer │
10
- │ (stories) │ │ (claude -p) │ │ (claude -p) │
11
- └─────────────┘ └──────┬───────┘ └──────┬───────┘
12
- │ │
13
- commits code verifies against
14
- marks passes:true acceptance criteria
15
- │ │
16
- │ ┌────────┐ │
17
- └───▶│ Loop │◀──────┘
18
- │ repeat │ (fail = retry)
19
- └────────┘
5
+ ```bash
6
+ npm i -g @kraftapps-ai/kai
7
+ kai
20
8
  ```
21
9
 
22
- 1. **Picks** the next incomplete story from `kai.json`
23
- 2. **Implements** it using Claude Code (one `claude -p` call)
24
- 3. **Reviews** the implementation with a separate Claude call that verifies each acceptance criterion against the actual git diff
25
- 4. **Retries** if the review fails (up to 3 attempts, then skips)
26
- 5. **Loops** to the next story
10
+ ## What is Kai?
27
11
 
28
- Each iteration starts freshno context pollution between stories.
12
+ Kai is a CLI that opens an interactive AI session acting as your **product manager**. Tell it what you want to build. It breaks the work into stories, then dispatches an autonomous AI developer to implement them with a built-in reviewer that catches when the AI cuts corners.
29
13
 
30
- ## Install
14
+ ## How it works
31
15
 
32
- ```bash
33
- npm i -g @kraftapps-ai/kai
34
16
  ```
35
-
36
- Or without installing:
37
-
38
- ```bash
39
- npx @kraftapps-ai/kai init
40
- npx @kraftapps-ai/kai plan "add auth"
41
- npx @kraftapps-ai/kai go
17
+ You ←→ Kai (PM) # brainstorm, plan, decide
18
+
19
+ kai.json # stories with acceptance criteria
20
+
21
+ ┌────────┴────────┐
22
+ │ Developer AI │ # implements one story at a time
23
+ │ (claude -p) │
24
+ └────────┬────────┘
25
+
26
+ ┌────────┴────────┐
27
+ │ Reviewer AI │ # verifies each criterion independently
28
+ │ (claude -p) │
29
+ └────────┬────────┘
30
+
31
+ Committed code # repeat until all stories done
42
32
  ```
43
33
 
44
- **Requirements:** `claude` CLI ([Claude Code](https://claude.ai/claude-code)), `jq`, `git`
45
-
46
- ## Quick start
34
+ ## Usage
47
35
 
48
36
  ```bash
49
37
  cd your-project
38
+ kai
39
+ ```
50
40
 
51
- # Initialize
52
- kai init
41
+ That's it. Kai will:
53
42
 
54
- # Add your project context (tech stack, build commands, conventions)
55
- vim .kai/PROMPT.md
43
+ 1. Auto-initialize if this is a new project
44
+ 2. Ask what you want to build
45
+ 3. Help you refine the idea and break it into stories
46
+ 4. Write the stories to `kai.json`
47
+ 5. When you say "go" — dispatch the AI developer loop
48
+ 6. Report back when everything is done
56
49
 
57
- # Plan with AI PMbrainstorm, refine, generate stories
58
- kai plan "add user authentication with OAuth"
59
- # → AI generates stories → confirms → adds to kai.json
50
+ Next time you run `kai`, it picks up where you left off reads `kai.json` for stories and `kai-progress.txt` for what's been done.
60
51
 
61
- # Check what's queued
62
- kai status
52
+ ## Example
63
53
 
64
- # Let Kai implement everything
65
- kai go
66
54
  ```
67
-
68
- ## Commands
69
-
70
- | Command | Description |
71
- |---|---|
72
- | `kai init` | Initialize kai in the current project |
73
- | `kai plan "topic"` | AI PM generates stories and adds them to kai.json |
74
- | `kai go` | Run the implement + review loop |
75
- | `kai status` | Show progress and remaining stories |
76
- | `kai reset <id>` | Reset a story to incomplete |
77
- | `kai help` | Show help |
55
+ $ kai
56
+ > I want to add Stripe payments to my Next.js app
57
+
58
+ Kai: Let me break that down. A few questions first:
59
+ - Checkout or subscriptions?
60
+ - Do you need a customer portal?
61
+ ...
62
+
63
+ > Just one-time checkout for now. Ship it.
64
+
65
+ Kai: Created 8 stories in kai.json. Starting the dev loop...
66
+ #1: Add Stripe SDK and env config
67
+ #2: Create checkout API route
68
+ #3: Add checkout button component
69
+ ...
70
+ All 8 stories complete!
71
+ ```
78
72
 
79
73
  ## Files
80
74
 
81
- After `kai init`, your project gets:
82
-
83
75
  ```
84
76
  your-project/
85
- ├── kai.json # Stories (version control this)
86
- ├── kai-progress.txt # Implementation log (version control this)
77
+ ├── kai.json # Stories (version control this)
78
+ ├── kai-progress.txt # Implementation log
87
79
  └── .kai/
88
- ├── PROMPT.md # Instructions for Claude (customize this!)
89
- └── context.txt # Optional: extra files to include (one per line)
80
+ ├── PROMPT.md # Project context (edit this!)
81
+ ├── loop.sh # Implementation loop (auto-generated)
82
+ ├── loop.log # Loop output
83
+ └── context.txt # Optional: extra files to include
90
84
  ```
91
85
 
92
- ### Adding project context
86
+ ### Project context
93
87
 
94
- Edit `.kai/PROMPT.md` to include your project's specifics — tech stack, file structure, build commands, coding conventions. The more context you give, the better Kai performs.
88
+ Edit `.kai/PROMPT.md` with your tech stack, build commands, and conventions. Kai reads this on every startup and passes it to the developer AI.
95
89
 
96
- ### Extra context files
97
-
98
- Create `.kai/context.txt` with paths to files that should be included in every iteration:
99
-
100
- ```
101
- AGENTS.md
102
- docs/ARCHITECTURE.md
103
- ```
90
+ ## Install
104
91
 
105
- ## Story format
106
-
107
- ```json
108
- {
109
- "id": 1,
110
- "title": "Add user login page",
111
- "description": "Create a login page with email/password",
112
- "acceptanceCriteria": [
113
- "Login page renders at /login",
114
- "Email and password fields present",
115
- "App builds successfully"
116
- ],
117
- "priority": 1,
118
- "passes": false
119
- }
92
+ ```bash
93
+ npm i -g @kraftapps-ai/kai
120
94
  ```
121
95
 
122
- Stories are processed in `priority` order (lowest first). The `passes` flag is set to `true` by the implementer and verified by the reviewer.
123
-
124
- ## The review step
125
-
126
- After the implementer commits, Kai dispatches a **separate Claude instance** as a reviewer. The reviewer:
127
-
128
- 1. Reads the actual git diff (not the implementer's self-report)
129
- 2. Verifies each acceptance criterion against the code
130
- 3. Is explicitly told: *"Do NOT trust the implementer. Verify independently."*
131
-
132
- If the review fails, the story is reset to `passes: false` and the feedback is appended to `kai-progress.txt` so the next iteration sees what went wrong.
96
+ Or without installing:
133
97
 
134
- After 3 consecutive failures on the same story, Kai skips it with a `concerns` flag and moves on.
98
+ ```bash
99
+ npx @kraftapps-ai/kai
100
+ ```
135
101
 
136
- ## Rationalization blockers
102
+ **Requirements:** [Claude Code](https://claude.ai/claude-code) CLI, `jq`, `git`
137
103
 
138
- The prompt includes a table of common ways AI agents cheat, with counters:
104
+ ## Context window
139
105
 
140
- - "This is already implemented" Verify. Read the code.
141
- - "I'll just mark it complete" → Every story needs real code changes.
142
- - "The build passes so it works" → Build ≠ correct behavior.
143
- - "This is close enough" → Partial = broken.
106
+ All state lives in files (`kai.json`, `kai-progress.txt`). When your session gets long, just exit and run `kai` again — it reads the files and picks up where you left off. No state is lost.
144
107
 
145
- Inspired by [Superpowers](https://github.com/obra/superpowers).
108
+ The developer loop already handles this by design — each story is a fresh `claude -p` call with a clean context window.
146
109
 
147
- ## Tips
110
+ ## The review step
148
111
 
149
- - **Write good acceptance criteria.** "App builds successfully" should always be the last criterion.
150
- - **Keep stories small.** 5-15 minutes of work each. Kai does better with many small stories than few large ones.
151
- - **Add build/test commands** to `.kai/PROMPT.md` so Kai knows how to verify.
152
- - **Use `kai status`** to monitor progress, or `git log --oneline` to see commits.
153
- - **Run overnight.** `nohup kai go > kai.log 2>&1 &` and check in the morning.
112
+ After each story is implemented, a separate Claude instance reviews the code:
154
113
 
155
- ## Cost
114
+ 1. Reads the actual git diff (not the implementer's self-report)
115
+ 2. Verifies each acceptance criterion
116
+ 3. Is told: *"Be skeptical. The implementer may have cut corners."*
156
117
 
157
- Each story costs roughly 2 Claude API calls (1 implement + 1 review). A 20-story project runs ~40 calls. At current Claude pricing, that's a few dollars total.
118
+ Failed reviews reset the story and feed back the failure reason for the next attempt. After 3 failures, the story is skipped.
158
119
 
159
120
  ## License
160
121
 
package/kai CHANGED
@@ -1,495 +1,237 @@
1
1
  #!/bin/bash
2
- # Kai — Autonomous AI developer loop for Claude Code
2
+ # Kai — Your AI product manager and development team
3
3
  # https://github.com/kraftapps-ai/kai
4
4
  #
5
- # Usage:
6
- # kai — Show help
7
- # kai init — Initialize kai in current project
8
- # kai plan [topic] — Interactive brainstorm with AI PM, generates stories
9
- # kai import — Import stories from JSON
10
- # kai go — Run the implement + review loop
11
- # kai status — Show remaining stories
12
- # kai reset <id> — Reset a story to incomplete
5
+ # Just run: kai
13
6
 
14
7
  set -e
15
8
 
16
- KAI_DIR="$(cd "$(dirname "$0")" && pwd)"
17
- PROJECT_DIR="$(pwd)"
18
9
  PRD_FILE="kai.json"
19
10
  PROGRESS_FILE="kai-progress.txt"
20
11
  PROMPT_FILE=".kai/PROMPT.md"
12
+ LOOP_SCRIPT=".kai/loop.sh"
21
13
 
22
- # ── Help ───────────────────────────────────────────────
14
+ # ── Auto-init if needed ───────────────────────────────
23
15
 
24
- cmd_help() {
25
- cat << 'EOF'
26
- Kai — Autonomous AI developer loop for Claude Code
16
+ if [ ! -f "$PRD_FILE" ]; then
17
+ mkdir -p .kai
27
18
 
28
- Commands:
29
- kai init Initialize kai in the current project
30
- kai plan "topic" AI generates stories from your description
31
- kai go Run the implement + review loop
32
- kai status Show progress and remaining stories
33
- kai reset <id> Reset a story to incomplete
34
- kai help Show this help
19
+ cat > "$PRD_FILE" << 'EOF'
20
+ {
21
+ "branchName": "main",
22
+ "userStories": []
23
+ }
24
+ EOF
35
25
 
36
- Workflow:
37
- 1. kai init # setup
38
- 2. vim .kai/PROMPT.md # add project context
39
- 3. kai plan "add user auth" # AI generates stories
40
- 4. kai go # AI implements everything
26
+ echo "# Kai Progress Log" > "$PROGRESS_FILE"
41
27
 
42
- Requirements: claude (Claude Code CLI), jq, git
28
+ cat > "$PROMPT_FILE" << 'EOF'
29
+ # Project Context
43
30
 
44
- https://github.com/kraftapps-ai/kai
45
- EOF
46
- }
31
+ Add your project-specific context here. The more you provide, the better Kai performs.
47
32
 
48
- # ── Commands ───────────────────────────────────────────
33
+ ## Tech stack
34
+ <!-- e.g., React + TypeScript, Laravel, Python Flask -->
49
35
 
50
- cmd_init() {
51
- if [ -f "$PRD_FILE" ]; then
52
- echo "kai.json already exists. Aborting."
53
- exit 1
54
- fi
36
+ ## Build command
37
+ <!-- e.g., npm run build, cargo build, go build -->
55
38
 
56
- mkdir -p .kai
39
+ ## Test command
40
+ <!-- e.g., npm test, pytest, go test ./... -->
57
41
 
58
- cat > "$PRD_FILE" << 'JSONEOF'
59
- {
60
- "branchName": "main",
61
- "userStories": []
62
- }
63
- JSONEOF
42
+ ## Project structure
43
+ <!-- Key directories and files -->
64
44
 
65
- echo "# Kai Progress Log" > "$PROGRESS_FILE"
66
- echo "" >> "$PROGRESS_FILE"
45
+ ## Conventions
46
+ <!-- Coding style, naming, patterns -->
47
+ EOF
48
+ fi
49
+
50
+ # ── Create the implementation loop script ─────────────
51
+
52
+ cat > "$LOOP_SCRIPT" << 'LOOPEOF'
53
+ #!/bin/bash
54
+ # Kai implementation loop — called by the PM when stories are ready
55
+ set -e
56
+
57
+ PRD_FILE="kai.json"
58
+ PROGRESS_FILE="kai-progress.txt"
59
+ PROMPT_FILE=".kai/PROMPT.md"
67
60
 
68
- cat > "$PROMPT_FILE" << 'PROMPTEOF'
69
- You are an autonomous AI developer.
61
+ WORKER_PROMPT='You are an autonomous AI developer.
70
62
 
71
63
  ## Your inputs
72
64
  - `@kai.json` — user stories with `passes: true/false`.
73
- - `@kai-progress.txt` — append-only log of what's been done.
65
+ - `@kai-progress.txt` — log of what has been done.
74
66
 
75
67
  ## Your task (ONE story per loop)
76
68
 
77
- 1. Read kai.json and find the highest-priority story where `passes: false`.
78
- 2. Read kai-progress.txt to understand what's already been done.
79
- 3. **PLAN before coding.** List the files you'll change and what you'll do in each.
69
+ 1. Read kai.json, find the highest-priority story where `passes: false`.
70
+ 2. Read kai-progress.txt for context on previous work.
71
+ 3. **PLAN before coding.** List files and changes before touching code.
80
72
  4. Implement ONLY that one story.
81
- 5. Run verification (build, tests, lint — whatever applies).
82
- 6. **SELF-REVIEW.** For each acceptance criterion, state what you did and cite evidence (file, line, command output). Do NOT use "should work", "probably", or "seems to".
83
- 7. If all criteria pass, commit with a descriptive message.
73
+ 5. Run verification (build, tests, lint).
74
+ 6. **SELF-REVIEW.** For each acceptance criterion, cite evidence (file, line, command output). No "should work" or "probably".
75
+ 7. Commit with a descriptive message.
84
76
  8. Update kai.json: set `passes` to `true`.
85
- 9. Append to kai-progress.txt: what you did, what you learned.
86
-
87
- ## Verification Protocol
88
-
89
- - Run the project's build/test command and read the output.
90
- - You cannot claim a criterion is met without evidence.
91
- - "I added the component" is NOT evidence. "I added FooComponent at src/Foo.tsx:45 and the build passes" IS evidence.
77
+ 9. Append to kai-progress.txt.
92
78
 
93
79
  ## Rules
94
-
95
- - ONE STORY PER LOOP. Do not work on multiple stories.
96
- - Search the codebase before assuming anything.
97
- - No placeholder implementations. Fully implement or report BLOCKED.
80
+ - ONE STORY PER LOOP.
81
+ - No placeholders. Fully implement or report BLOCKED.
98
82
  - Do not break existing functionality.
99
- - Keep commits atomic — one commit per story.
100
83
  - If ALL stories have `passes: true`, output: <promise>COMPLETE</promise>
101
84
 
102
85
  ## Rationalization Blockers
103
-
104
- | Your thought | Why it's wrong | Do this instead |
86
+ | Thought | Reality | Action |
105
87
  |---|---|---|
106
- | "This story is already implemented" | You haven't verified. | Read every criterion, find the code, run the build. |
107
- | "I'll just mark it complete" | A commit with only kai.json changes is wrong. | Every story needs real code changes. |
108
- | "The build passes so it works" | Build ≠ correct behavior. | Verify each criterion independently. |
109
- | "I'll fix other issues I noticed" | Scope creep introduces bugs. | Only implement the current story. |
110
- | "This is close enough" | Partial = broken for the user. | Implement ALL criteria or report BLOCKED. |
111
- | "I'll skip the review, it's simple" | Simple code has bugs too. | Always self-review against criteria. |
112
- | "I need to refactor first" | Refactoring without a story = scope creep. | Only refactor if the story requires it. |
113
-
114
- ## Status Reporting
115
-
116
- - **DONE** — All criteria met, build passes, committed.
117
- - **DONE_WITH_CONCERNS** — Completed but something feels off. Document in `concerns` field.
118
- - **BLOCKED** — Cannot complete. Document why in kai-progress.txt.
119
- - **NEEDS_CONTEXT** — Missing information. Document in kai-progress.txt.
120
- PROMPTEOF
121
-
122
- echo "Kai initialized."
123
- echo ""
124
- echo " Created: kai.json, kai-progress.txt, .kai/PROMPT.md"
125
- echo ""
126
- echo "Next:"
127
- echo " 1. Edit .kai/PROMPT.md with your project context"
128
- echo " 2. kai plan \"what you want to build\""
129
- echo " 3. kai go"
130
- }
88
+ | "Already implemented" | You have not verified. | Read code, run build. |
89
+ | "Just mark complete" | No code changes = not done. | Implement it. |
90
+ | "Build passes = works" | Build ≠ correct. | Check each criterion. |
91
+ | "Close enough" | Partial = broken. | All criteria or BLOCKED. |
92
+ | "Skip review" | Simple code has bugs. | Always self-review. |'
93
+
94
+ context_files="@${PROMPT_FILE} @${PRD_FILE} @${PROGRESS_FILE}"
95
+ if [ -f ".kai/context.txt" ]; then
96
+ while IFS= read -r file; do
97
+ [ -n "$file" ] && [ -f "$file" ] && context_files="$context_files @${file}"
98
+ done < .kai/context.txt
99
+ fi
100
+
101
+ iteration=0
102
+ review_failures=0
103
+
104
+ while :; do
105
+ iteration=$((iteration + 1))
106
+ REMAINING=$(jq '[.userStories[] | select(.passes == false)] | length' "$PRD_FILE")
107
+
108
+ if [ "$REMAINING" -eq 0 ]; then
109
+ echo "All stories complete!"
110
+ break
111
+ fi
131
112
 
132
- cmd_plan() {
133
- topic="${1:-}"
113
+ NEXT_ID=$(jq -r '[.userStories[] | select(.passes == false)] | sort_by(.priority) | .[0].id' "$PRD_FILE")
114
+ NEXT=$(jq -r '[.userStories[] | select(.passes == false)] | sort_by(.priority) | .[0].title' "$PRD_FILE")
134
115
 
135
- if [ ! -f "$PRD_FILE" ]; then
136
- echo "kai.json not found. Run 'kai init' first."
137
- exit 1
138
- fi
116
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
117
+ echo "#${iteration} $(date)"
118
+ echo " Remaining: $REMAINING | Next: $NEXT"
119
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
139
120
 
140
- # Build context about existing stories
141
- existing=""
142
- story_count=$(jq '.userStories | length' "$PRD_FILE")
143
- if [ "$story_count" -gt 0 ]; then
144
- existing="
121
+ start_time=$(date +%s)
145
122
 
146
- Existing stories in kai.json (don't duplicate these):
147
- $(jq -r '.userStories[] | "- [\(if .passes then "done" else "todo" end)] \(.title)"' "$PRD_FILE")"
148
- fi
123
+ set +e
124
+ result=$(claude -p --dangerously-skip-permissions $context_files)
125
+ exit_code=$?
126
+ set -e
149
127
 
150
- # Build context about the project
151
- project_context=""
152
- if [ -f "$PROMPT_FILE" ]; then
153
- project_context="
128
+ elapsed=$(( $(date +%s) - start_time ))
129
+ echo "$result" | tail -20
154
130
 
155
- Project context from .kai/PROMPT.md:
156
- $(cat "$PROMPT_FILE")"
131
+ if [ $exit_code -ne 0 ]; then
132
+ echo "Failed (code ${exit_code}). Restarting..."
133
+ continue
157
134
  fi
158
135
 
159
- # PM system prompt
160
- pm_prompt="You are a senior product manager and technical architect. You're planning work with a developer.
161
-
162
- Your job:
163
- 1. Understand what they want to build or improve
164
- 2. Ask clarifying questions (target user, constraints, scope)
165
- 3. Break the work into small, implementable stories (5-15 min each)
166
- 4. Each story needs: title, description, and specific acceptance criteria
167
- 5. Stories should be ordered by dependency (build foundations first)
168
-
169
- Rules for good stories:
170
- - Each story should be independently committable
171
- - Last acceptance criterion should always be \"App builds successfully\" or equivalent
172
- - Acceptance criteria must be verifiable (not vague like \"looks good\")
173
- - Keep stories small — if it takes more than 15 min, split it
174
- - Include edge cases and error handling as separate stories
175
- - Don't forget: tests, error states, loading states, empty states
176
-
177
- When the user is happy with the plan, output the stories in this EXACT format — one JSON block with all stories:
178
-
179
- \`\`\`kai-stories
180
- [
181
- {
182
- \"title\": \"Story title here\",
183
- \"description\": \"What to implement and why\",
184
- \"acceptanceCriteria\": [\"Criterion 1\", \"Criterion 2\", \"App builds successfully\"]
185
- }
186
- ]
187
- \`\`\`
188
-
189
- The user will say \"looks good\" or \"ship it\" when they want you to output the final stories.
190
- ${existing}${project_context}"
191
-
192
- # Generate a session ID so we can find the transcript after
193
- SESSION_ID=$(python3 -c "import uuid; print(uuid.uuid4())" 2>/dev/null || uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null)
194
-
195
- if [ -n "$topic" ]; then
196
- echo "Planning: $topic"
197
- echo "Say 'ship it' when you're happy with the stories."
198
- echo ""
199
- claude --session-id "$SESSION_ID" --system-prompt "$pm_prompt" "Let's plan: $topic"
200
- else
201
- echo "Describe what you want to build. Say 'ship it' when ready."
202
- echo ""
203
- claude --session-id "$SESSION_ID" --system-prompt "$pm_prompt"
136
+ if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
137
+ echo "All stories complete after $iteration iterations!"
138
+ exit 0
204
139
  fi
205
140
 
206
- # After session ends, find the transcript and extract stories
207
- echo ""
208
- echo "Scanning session for stories..."
209
-
210
- # Find the project transcript directory
211
- project_dir=$(echo "$PROJECT_DIR" | sed 's|/|-|g; s|^-||')
212
- transcript=""
213
- for dir in ~/.claude/projects/*/; do
214
- if [ -f "${dir}${SESSION_ID}.jsonl" ]; then
215
- transcript="${dir}${SESSION_ID}.jsonl"
216
- break
217
- fi
218
- done
141
+ # Review
142
+ STORY_PASSES=$(jq -r ".userStories[] | select(.id == $NEXT_ID) | .passes" "$PRD_FILE")
143
+ if [ "$STORY_PASSES" = "true" ]; then
144
+ last_commit=$(git log --oneline -1 2>/dev/null || echo "no git")
145
+ ACCEPTANCE=$(jq -r ".userStories[] | select(.id == $NEXT_ID) | .acceptanceCriteria | join(\"\n- \")" "$PRD_FILE")
219
146
 
220
- if [ -z "$transcript" ] || [ ! -f "$transcript" ]; then
221
- echo "Could not find session transcript."
222
- echo "If stories were generated, you can manually add them to kai.json."
223
- return
224
- fi
147
+ set +e
148
+ review=$(claude -p --dangerously-skip-permissions \
149
+ "You are a code reviewer. Story #${NEXT_ID} ('${NEXT}') claims complete.
150
+ Last commit: ${last_commit}
151
+ Acceptance criteria:
152
+ - ${ACCEPTANCE}
153
+ Read git diff HEAD~1 HEAD. Verify EACH criterion. Be skeptical.
154
+ If ANY fails: REVIEW_FAIL: [reason]
155
+ If all pass: REVIEW_PASS")
156
+ set -e
225
157
 
226
- # Extract kai-stories JSON from the transcript
227
- stories_json=$(python3 -c "
228
- import json, re, sys
229
-
230
- stories = None
231
- with open('$transcript') as f:
232
- for line in f:
233
- try:
234
- d = json.loads(line)
235
- if d.get('type') == 'assistant':
236
- content = d.get('message', {}).get('content', [])
237
- if isinstance(content, list):
238
- for c in content:
239
- if c.get('type') == 'text':
240
- text = c['text']
241
- # Find kai-stories block
242
- match = re.search(r'\`\`\`kai-stories\s*\n(.*?)\n\`\`\`', text, re.DOTALL)
243
- if match:
244
- stories = match.group(1)
245
- except: pass
246
-
247
- if stories:
248
- # Validate it's valid JSON
249
- parsed = json.loads(stories)
250
- print(json.dumps(parsed))
251
- " 2>/dev/null)
252
-
253
- if [ -n "$stories_json" ] && echo "$stories_json" | jq empty 2>/dev/null; then
254
- count=$(echo "$stories_json" | jq 'length')
255
- echo ""
256
- echo "Found ${count} stories:"
257
- echo "$stories_json" | jq -r '.[] | " - \(.title)"'
258
- echo ""
259
- echo "Add to kai.json? (y/n)"
260
- read -r confirm
261
- if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ] || [ "$confirm" = "" ]; then
262
- _import_stories "$stories_json"
158
+ echo "$review" | tail -5
159
+
160
+ if [[ "$review" == *"REVIEW_FAIL"* ]]; then
161
+ jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
162
+ echo "REVIEW FEEDBACK: $review" >> "$PROGRESS_FILE"
163
+ review_failures=$((review_failures + 1))
164
+ [ $review_failures -ge 3 ] && {
165
+ jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = true' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
166
+ review_failures=0
167
+ }
263
168
  else
264
- echo "Skipped."
169
+ review_failures=0
265
170
  fi
266
- else
267
- echo "No stories found in session."
268
- echo "If the PM generated stories, you can copy the JSON and add manually to kai.json."
269
- fi
270
- }
271
-
272
- _import_stories() {
273
- local stories_json="$1"
274
-
275
- if ! echo "$stories_json" | jq empty 2>/dev/null; then
276
- echo "Invalid JSON."
277
- return 1
278
171
  fi
279
172
 
280
- max_id=$(jq '[.userStories[].id] | max // 0' "$PRD_FILE")
281
- count=$(echo "$stories_json" | jq 'length')
282
-
283
- echo "$stories_json" | jq -c '.[]' | while IFS= read -r story; do
284
- max_id=$((max_id + 1))
285
- title=$(echo "$story" | jq -r '.title')
286
- desc=$(echo "$story" | jq -r '.description')
287
- criteria=$(echo "$story" | jq '.acceptanceCriteria')
288
-
289
- jq --arg title "$title" \
290
- --arg desc "$desc" \
291
- --argjson id "$max_id" \
292
- --argjson criteria "$criteria" \
293
- '.userStories += [{
294
- id: $id,
295
- title: $title,
296
- description: $desc,
297
- acceptanceCriteria: $criteria,
298
- priority: $id,
299
- passes: false
300
- }]' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
301
-
302
- echo " #${max_id}: ${title}"
303
- done
304
-
173
+ echo "Done in $((elapsed / 60))m $((elapsed % 60))s"
305
174
  echo ""
306
- echo "Added ${count} stories."
307
- }
175
+ done
176
+ LOOPEOF
177
+ chmod +x "$LOOP_SCRIPT"
308
178
 
309
- cmd_status() {
310
- if [ ! -f "$PRD_FILE" ]; then
311
- echo "kai.json not found. Run 'kai init' first."
312
- exit 1
313
- fi
179
+ # ── Build status summary ──────────────────────────────
314
180
 
181
+ status=""
182
+ if [ -f "$PRD_FILE" ]; then
315
183
  total=$(jq '.userStories | length' "$PRD_FILE")
316
184
  done_count=$(jq '[.userStories[] | select(.passes == true)] | length' "$PRD_FILE")
317
185
  remaining=$((total - done_count))
186
+ if [ "$total" -gt 0 ]; then
187
+ status="
318
188
 
319
- echo "Kai: ${done_count}/${total} complete (${remaining} remaining)"
320
- echo ""
321
-
322
- if [ "$remaining" -gt 0 ]; then
323
- echo "Remaining:"
324
- jq -r '.userStories[] | select(.passes == false) | " \(.id): \(.title)"' "$PRD_FILE"
325
- fi
326
- }
327
-
328
- cmd_reset() {
329
- id="$1"
330
- if [ -z "$id" ]; then
331
- echo "Usage: kai reset <story-id>"
332
- exit 1
189
+ Current progress: ${done_count}/${total} stories complete (${remaining} remaining).
190
+ $(jq -r '.userStories[] | "- [\(if .passes then "DONE" else "TODO" end)] #\(.id): \(.title)"' "$PRD_FILE")"
333
191
  fi
192
+ fi
334
193
 
335
- jq --argjson id "$id" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
336
- echo "Reset story #${id}."
337
- }
338
-
339
- cmd_go() {
340
- if [ ! -f "$PRD_FILE" ]; then
341
- echo "kai.json not found. Run 'kai init' first."
342
- exit 1
343
- fi
194
+ project_context=""
195
+ [ -f "$PROMPT_FILE" ] && project_context="
344
196
 
345
- if [ ! -f "$PROMPT_FILE" ]; then
346
- echo ".kai/PROMPT.md not found. Run 'kai init' first."
347
- exit 1
348
- fi
349
-
350
- # Collect context files
351
- context_files="@${PROMPT_FILE} @${PRD_FILE} @${PROGRESS_FILE}"
352
- if [ -f ".kai/context.txt" ]; then
353
- while IFS= read -r file; do
354
- [ -n "$file" ] && [ -f "$file" ] && context_files="$context_files @${file}"
355
- done < .kai/context.txt
356
- fi
357
-
358
- echo "Starting Kai..."
359
- echo " Stories remaining: $(jq '[.userStories[] | select(.passes == false)] | length' "$PRD_FILE")"
360
- echo " Ctrl+C to stop"
361
- echo ""
362
-
363
- iteration=0
364
- review_failures=0
365
-
366
- while :; do
367
- iteration=$((iteration + 1))
368
- REMAINING=$(jq '[.userStories[] | select(.passes == false)] | length' "$PRD_FILE")
369
-
370
- if [ "$REMAINING" -eq 0 ]; then
371
- echo "All stories complete!"
372
- break
373
- fi
374
-
375
- NEXT_ID=$(jq -r '[.userStories[] | select(.passes == false)] | sort_by(.priority) | .[0].id' "$PRD_FILE")
376
- NEXT=$(jq -r '[.userStories[] | select(.passes == false)] | sort_by(.priority) | .[0].title' "$PRD_FILE")
377
-
378
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
379
- echo "#${iteration} — $(date)"
380
- echo " Remaining: $REMAINING | Next: $NEXT"
381
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
382
-
383
- start_time=$(date +%s)
384
-
385
- # ── Implement ──────────────────────────────────
386
- set +e
387
- result=$(claude -p \
388
- --dangerously-skip-permissions \
389
- $context_files)
390
- exit_code=$?
391
- set -e
392
-
393
- end_time=$(date +%s)
394
- elapsed=$(( end_time - start_time ))
395
- minutes=$(( elapsed / 60 ))
396
- seconds=$(( elapsed % 60 ))
197
+ Project context (.kai/PROMPT.md):
198
+ $(cat "$PROMPT_FILE")"
397
199
 
398
- echo "$result" | tail -20
399
- echo ""
200
+ progress=""
201
+ [ -f "$PROGRESS_FILE" ] && [ "$(wc -l < "$PROGRESS_FILE")" -gt 2 ] && progress="
400
202
 
401
- if [ $exit_code -ne 0 ]; then
402
- echo "Iteration #${iteration} failed (code ${exit_code}). Restarting..."
403
- continue
404
- fi
203
+ Recent progress (kai-progress.txt):
204
+ $(tail -30 "$PROGRESS_FILE")"
405
205
 
406
- if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
407
- echo "All stories complete after $iteration iterations!"
408
- exit 0
409
- fi
206
+ # ── Launch the PM ─────────────────────────────────────
410
207
 
411
- # ── Review ─────────────────────────────────────
412
- STORY_PASSES=$(jq -r ".userStories[] | select(.id == $NEXT_ID) | .passes" "$PRD_FILE")
413
-
414
- if [ "$STORY_PASSES" = "true" ]; then
415
- last_commit=$(git log --oneline -1 2>/dev/null || echo "no git")
416
- last_diff_stat=$(git diff --stat HEAD~1 HEAD 2>/dev/null | tail -1)
417
-
418
- # Sanity: real code changes?
419
- if [ -z "$last_diff_stat" ] || [[ "$last_diff_stat" == *"0 insertions"*"0 deletions"* ]]; then
420
- echo "REVIEW FAIL: No code changes in commit!"
421
- jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
422
- review_failures=$((review_failures + 1))
423
- if [ $review_failures -ge 3 ]; then
424
- echo "3 failures on story #${NEXT_ID}. Skipping."
425
- jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = true | (.userStories[] | select(.id == $id)).concerns = "Skipped after 3 failures"' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
426
- review_failures=0
427
- fi
428
- continue
429
- fi
430
-
431
- # Dispatch reviewer
432
- echo "Reviewing story #${NEXT_ID}..."
433
- ACCEPTANCE=$(jq -r ".userStories[] | select(.id == $NEXT_ID) | .acceptanceCriteria | join(\"\n- \")" "$PRD_FILE")
434
-
435
- set +e
436
- review_result=$(claude -p \
437
- --dangerously-skip-permissions \
438
- "You are a code reviewer. The implementer claims story #${NEXT_ID} ('${NEXT}') is complete.
439
-
440
- Last commit: ${last_commit}
441
- Changes: ${last_diff_stat}
208
+ exec claude --system-prompt "You are Kai — an AI product manager and tech lead. You work directly with the developer to plan and ship software.
442
209
 
443
- Acceptance criteria:
444
- - ${ACCEPTANCE}
210
+ ## What you can do
445
211
 
446
- Instructions:
447
- 1. Read the changed files (git diff HEAD~1 HEAD).
448
- 2. For EACH criterion, verify it is met by the actual code. Be skeptical.
449
- 3. Run the build/test command if applicable.
450
- 4. If ANY criterion is not met: REVIEW_FAIL: [which criterion and why]
451
- 5. If all criteria met: REVIEW_PASS
452
-
453
- Do NOT trust the implementer's self-report. Verify independently.")
454
- review_exit=$?
455
- set -e
456
-
457
- echo "$review_result" | tail -10
458
-
459
- if [[ "$review_result" == *"REVIEW_FAIL"* ]]; then
460
- echo "Review failed!"
461
- jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
462
- echo "" >> "$PROGRESS_FILE"
463
- echo "## REVIEW FEEDBACK for Story $NEXT_ID" >> "$PROGRESS_FILE"
464
- echo "$review_result" | grep -i "REVIEW_FAIL" >> "$PROGRESS_FILE" 2>/dev/null
465
- review_failures=$((review_failures + 1))
466
- if [ $review_failures -ge 3 ]; then
467
- echo "3 review failures on story #${NEXT_ID}. Skipping."
468
- jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = true | (.userStories[] | select(.id == $id)).concerns = "Passed after 3 review attempts"' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
469
- review_failures=0
470
- fi
471
- else
472
- echo "Review passed."
473
- review_failures=0
474
- fi
475
- fi
212
+ 1. **Brainstorm** — Help the developer think through ideas, make decisions, define scope
213
+ 2. **Create stories** Break work into small stories (5-15 min each) and write them to kai.json
214
+ 3. **Run the dev loop** Execute \`.kai/loop.sh\` to have an AI developer implement all stories autonomously
215
+ 4. **Check progress** Read kai.json and kai-progress.txt to report status
216
+ 5. **Adjust the plan** Edit stories, reprioritize, add new ones, reset failed ones
476
217
 
477
- echo "Iteration #${iteration} done in ${minutes}m ${seconds}s"
478
- last_commit=$(git log --oneline -1 2>/dev/null || echo "")
479
- [ -n "$last_commit" ] && echo " Last commit: ${last_commit}"
480
- echo ""
481
- done
218
+ ## How stories work
482
219
 
483
- echo "Kai finished after ${iteration} iterations."
484
- }
220
+ Stories live in kai.json. Each has: id, title, description, acceptanceCriteria, priority, passes (true/false).
221
+ To add stories, edit kai.json directly using the Edit or Write tool.
222
+ To run implementation, execute: \`nohup .kai/loop.sh > .kai/loop.log 2>&1 &\` then monitor with \`tail -f .kai/loop.log\`
485
223
 
486
- # ── Main ───────────────────────────────────────────────
224
+ ## Rules for good stories
225
+ - Each story: independently committable, 5-15 min of work
226
+ - Acceptance criteria must be objectively verifiable
227
+ - Last criterion should be a build/test command passing
228
+ - Order by dependency (foundations first)
229
+ - Include error handling, edge cases as separate stories
487
230
 
488
- case "${1:-help}" in
489
- init) cmd_init ;;
490
- plan) shift; cmd_plan "$@" ;;
491
- go) cmd_go ;;
492
- status) cmd_status ;;
493
- reset) shift; cmd_reset "$@" ;;
494
- help|*) cmd_help ;;
495
- esac
231
+ ## Your personality
232
+ - You're a hands-on PM who understands code
233
+ - Be direct and concise
234
+ - Make decisions, don't just list options
235
+ - When the developer says \"ship it\" or \"go\" or \"do it\", start the loop
236
+ - Don't ask unnecessary questions — use good defaults
237
+ ${status}${project_context}${progress}" "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kraftapps-ai/kai",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Autonomous AI developer loop for Claude Code",
5
5
  "bin": {
6
6
  "kai": "kai"