@kraftapps-ai/kai 1.7.1 → 1.8.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.
- package/CLAUDE.md +20 -11
- package/kai +105 -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,48 @@ 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
|
+
"echo '⏳ Dev loop pane — waiting for PM to start the loop...'; cat"
|
|
55
|
+
tmux select-pane -t "${KAI_TMUX_SESSION}:0.0"
|
|
56
|
+
exec tmux attach-session -t "$KAI_TMUX_SESSION"
|
|
57
|
+
fi
|
|
58
|
+
fi
|
|
59
|
+
|
|
18
60
|
PRD_FILE=".kai/stories.json"
|
|
19
61
|
PROGRESS_FILE=".kai/progress.txt"
|
|
20
62
|
MEMORY_FILE=".kai/memory.md"
|
|
@@ -167,6 +209,15 @@ MCPEOF
|
|
|
167
209
|
echo " MCP servers configured in .mcp.json"
|
|
168
210
|
fi
|
|
169
211
|
|
|
212
|
+
# ── Create loop MCP config (no Playwright) ───────────
|
|
213
|
+
|
|
214
|
+
# Worker/reviewer don't need Playwright — it spawns Chromium and causes freezes
|
|
215
|
+
if [ -f ".mcp.json" ]; then
|
|
216
|
+
jq 'del(.mcpServers.playwright)' .mcp.json > .kai/loop-mcp.json
|
|
217
|
+
else
|
|
218
|
+
echo '{"mcpServers":{}}' > .kai/loop-mcp.json
|
|
219
|
+
fi
|
|
220
|
+
|
|
170
221
|
# ── Create the implementation loop script ─────────────
|
|
171
222
|
|
|
172
223
|
cat > "$LOOP_SCRIPT" << 'LOOPEOF'
|
|
@@ -176,6 +227,13 @@ set -e
|
|
|
176
227
|
|
|
177
228
|
PRD_FILE=".kai/stories.json"
|
|
178
229
|
PROGRESS_FILE=".kai/progress.txt"
|
|
230
|
+
LOOP_MCP_ARGS="--mcp-config .kai/loop-mcp.json"
|
|
231
|
+
|
|
232
|
+
# Stream output live when running in a tmux pane
|
|
233
|
+
KAI_STREAM=false
|
|
234
|
+
if [ -n "${TMUX:-}" ]; then
|
|
235
|
+
KAI_STREAM=true
|
|
236
|
+
fi
|
|
179
237
|
|
|
180
238
|
WORKER_PROMPT='You are an autonomous AI developer specializing in Shopify app and theme development.
|
|
181
239
|
|
|
@@ -268,12 +326,18 @@ while :; do
|
|
|
268
326
|
start_time=$(date +%s)
|
|
269
327
|
|
|
270
328
|
set +e
|
|
271
|
-
|
|
272
|
-
|
|
329
|
+
if [ "$KAI_STREAM" = true ]; then
|
|
330
|
+
claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS --system-prompt "$WORKER_PROMPT" $context_files 2>&1 | tee .kai/worker-output.tmp
|
|
331
|
+
exit_code=${PIPESTATUS[0]}
|
|
332
|
+
result=$(cat .kai/worker-output.tmp)
|
|
333
|
+
else
|
|
334
|
+
result=$(claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS --system-prompt "$WORKER_PROMPT" $context_files)
|
|
335
|
+
exit_code=$?
|
|
336
|
+
echo "$result" | tail -20
|
|
337
|
+
fi
|
|
273
338
|
set -e
|
|
274
339
|
|
|
275
340
|
elapsed=$(( $(date +%s) - start_time ))
|
|
276
|
-
echo "$result" | tail -20
|
|
277
341
|
|
|
278
342
|
if [ $exit_code -ne 0 ]; then
|
|
279
343
|
echo "Failed (code ${exit_code}). Restarting..."
|
|
@@ -286,14 +350,12 @@ while :; do
|
|
|
286
350
|
fi
|
|
287
351
|
|
|
288
352
|
# Review
|
|
289
|
-
STORY_PASSES=$(jq -r ".userStories[] | select(.id == $
|
|
353
|
+
STORY_PASSES=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .passes' "$PRD_FILE")
|
|
290
354
|
if [ "$STORY_PASSES" = "true" ]; then
|
|
291
355
|
last_commit=$(git log --oneline -1 2>/dev/null || echo "no git")
|
|
292
|
-
ACCEPTANCE=$(jq -r ".userStories[] | select(.id == $
|
|
356
|
+
ACCEPTANCE=$(jq -r --arg id "$NEXT_ID" '.userStories[] | select(.id == $id) | .acceptanceCriteria | join("\n- ")' "$PRD_FILE")
|
|
293
357
|
|
|
294
|
-
|
|
295
|
-
review=$(claude -p --dangerously-skip-permissions \
|
|
296
|
-
"You are a Shopify expert code reviewer. Story #${NEXT_ID} ('${NEXT}') claims complete.
|
|
358
|
+
REVIEW_PROMPT="You are a Shopify expert code reviewer. Story #${NEXT_ID} ('${NEXT}') claims complete.
|
|
297
359
|
Last commit: ${last_commit}
|
|
298
360
|
Acceptance criteria:
|
|
299
361
|
- ${ACCEPTANCE}
|
|
@@ -301,19 +363,35 @@ Read git diff HEAD~1 HEAD. Verify EACH criterion. Be skeptical.
|
|
|
301
363
|
If the story involves Shopify APIs, use introspect_graphql_schema to verify the code uses correct fields and types.
|
|
302
364
|
If it involves Liquid, use validate_theme_codeblocks to check for errors.
|
|
303
365
|
If ANY fails: REVIEW_FAIL: [reason]
|
|
304
|
-
If all pass: REVIEW_PASS"
|
|
305
|
-
set -e
|
|
366
|
+
If all pass: REVIEW_PASS"
|
|
306
367
|
|
|
307
|
-
|
|
368
|
+
set +e
|
|
369
|
+
if [ "$KAI_STREAM" = true ]; then
|
|
370
|
+
claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS "$REVIEW_PROMPT" 2>&1 | tee .kai/review-output.tmp
|
|
371
|
+
review=$(cat .kai/review-output.tmp)
|
|
372
|
+
else
|
|
373
|
+
review=$(claude -p --dangerously-skip-permissions $LOOP_MCP_ARGS "$REVIEW_PROMPT")
|
|
374
|
+
echo "$review" | tail -5
|
|
375
|
+
fi
|
|
376
|
+
set -e
|
|
308
377
|
|
|
309
378
|
if [[ "$review" == *"REVIEW_FAIL"* ]]; then
|
|
310
|
-
jq --
|
|
379
|
+
jq --arg id "$NEXT_ID" '(.userStories[] | select(.id == $id)).passes = false' "$PRD_FILE" > "${PRD_FILE}.tmp" && mv "${PRD_FILE}.tmp" "$PRD_FILE"
|
|
311
380
|
echo "REVIEW FEEDBACK: $review" >> "$PROGRESS_FILE"
|
|
312
381
|
review_failures=$((review_failures + 1))
|
|
313
|
-
[ $review_failures -ge 3 ]
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
382
|
+
if [ $review_failures -ge 3 ]; then
|
|
383
|
+
echo ""
|
|
384
|
+
echo "╔══════════════════════════════════════════════════╗"
|
|
385
|
+
echo "║ STALLED: Story #${NEXT_ID} failed review 3 times ║"
|
|
386
|
+
echo "╚══════════════════════════════════════════════════╝"
|
|
387
|
+
echo ""
|
|
388
|
+
echo "Review feedback:" >> "$PROGRESS_FILE"
|
|
389
|
+
echo "$review" >> "$PROGRESS_FILE"
|
|
390
|
+
echo "" >> "$PROGRESS_FILE"
|
|
391
|
+
echo "STALLED: Story #${NEXT_ID} failed review 3 times. Human intervention needed." >> "$PROGRESS_FILE"
|
|
392
|
+
echo "Loop stopped at $(date). Waiting for human intervention."
|
|
393
|
+
exit 1
|
|
394
|
+
fi
|
|
317
395
|
else
|
|
318
396
|
review_failures=0
|
|
319
397
|
fi
|
|
@@ -365,6 +443,16 @@ dev_greeting=""
|
|
|
365
443
|
[ -n "$dev_name" ] && dev_greeting="
|
|
366
444
|
The developer's name is: ${dev_name}"
|
|
367
445
|
|
|
446
|
+
# ── Build loop run instructions for PM ────────────────
|
|
447
|
+
|
|
448
|
+
if [ "$KAI_TMUX" = true ] || [ -n "${TMUX:-}" ]; then
|
|
449
|
+
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\`
|
|
450
|
+
The dev loop output streams live in the right tmux pane. You can also check \`tail -f .kai/loop.log\`.
|
|
451
|
+
To stop the loop: \`tmux send-keys -t ${KAI_TMUX_SESSION}:0.1 C-c\`"
|
|
452
|
+
else
|
|
453
|
+
LOOP_INSTRUCTIONS="To run implementation, execute: \`nohup .kai/loop.sh > .kai/loop.log 2>&1 &\` then monitor with \`tail -f .kai/loop.log\`"
|
|
454
|
+
fi
|
|
455
|
+
|
|
368
456
|
# ── Build Claude args ─────────────────────────────────
|
|
369
457
|
|
|
370
458
|
CLAUDE_ARGS="--dangerously-skip-permissions --name kai"
|
|
@@ -462,7 +550,7 @@ OAuth authentication happens automatically via browser on first use — no API k
|
|
|
462
550
|
|
|
463
551
|
Stories live in .kai/stories.json. Each has: id, title, description, acceptanceCriteria, priority, passes (true/false).
|
|
464
552
|
To add stories, edit .kai/stories.json directly using the Edit or Write tool.
|
|
465
|
-
|
|
553
|
+
${LOOP_INSTRUCTIONS}
|
|
466
554
|
|
|
467
555
|
## Browser testing (Playwright)
|
|
468
556
|
|