@kraftapps-ai/kai 1.7.1 → 1.8.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/CLAUDE.md +20 -11
- package/kai +104 -17
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -6,29 +6,38 @@ Autonomous AI Shopify expert, product manager, and developer loop for Claude Cod
|
|
|
6
6
|
|
|
7
7
|
- `kai` — the entire tool; a single bash script that bootstraps the PM agent and dev loop
|
|
8
8
|
- `package.json` — npm metadata and version
|
|
9
|
-
- `.kai/PROMPT.md` — per-project context (generated at runtime, not in repo)
|
|
10
9
|
- `.kai/memory.md` — persistent memory across sessions (generated at runtime, not in repo)
|
|
11
10
|
- `.kai/loop.sh` — dev loop script (generated at runtime, not in repo)
|
|
11
|
+
- `.kai/loop-mcp.json` — MCP config without Playwright for the dev loop (generated at runtime)
|
|
12
12
|
|
|
13
13
|
## How it works
|
|
14
14
|
|
|
15
|
-
1. `kai` script auto-inits project files (
|
|
15
|
+
1. `kai` script auto-inits project files (`.kai/stories.json`, `.kai/progress.txt`, `.kai/memory.md`)
|
|
16
16
|
2. Auto-installs MCP servers if not already configured:
|
|
17
|
-
- **Playwright** — browser testing inside Shopify Admin
|
|
17
|
+
- **Playwright** — browser testing inside Shopify Admin (PM only, excluded from dev loop)
|
|
18
18
|
- **@shopify/dev-mcp** — Shopify docs, GraphQL schema introspection, Liquid/GraphQL/component validation
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
- **Mantle** — Shopify app billing, subscriptions, analytics
|
|
20
|
+
3. Generates `.kai/loop.sh` (the autonomous dev loop) and `.kai/loop-mcp.json` (MCP config without Playwright)
|
|
21
|
+
4. Launches a tmux session with two panes: PM (left) and dev loop (right)
|
|
22
|
+
5. Falls back to non-tmux mode if tmux is not installed or `--no-tmux` is passed
|
|
23
|
+
|
|
24
|
+
## tmux integration
|
|
25
|
+
|
|
26
|
+
Kai runs inside a tmux session (`kai`) with two panes:
|
|
27
|
+
- **Pane 0 (left)** — The PM: interactive Claude session where you chat with Kai
|
|
28
|
+
- **Pane 1 (right)** — Dev loop: streams live output when the PM kicks off `.kai/loop.sh`
|
|
29
|
+
|
|
30
|
+
When you exit and run `kai` again, it reattaches to the existing tmux session. If the dev loop is still running in pane 1, it continues undisturbed — the PM respawns in pane 0 with full context from `.kai/memory.md`, `.kai/stories.json`, and `.kai/progress.txt`.
|
|
31
|
+
|
|
32
|
+
Use `kai --no-tmux` to skip tmux and run in the current terminal (original behavior).
|
|
22
33
|
|
|
23
34
|
## Session persistence
|
|
24
35
|
|
|
25
|
-
Kai uses
|
|
26
|
-
- **`claude --continue`** — resumes the exact last conversation in this directory (primary)
|
|
27
|
-
- **`.kai/memory.md`** — Kai-maintained memory file with key decisions, current focus, and session log (fallback)
|
|
36
|
+
Kai uses `.kai/memory.md` to preserve context between sessions. The PM system prompt injects story status, progress log, and memory on every startup.
|
|
28
37
|
|
|
29
38
|
Use `kai --new` to force a fresh conversation (memory.md is still loaded for context).
|
|
30
39
|
|
|
31
|
-
The PM creates user stories in
|
|
40
|
+
The PM creates user stories in `.kai/stories.json`, then kicks off `.kai/loop.sh` which runs Claude in a loop — one story per iteration with self-review. The dev loop uses a Playwright-free MCP config (`.kai/loop-mcp.json`) to avoid spawning Chromium browsers. Only the PM uses Playwright for QA.
|
|
32
41
|
|
|
33
42
|
## MCP servers
|
|
34
43
|
|
|
@@ -46,4 +55,4 @@ Version lives in `package.json` only.
|
|
|
46
55
|
|
|
47
56
|
## Testing changes
|
|
48
57
|
|
|
49
|
-
Run `./kai` in any project directory. It will auto-init if
|
|
58
|
+
Run `./kai` in any project directory. It will auto-init if `.kai/stories.json` doesn't exist. Use `./kai --no-tmux` to test without tmux.
|
package/kai
CHANGED
|
@@ -15,6 +15,47 @@ if [ "${1:-}" = "--version" ] || [ "${1:-}" = "-v" ]; then
|
|
|
15
15
|
exit 0
|
|
16
16
|
fi
|
|
17
17
|
|
|
18
|
+
# ── Parse kai flags ──────────────────────────────────
|
|
19
|
+
|
|
20
|
+
KAI_TMUX=true
|
|
21
|
+
PASSTHROUGH_ARGS=()
|
|
22
|
+
for arg in "$@"; do
|
|
23
|
+
case "$arg" in
|
|
24
|
+
--no-tmux) KAI_TMUX=false ;;
|
|
25
|
+
--new) PASSTHROUGH_ARGS+=("$arg") ;;
|
|
26
|
+
*) PASSTHROUGH_ARGS+=("$arg") ;;
|
|
27
|
+
esac
|
|
28
|
+
done
|
|
29
|
+
set -- "${PASSTHROUGH_ARGS[@]}"
|
|
30
|
+
|
|
31
|
+
# Fall back if tmux is not installed
|
|
32
|
+
if ! command -v tmux &>/dev/null; then
|
|
33
|
+
KAI_TMUX=false
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# ── tmux session management ──────────────────────────
|
|
37
|
+
|
|
38
|
+
KAI_TMUX_SESSION="kai"
|
|
39
|
+
|
|
40
|
+
if [ "$KAI_TMUX" = true ]; then
|
|
41
|
+
# Already inside the kai tmux session — skip setup, run PM directly
|
|
42
|
+
if [ -n "${TMUX:-}" ] && [ "$(tmux display-message -p '#S' 2>/dev/null)" = "$KAI_TMUX_SESSION" ]; then
|
|
43
|
+
: # continue to normal execution below
|
|
44
|
+
elif tmux has-session -t "$KAI_TMUX_SESSION" 2>/dev/null; then
|
|
45
|
+
# Existing session — respawn PM in pane 0, reattach
|
|
46
|
+
tmux respawn-pane -k -t "${KAI_TMUX_SESSION}:0.0" \
|
|
47
|
+
"kai --no-tmux $(printf '%q ' "$@")"
|
|
48
|
+
exec tmux attach-session -t "$KAI_TMUX_SESSION"
|
|
49
|
+
else
|
|
50
|
+
# New session: pane 0 = PM, pane 1 = dev loop (waiting)
|
|
51
|
+
tmux new-session -d -s "$KAI_TMUX_SESSION" \
|
|
52
|
+
"kai --no-tmux $(printf '%q ' "$@")"
|
|
53
|
+
tmux split-window -h -t "${KAI_TMUX_SESSION}:0"
|
|
54
|
+
tmux select-pane -t "${KAI_TMUX_SESSION}:0.0"
|
|
55
|
+
exec tmux attach-session -t "$KAI_TMUX_SESSION"
|
|
56
|
+
fi
|
|
57
|
+
fi
|
|
58
|
+
|
|
18
59
|
PRD_FILE=".kai/stories.json"
|
|
19
60
|
PROGRESS_FILE=".kai/progress.txt"
|
|
20
61
|
MEMORY_FILE=".kai/memory.md"
|
|
@@ -167,6 +208,15 @@ MCPEOF
|
|
|
167
208
|
echo " MCP servers configured in .mcp.json"
|
|
168
209
|
fi
|
|
169
210
|
|
|
211
|
+
# ── Create loop MCP config (no Playwright) ───────────
|
|
212
|
+
|
|
213
|
+
# Worker/reviewer don't need Playwright — it spawns Chromium and causes freezes
|
|
214
|
+
if [ -f ".mcp.json" ]; then
|
|
215
|
+
jq 'del(.mcpServers.playwright)' .mcp.json > .kai/loop-mcp.json
|
|
216
|
+
else
|
|
217
|
+
echo '{"mcpServers":{}}' > .kai/loop-mcp.json
|
|
218
|
+
fi
|
|
219
|
+
|
|
170
220
|
# ── Create the implementation loop script ─────────────
|
|
171
221
|
|
|
172
222
|
cat > "$LOOP_SCRIPT" << 'LOOPEOF'
|
|
@@ -176,6 +226,13 @@ set -e
|
|
|
176
226
|
|
|
177
227
|
PRD_FILE=".kai/stories.json"
|
|
178
228
|
PROGRESS_FILE=".kai/progress.txt"
|
|
229
|
+
LOOP_MCP_ARGS="--mcp-config .kai/loop-mcp.json"
|
|
230
|
+
|
|
231
|
+
# Stream output live when running in a tmux pane
|
|
232
|
+
KAI_STREAM=false
|
|
233
|
+
if [ -n "${TMUX:-}" ]; then
|
|
234
|
+
KAI_STREAM=true
|
|
235
|
+
fi
|
|
179
236
|
|
|
180
237
|
WORKER_PROMPT='You are an autonomous AI developer specializing in Shopify app and theme development.
|
|
181
238
|
|
|
@@ -268,12 +325,18 @@ while :; do
|
|
|
268
325
|
start_time=$(date +%s)
|
|
269
326
|
|
|
270
327
|
set +e
|
|
271
|
-
|
|
272
|
-
|
|
328
|
+
if [ "$KAI_STREAM" = true ]; then
|
|
329
|
+
claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS --system-prompt "$WORKER_PROMPT" $context_files 2>&1 | tee .kai/worker-output.tmp
|
|
330
|
+
exit_code=${PIPESTATUS[0]}
|
|
331
|
+
result=$(cat .kai/worker-output.tmp)
|
|
332
|
+
else
|
|
333
|
+
result=$(claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS --system-prompt "$WORKER_PROMPT" $context_files)
|
|
334
|
+
exit_code=$?
|
|
335
|
+
echo "$result" | tail -20
|
|
336
|
+
fi
|
|
273
337
|
set -e
|
|
274
338
|
|
|
275
339
|
elapsed=$(( $(date +%s) - start_time ))
|
|
276
|
-
echo "$result" | tail -20
|
|
277
340
|
|
|
278
341
|
if [ $exit_code -ne 0 ]; then
|
|
279
342
|
echo "Failed (code ${exit_code}). Restarting..."
|
|
@@ -286,14 +349,12 @@ while :; do
|
|
|
286
349
|
fi
|
|
287
350
|
|
|
288
351
|
# Review
|
|
289
|
-
STORY_PASSES=$(jq -r ".userStories[] | select(.id == $
|
|
352
|
+
STORY_PASSES=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .passes' "$PRD_FILE")
|
|
290
353
|
if [ "$STORY_PASSES" = "true" ]; then
|
|
291
354
|
last_commit=$(git log --oneline -1 2>/dev/null || echo "no git")
|
|
292
|
-
ACCEPTANCE=$(jq -r ".userStories[] | select(.id == $
|
|
355
|
+
ACCEPTANCE=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .acceptanceCriteria | join("\n- ")' "$PRD_FILE")
|
|
293
356
|
|
|
294
|
-
|
|
295
|
-
review=$(claude -p --dangerously-skip-permissions \
|
|
296
|
-
"You are a Shopify expert code reviewer. Story #${NEXT_ID} ('${NEXT}') claims complete.
|
|
357
|
+
REVIEW_PROMPT="You are a Shopify expert code reviewer. Story #${NEXT_ID} ('${NEXT}') claims complete.
|
|
297
358
|
Last commit: ${last_commit}
|
|
298
359
|
Acceptance criteria:
|
|
299
360
|
- ${ACCEPTANCE}
|
|
@@ -301,19 +362,35 @@ Read git diff HEAD~1 HEAD. Verify EACH criterion. Be skeptical.
|
|
|
301
362
|
If the story involves Shopify APIs, use introspect_graphql_schema to verify the code uses correct fields and types.
|
|
302
363
|
If it involves Liquid, use validate_theme_codeblocks to check for errors.
|
|
303
364
|
If ANY fails: REVIEW_FAIL: [reason]
|
|
304
|
-
If all pass: REVIEW_PASS"
|
|
305
|
-
set -e
|
|
365
|
+
If all pass: REVIEW_PASS"
|
|
306
366
|
|
|
307
|
-
|
|
367
|
+
set +e
|
|
368
|
+
if [ "$KAI_STREAM" = true ]; then
|
|
369
|
+
claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS "$REVIEW_PROMPT" 2>&1 | tee .kai/review-output.tmp
|
|
370
|
+
review=$(cat .kai/review-output.tmp)
|
|
371
|
+
else
|
|
372
|
+
review=$(claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS "$REVIEW_PROMPT")
|
|
373
|
+
echo "$review" | tail -5
|
|
374
|
+
fi
|
|
375
|
+
set -e
|
|
308
376
|
|
|
309
377
|
if [[ "$review" == *"REVIEW_FAIL"* ]]; then
|
|
310
|
-
jq --
|
|
378
|
+
jq --arg id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
|
|
311
379
|
echo "REVIEW FEEDBACK: $review" >> "$PROGRESS_FILE"
|
|
312
380
|
review_failures=$((review_failures + 1))
|
|
313
|
-
[ $review_failures -ge 3 ]
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
381
|
+
if [ $review_failures -ge 3 ]; then
|
|
382
|
+
echo ""
|
|
383
|
+
echo "╔══════════════════════════════════════════════════╗"
|
|
384
|
+
echo "║ STALLED: Story #${NEXT_ID} failed review 3 times ║"
|
|
385
|
+
echo "╚══════════════════════════════════════════════════╝"
|
|
386
|
+
echo ""
|
|
387
|
+
echo "Review feedback:" >> "$PROGRESS_FILE"
|
|
388
|
+
echo "$review" >> "$PROGRESS_FILE"
|
|
389
|
+
echo "" >> "$PROGRESS_FILE"
|
|
390
|
+
echo "STALLED: Story #${NEXT_ID} failed review 3 times. Human intervention needed." >> "$PROGRESS_FILE"
|
|
391
|
+
echo "Loop stopped at $(date). Waiting for human intervention."
|
|
392
|
+
exit 1
|
|
393
|
+
fi
|
|
317
394
|
else
|
|
318
395
|
review_failures=0
|
|
319
396
|
fi
|
|
@@ -365,6 +442,16 @@ dev_greeting=""
|
|
|
365
442
|
[ -n "$dev_name" ] && dev_greeting="
|
|
366
443
|
The developer's name is: ${dev_name}"
|
|
367
444
|
|
|
445
|
+
# ── Build loop run instructions for PM ────────────────
|
|
446
|
+
|
|
447
|
+
if [ "$KAI_TMUX" = true ] || [ -n "${TMUX:-}" ]; then
|
|
448
|
+
LOOP_INSTRUCTIONS="To run implementation, execute: \`tmux send-keys -t ${KAI_TMUX_SESSION}:0.1 '.kai/loop.sh 2>&1 | tee .kai/loop.log' Enter\`
|
|
449
|
+
The dev loop output streams live in the right tmux pane. You can also check \`tail -f .kai/loop.log\`.
|
|
450
|
+
To stop the loop: \`tmux send-keys -t ${KAI_TMUX_SESSION}:0.1 C-c\`"
|
|
451
|
+
else
|
|
452
|
+
LOOP_INSTRUCTIONS="To run implementation, execute: \`nohup .kai/loop.sh > .kai/loop.log 2>&1 &\` then monitor with \`tail -f .kai/loop.log\`"
|
|
453
|
+
fi
|
|
454
|
+
|
|
368
455
|
# ── Build Claude args ─────────────────────────────────
|
|
369
456
|
|
|
370
457
|
CLAUDE_ARGS="--dangerously-skip-permissions --name kai"
|
|
@@ -462,7 +549,7 @@ OAuth authentication happens automatically via browser on first use — no API k
|
|
|
462
549
|
|
|
463
550
|
Stories live in .kai/stories.json. Each has: id, title, description, acceptanceCriteria, priority, passes (true/false).
|
|
464
551
|
To add stories, edit .kai/stories.json directly using the Edit or Write tool.
|
|
465
|
-
|
|
552
|
+
${LOOP_INSTRUCTIONS}
|
|
466
553
|
|
|
467
554
|
## Browser testing (Playwright)
|
|
468
555
|
|