@kraftapps-ai/kai 1.0.1 → 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 (3) hide show
  1. package/README.md +76 -115
  2. package/kai +166 -416
  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,488 +1,238 @@
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
- ensure_init() {
51
- [ -f "$PRD_FILE" ] && return
52
- cmd_init
53
- }
36
+ ## Build command
37
+ <!-- e.g., npm run build, cargo build, go build -->
54
38
 
55
- cmd_init() {
56
- if [ -f "$PRD_FILE" ]; then
57
- echo "Already initialized."
58
- return
59
- fi
39
+ ## Test command
40
+ <!-- e.g., npm test, pytest, go test ./... -->
60
41
 
61
- mkdir -p .kai
42
+ ## Project structure
43
+ <!-- Key directories and files -->
62
44
 
63
- cat > "$PRD_FILE" << 'JSONEOF'
64
- {
65
- "branchName": "main",
66
- "userStories": []
67
- }
68
- JSONEOF
45
+ ## Conventions
46
+ <!-- Coding style, naming, patterns -->
47
+ EOF
48
+ fi
69
49
 
70
- echo "# Kai Progress Log" > "$PROGRESS_FILE"
71
- echo "" >> "$PROGRESS_FILE"
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
72
56
 
73
- cat > "$PROMPT_FILE" << 'PROMPTEOF'
74
- You are an autonomous AI developer.
57
+ PRD_FILE="kai.json"
58
+ PROGRESS_FILE="kai-progress.txt"
59
+ PROMPT_FILE=".kai/PROMPT.md"
60
+
61
+ WORKER_PROMPT='You are an autonomous AI developer.
75
62
 
76
63
  ## Your inputs
77
64
  - `@kai.json` — user stories with `passes: true/false`.
78
- - `@kai-progress.txt` — append-only log of what's been done.
65
+ - `@kai-progress.txt` — log of what has been done.
79
66
 
80
67
  ## Your task (ONE story per loop)
81
68
 
82
- 1. Read kai.json and find the highest-priority story where `passes: false`.
83
- 2. Read kai-progress.txt to understand what's already been done.
84
- 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.
85
72
  4. Implement ONLY that one story.
86
- 5. Run verification (build, tests, lint — whatever applies).
87
- 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".
88
- 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.
89
76
  8. Update kai.json: set `passes` to `true`.
90
- 9. Append to kai-progress.txt: what you did, what you learned.
91
-
92
- ## Verification Protocol
93
-
94
- - Run the project's build/test command and read the output.
95
- - You cannot claim a criterion is met without evidence.
96
- - "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.
97
78
 
98
79
  ## Rules
99
-
100
- - ONE STORY PER LOOP. Do not work on multiple stories.
101
- - Search the codebase before assuming anything.
102
- - No placeholder implementations. Fully implement or report BLOCKED.
80
+ - ONE STORY PER LOOP.
81
+ - No placeholders. Fully implement or report BLOCKED.
103
82
  - Do not break existing functionality.
104
- - Keep commits atomic — one commit per story.
105
83
  - If ALL stories have `passes: true`, output: <promise>COMPLETE</promise>
106
84
 
107
85
  ## Rationalization Blockers
108
-
109
- | Your thought | Why it's wrong | Do this instead |
86
+ | Thought | Reality | Action |
110
87
  |---|---|---|
111
- | "This story is already implemented" | You haven't verified. | Read every criterion, find the code, run the build. |
112
- | "I'll just mark it complete" | A commit with only kai.json changes is wrong. | Every story needs real code changes. |
113
- | "The build passes so it works" | Build ≠ correct behavior. | Verify each criterion independently. |
114
- | "I'll fix other issues I noticed" | Scope creep introduces bugs. | Only implement the current story. |
115
- | "This is close enough" | Partial = broken for the user. | Implement ALL criteria or report BLOCKED. |
116
- | "I'll skip the review, it's simple" | Simple code has bugs too. | Always self-review against criteria. |
117
- | "I need to refactor first" | Refactoring without a story = scope creep. | Only refactor if the story requires it. |
118
-
119
- ## Status Reporting
120
-
121
- - **DONE** — All criteria met, build passes, committed.
122
- - **DONE_WITH_CONCERNS** — Completed but something feels off. Document in `concerns` field.
123
- - **BLOCKED** — Cannot complete. Document why in kai-progress.txt.
124
- - **NEEDS_CONTEXT** — Missing information. Document in kai-progress.txt.
125
- PROMPTEOF
126
-
127
- echo "Kai initialized."
128
- echo ""
129
- echo " Created: kai.json, kai-progress.txt, .kai/PROMPT.md"
130
- echo ""
131
- echo "Next:"
132
- echo " 1. Edit .kai/PROMPT.md with your project context"
133
- echo " 2. kai plan \"what you want to build\""
134
- echo " 3. kai go"
135
- }
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
136
112
 
137
- cmd_plan() {
138
- ensure_init
139
- 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")
140
115
 
141
- # Build context about existing stories
142
- existing=""
143
- story_count=$(jq '.userStories | length' "$PRD_FILE")
144
- if [ "$story_count" -gt 0 ]; then
145
- existing="
116
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
117
+ echo "#${iteration} — $(date)"
118
+ echo " Remaining: $REMAINING | Next: $NEXT"
119
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
146
120
 
147
- Existing stories in kai.json (don't duplicate these):
148
- $(jq -r '.userStories[] | "- [\(if .passes then "done" else "todo" end)] \(.title)"' "$PRD_FILE")"
149
- fi
121
+ start_time=$(date +%s)
150
122
 
151
- # Build context about the project
152
- project_context=""
153
- if [ -f "$PROMPT_FILE" ]; then
154
- project_context="
123
+ set +e
124
+ result=$(claude -p --dangerously-skip-permissions $context_files)
125
+ exit_code=$?
126
+ set -e
155
127
 
156
- Project context from .kai/PROMPT.md:
157
- $(cat "$PROMPT_FILE")"
128
+ elapsed=$(( $(date +%s) - start_time ))
129
+ echo "$result" | tail -20
130
+
131
+ if [ $exit_code -ne 0 ]; then
132
+ echo "Failed (code ${exit_code}). Restarting..."
133
+ continue
158
134
  fi
159
135
 
160
- # PM system prompt
161
- pm_prompt="You are a senior product manager and technical architect. You're planning work with a developer.
162
-
163
- Your job:
164
- 1. Understand what they want to build or improve
165
- 2. Ask clarifying questions (target user, constraints, scope)
166
- 3. Break the work into small, implementable stories (5-15 min each)
167
- 4. Each story needs: title, description, and specific acceptance criteria
168
- 5. Stories should be ordered by dependency (build foundations first)
169
-
170
- Rules for good stories:
171
- - Each story should be independently committable
172
- - Last acceptance criterion should always be \"App builds successfully\" or equivalent
173
- - Acceptance criteria must be verifiable (not vague like \"looks good\")
174
- - Keep stories small — if it takes more than 15 min, split it
175
- - Include edge cases and error handling as separate stories
176
- - Don't forget: tests, error states, loading states, empty states
177
-
178
- When the user is happy with the plan, output the stories in this EXACT format — one JSON block with all stories:
179
-
180
- \`\`\`kai-stories
181
- [
182
- {
183
- \"title\": \"Story title here\",
184
- \"description\": \"What to implement and why\",
185
- \"acceptanceCriteria\": [\"Criterion 1\", \"Criterion 2\", \"App builds successfully\"]
186
- }
187
- ]
188
- \`\`\`
189
-
190
- The user will say \"looks good\" or \"ship it\" when they want you to output the final stories.
191
- ${existing}${project_context}"
192
-
193
- # Generate a session ID so we can find the transcript after
194
- 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)
195
-
196
- if [ -n "$topic" ]; then
197
- echo "Planning: $topic"
198
- echo "Say 'ship it' when you're happy with the stories."
199
- echo ""
200
- claude --session-id "$SESSION_ID" --system-prompt "$pm_prompt" "Let's plan: $topic"
201
- else
202
- echo "Describe what you want to build. Say 'ship it' when ready."
203
- echo ""
204
- 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
205
139
  fi
206
140
 
207
- # After session ends, find the transcript and extract stories
208
- echo ""
209
- echo "Scanning session for stories..."
210
-
211
- # Find the project transcript directory
212
- project_dir=$(echo "$PROJECT_DIR" | sed 's|/|-|g; s|^-||')
213
- transcript=""
214
- for dir in ~/.claude/projects/*/; do
215
- if [ -f "${dir}${SESSION_ID}.jsonl" ]; then
216
- transcript="${dir}${SESSION_ID}.jsonl"
217
- break
218
- fi
219
- 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")
220
146
 
221
- if [ -z "$transcript" ] || [ ! -f "$transcript" ]; then
222
- echo "Could not find session transcript."
223
- echo "If stories were generated, you can manually add them to kai.json."
224
- return
225
- 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
157
+
158
+ echo "$review" | tail -5
226
159
 
227
- # Extract kai-stories JSON from the transcript
228
- stories_json=$(python3 -c "
229
- import json, re, sys
230
-
231
- stories = None
232
- with open('$transcript') as f:
233
- for line in f:
234
- try:
235
- d = json.loads(line)
236
- if d.get('type') == 'assistant':
237
- content = d.get('message', {}).get('content', [])
238
- if isinstance(content, list):
239
- for c in content:
240
- if c.get('type') == 'text':
241
- text = c['text']
242
- # Find kai-stories block
243
- match = re.search(r'\`\`\`kai-stories\s*\n(.*?)\n\`\`\`', text, re.DOTALL)
244
- if match:
245
- stories = match.group(1)
246
- except: pass
247
-
248
- if stories:
249
- # Validate it's valid JSON
250
- parsed = json.loads(stories)
251
- print(json.dumps(parsed))
252
- " 2>/dev/null)
253
-
254
- if [ -n "$stories_json" ] && echo "$stories_json" | jq empty 2>/dev/null; then
255
- count=$(echo "$stories_json" | jq 'length')
256
- echo ""
257
- echo "Found ${count} stories:"
258
- echo "$stories_json" | jq -r '.[] | " - \(.title)"'
259
- echo ""
260
- echo "Add to kai.json? (y/n)"
261
- read -r confirm
262
- if [ "$confirm" = "y" ] || [ "$confirm" = "Y" ] || [ "$confirm" = "" ]; then
263
- _import_stories "$stories_json"
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
+ }
264
168
  else
265
- echo "Skipped."
169
+ review_failures=0
266
170
  fi
267
- else
268
- echo "No stories found in session."
269
- echo "If the PM generated stories, you can copy the JSON and add manually to kai.json."
270
171
  fi
271
- }
272
-
273
- _import_stories() {
274
- local stories_json="$1"
275
-
276
- if ! echo "$stories_json" | jq empty 2>/dev/null; then
277
- echo "Invalid JSON."
278
- return 1
279
- fi
280
-
281
- max_id=$(jq '[.userStories[].id] | max // 0' "$PRD_FILE")
282
- count=$(echo "$stories_json" | jq 'length')
283
-
284
- echo "$stories_json" | jq -c '.[]' | while IFS= read -r story; do
285
- max_id=$((max_id + 1))
286
- title=$(echo "$story" | jq -r '.title')
287
- desc=$(echo "$story" | jq -r '.description')
288
- criteria=$(echo "$story" | jq '.acceptanceCriteria')
289
-
290
- jq --arg title "$title" \
291
- --arg desc "$desc" \
292
- --argjson id "$max_id" \
293
- --argjson criteria "$criteria" \
294
- '.userStories += [{
295
- id: $id,
296
- title: $title,
297
- description: $desc,
298
- acceptanceCriteria: $criteria,
299
- priority: $id,
300
- passes: false
301
- }]' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
302
-
303
- echo " #${max_id}: ${title}"
304
- done
305
172
 
173
+ echo "Done in $((elapsed / 60))m $((elapsed % 60))s"
306
174
  echo ""
307
- echo "Added ${count} stories."
308
- }
175
+ done
176
+ LOOPEOF
177
+ chmod +x "$LOOP_SCRIPT"
309
178
 
310
- cmd_status() {
311
- if [ ! -f "$PRD_FILE" ]; then
312
- echo "kai.json not found. Run 'kai init' first."
313
- exit 1
314
- fi
179
+ # ── Build status summary ──────────────────────────────
315
180
 
181
+ status=""
182
+ if [ -f "$PRD_FILE" ]; then
316
183
  total=$(jq '.userStories | length' "$PRD_FILE")
317
184
  done_count=$(jq '[.userStories[] | select(.passes == true)] | length' "$PRD_FILE")
318
185
  remaining=$((total - done_count))
186
+ if [ "$total" -gt 0 ]; then
187
+ status="
319
188
 
320
- echo "Kai: ${done_count}/${total} complete (${remaining} remaining)"
321
- echo ""
322
-
323
- if [ "$remaining" -gt 0 ]; then
324
- echo "Remaining:"
325
- jq -r '.userStories[] | select(.passes == false) | " \(.id): \(.title)"' "$PRD_FILE"
326
- fi
327
- }
328
-
329
- cmd_reset() {
330
- id="$1"
331
- if [ -z "$id" ]; then
332
- echo "Usage: kai reset <story-id>"
333
- exit 1
334
- fi
335
-
336
- jq --argjson id "$id" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
337
- echo "Reset story #${id}."
338
- }
339
-
340
- cmd_go() {
341
- ensure_init
342
-
343
- # Collect context files
344
- context_files="@${PROMPT_FILE} @${PRD_FILE} @${PROGRESS_FILE}"
345
- if [ -f ".kai/context.txt" ]; then
346
- while IFS= read -r file; do
347
- [ -n "$file" ] && [ -f "$file" ] && context_files="$context_files @${file}"
348
- done < .kai/context.txt
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")"
349
191
  fi
192
+ fi
350
193
 
351
- echo "Starting Kai..."
352
- echo " Stories remaining: $(jq '[.userStories[] | select(.passes == false)] | length' "$PRD_FILE")"
353
- echo " Ctrl+C to stop"
354
- echo ""
355
-
356
- iteration=0
357
- review_failures=0
358
-
359
- while :; do
360
- iteration=$((iteration + 1))
361
- REMAINING=$(jq '[.userStories[] | select(.passes == false)] | length' "$PRD_FILE")
362
-
363
- if [ "$REMAINING" -eq 0 ]; then
364
- echo "All stories complete!"
365
- break
366
- fi
367
-
368
- NEXT_ID=$(jq -r '[.userStories[] | select(.passes == false)] | sort_by(.priority) | .[0].id' "$PRD_FILE")
369
- NEXT=$(jq -r '[.userStories[] | select(.passes == false)] | sort_by(.priority) | .[0].title' "$PRD_FILE")
370
-
371
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
372
- echo "#${iteration} — $(date)"
373
- echo " Remaining: $REMAINING | Next: $NEXT"
374
- echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
375
-
376
- start_time=$(date +%s)
377
-
378
- # ── Implement ──────────────────────────────────
379
- set +e
380
- result=$(claude -p \
381
- --dangerously-skip-permissions \
382
- $context_files)
383
- exit_code=$?
384
- set -e
194
+ project_context=""
195
+ [ -f "$PROMPT_FILE" ] && project_context="
385
196
 
386
- end_time=$(date +%s)
387
- elapsed=$(( end_time - start_time ))
388
- minutes=$(( elapsed / 60 ))
389
- seconds=$(( elapsed % 60 ))
197
+ Project context (.kai/PROMPT.md):
198
+ $(cat "$PROMPT_FILE")"
390
199
 
391
- echo "$result" | tail -20
392
- echo ""
200
+ progress=""
201
+ [ -f "$PROGRESS_FILE" ] && [ "$(wc -l < "$PROGRESS_FILE")" -gt 2 ] && progress="
393
202
 
394
- if [ $exit_code -ne 0 ]; then
395
- echo "Iteration #${iteration} failed (code ${exit_code}). Restarting..."
396
- continue
397
- fi
203
+ Recent progress (kai-progress.txt):
204
+ $(tail -30 "$PROGRESS_FILE")"
398
205
 
399
- if [[ "$result" == *"<promise>COMPLETE</promise>"* ]]; then
400
- echo "All stories complete after $iteration iterations!"
401
- exit 0
402
- fi
206
+ # ── Launch the PM ─────────────────────────────────────
403
207
 
404
- # ── Review ─────────────────────────────────────
405
- STORY_PASSES=$(jq -r ".userStories[] | select(.id == $NEXT_ID) | .passes" "$PRD_FILE")
406
-
407
- if [ "$STORY_PASSES" = "true" ]; then
408
- last_commit=$(git log --oneline -1 2>/dev/null || echo "no git")
409
- last_diff_stat=$(git diff --stat HEAD~1 HEAD 2>/dev/null | tail -1)
410
-
411
- # Sanity: real code changes?
412
- if [ -z "$last_diff_stat" ] || [[ "$last_diff_stat" == *"0 insertions"*"0 deletions"* ]]; then
413
- echo "REVIEW FAIL: No code changes in commit!"
414
- jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
415
- review_failures=$((review_failures + 1))
416
- if [ $review_failures -ge 3 ]; then
417
- echo "3 failures on story #${NEXT_ID}. Skipping."
418
- 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"
419
- review_failures=0
420
- fi
421
- continue
422
- fi
423
-
424
- # Dispatch reviewer
425
- echo "Reviewing story #${NEXT_ID}..."
426
- ACCEPTANCE=$(jq -r ".userStories[] | select(.id == $NEXT_ID) | .acceptanceCriteria | join(\"\n- \")" "$PRD_FILE")
427
-
428
- set +e
429
- review_result=$(claude -p \
430
- --dangerously-skip-permissions \
431
- "You are a code reviewer. The implementer claims story #${NEXT_ID} ('${NEXT}') is complete.
432
-
433
- Last commit: ${last_commit}
434
- 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.
435
209
 
436
- Acceptance criteria:
437
- - ${ACCEPTANCE}
210
+ ## What you can do
438
211
 
439
- Instructions:
440
- 1. Read the changed files (git diff HEAD~1 HEAD).
441
- 2. For EACH criterion, verify it is met by the actual code. Be skeptical.
442
- 3. Run the build/test command if applicable.
443
- 4. If ANY criterion is not met: REVIEW_FAIL: [which criterion and why]
444
- 5. If all criteria met: REVIEW_PASS
445
-
446
- Do NOT trust the implementer's self-report. Verify independently.")
447
- review_exit=$?
448
- set -e
449
-
450
- echo "$review_result" | tail -10
451
-
452
- if [[ "$review_result" == *"REVIEW_FAIL"* ]]; then
453
- echo "Review failed!"
454
- jq --argjson id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
455
- echo "" >> "$PROGRESS_FILE"
456
- echo "## REVIEW FEEDBACK for Story $NEXT_ID" >> "$PROGRESS_FILE"
457
- echo "$review_result" | grep -i "REVIEW_FAIL" >> "$PROGRESS_FILE" 2>/dev/null
458
- review_failures=$((review_failures + 1))
459
- if [ $review_failures -ge 3 ]; then
460
- echo "3 review failures on story #${NEXT_ID}. Skipping."
461
- 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"
462
- review_failures=0
463
- fi
464
- else
465
- echo "Review passed."
466
- review_failures=0
467
- fi
468
- 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
469
217
 
470
- echo "Iteration #${iteration} done in ${minutes}m ${seconds}s"
471
- last_commit=$(git log --oneline -1 2>/dev/null || echo "")
472
- [ -n "$last_commit" ] && echo " Last commit: ${last_commit}"
473
- echo ""
474
- done
218
+ ## How stories work
475
219
 
476
- echo "Kai finished after ${iteration} iterations."
477
- }
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\`
478
223
 
479
- # ── 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
480
230
 
481
- case "${1:-help}" in
482
- init) cmd_init ;;
483
- plan) shift; cmd_plan "$@" ;;
484
- go) cmd_go ;;
485
- status) cmd_status ;;
486
- reset) shift; cmd_reset "$@" ;;
487
- help|*) cmd_help ;;
488
- 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
+ - On startup, greet the developer briefly. If there are existing stories, give a quick status. If not, ask what they want to build. Keep it to 2-3 lines max.
238
+ ${status}${project_context}${progress}" "${@:-Greet me and let\\'s get started.}"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kraftapps-ai/kai",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Autonomous AI developer loop for Claude Code",
5
5
  "bin": {
6
6
  "kai": "kai"