-
Notifications
You must be signed in to change notification settings - Fork 0
Scenarios
Real workflows. Grandpa walked so you run. STATE + BOARD snapshots.
User: "Add dark mode toggle"
Initial STATE:
phase: DONE
next_action: "Wait for user command"
Flow:
- Agent reads STATE (DONE) → BOARD (empty) → no active work
- PLAN: reads existing UI code — light theme only, CSS variables in
theme.css, no dark palette - BOARD tickets:
## TODO - [ ] T-1 [P2] add dark mode CSS vars | verify: toggle switches CSS class on <body> - [ ] T-2 [P2] add theme toggle button | needs: T-1 | verify: button visible, clickable - [ ] T-3 [P1] persist preference in localStorage | needs: T-2 | verify: refresh preserves choice - Claim T-1, SCOUT→BUILD. SCOUT: reads
theme.css(180 lines), 12 color variables. Creates:root.darkblock. BUILD: adds 12 dark-mode vars, wires toggle - VERIFY: toggle switches body class, colors invert, contrast OK
- REVIEW: 30-line diff, no creep, no dead code, tests pass
- SHIP: commit, tag, push
Final STATE:
phase: DONE
next_action: "Wait for user command"
DED: Dark mode in 8 min. Without SAIPEN? Grandpa builds dark mode. Then light mode. Then sepia. Then cries. SAIPEN builds. Ships. Done. Grandpa naps.
User: "Export button crashes on empty state"
Initial STATE:
phase: BUILD
task: T-14 implement CSV export
next_action: "BUILD T-14: wire export endpoint"
Flow:
- Pause T-14. Create ticket:
- [/] T-15 [P1] fix export crash empty state | verify: export([]) returns valid empty CSV- [ ] T-14 [P2] CSV export (paused for T-15) - SCOUT: reads
export.py(210 lines).[row for row in data]assumed non-empty. Empty →data[0].keys()raises IndexError. No test. No guard. - BUILD: guard at function entry:
def export_csv(data): if not data: return "header1,header2,header3\n" headers = data[0].keys()
- VERIFY:
export_csv([])returns headers.export_csv([{...}])still works. pytest green. - REVIEW: 3-line diff, no side effects, tests cover empty case
- SHIP: commit "fix: export crash on empty data (T-15)"
After fix: T-14 unaffected. Resume T-14.
DED: 3-line fix took longer to find than write. Classic. Grandpa says "test empty state FIRST". Nobody listens. T-15 proves grandpa right.
Agent A (Claude Code) worked 2h, reached SHIP on T-42. User opens Agent B (Gemini) → "saipen continue"
Agent B reads:
.saipen/STATE.md:
phase: SHIP
task: T-42 implement user preferences panel
next_action: "SHIP T-42: verify tests pass, commit v1.3.0, tag, push"
agent: claude-code
.saipen/BOARD.md:
## DOING
- [/] T-42 [P2] implement user prefs panel | owner: claude-code | claim_time: ... | verify: pytest tests/test_prefs.py
.saipen/LOG.md (tail):
[E-88] SCOUT — read prefs API, found PATCH /preferences endpoint, frontend missing
[E-89] BUILD — panel rendered, 5 toggles wired, save calls PATCH
[E-90] VERIFY — all tests pass, toggles persist after refresh
Agent B:
- Reads BOOT → STATE (SHIP) → BOARD (T-42 DOING) → LOG tail
- Executes
SHIP T-42 - Runs
pytest tests/test_prefs.py— all green - Bumps VERSION, CHANGELOG, commits, tags v1.3.0, pushes
- Checkpoints
Result: Agent B shipped Agent A's work in 2 minutes. Zero briefing.
DED: Claude builds. Gemini ships. No "wait who are you". No re-explaining. Grandpa switches agents like socks. SAIPEN brain shared. All agents same page.
Core agent building feature. User says "saihunt" then "saitranslate". Both run parallel.
-
saihuntauto-spawns at.saipen/extensions/subs/saihunt/:phase: HUNT, task: 6-category sweep, mode: read-only - saihunt reads project (read-only), runs 6 categories:
- Tests: 9/9 PASS
- Commits: all verified
- TODOs: clean
- Silent failures: none
- Symmetry: bootstrap sh+ps1 pairs ✓
- Dead code: 2 stale kitchen files (tickets DONE)
- saihunt OUTBOX:
HUNT-001: clean sweep, 1 finding — 2 stale files, owning tickets DONE -
saitranslateauto-spawns, runs structure validation:- 32/32 locales complete
- 3 Core up to date
- 29 non-Core stale (ticketed T-186)
-
collect→ main agent reads both OUTBOXes. Deletes 2 stale files. Notes T-186. - Main agent continues BUILD — never interrupted.
DED: Feature ships. Bugs found. Locales checked. All parallel. Grandpa cooks borscht. Agent handles rest.
User: "saipen goal make UI responsive"
-
PLAN generates wave 1:
T-1: viewport meta tag | verify: <meta name="viewport"> in <head> T-2: convert hardcoded widths to %/rem | needs: T-1 T-3: mobile breakpoint 768px | needs: T-2 T-4: hamburger nav on mobile | needs: T-3 -
goal_waves=1, goal_tickets=4
-
Execute T-1→T-4: each SCOUT→BUILD→VERIFY→REVIEW→SHIP→DONE
-
After each DONE:
phase: DONE | goal_waves: 1 | goal_tickets: 4/20 -
All wave 1 done. More improvements possible? Yes → wave 2 (T-5..T-8: tablet breakpoint, font scaling, touch targets, reduce motion).
-
goal_waves=2, goal_tickets=8
-
Wave 2 done. Product meets responsive bar. Mature exit.
-
Report:
Goal complete: UI responsive 8 tickets shipped across 2 waves
DED: "Make responsive". 8 tickets. 2 waves. Done. Grandpa remembers when "responsive" meant "turn it off and on". Kids these days.
Agent crashed mid-BUILD. New agent opens project.
Sees:
STATE: phase: BUILD, task: T-18 implement search
next_action: "BUILD T-18: wire search input to backend"
agent: dead-agent, updated: 3h ago
BOARD: [/] T-18 | owner: dead-agent | claim_time: 3h ago
Recovery (RFC 1.5):
- Detects stale
claim_time(>15 min) - LOG:
[E-91] RECOVERY: T-18 claim by dead-agent stale, resetting - Resets claim: remove owner, claim_time. BOARD line unchanged.
- Reads LOG tail for progress:
[E-85] SCOUT — /search?q= endpoint exists [E-86] BUILD — input rendered, onChange wired, 300ms debounce - Checks
git diff:search.jsxpartially written (input + onChange done, results not started) - Reclaims T-18: new owner, new claim_time
- Continues BUILD from where dead agent left off
Result: <1 min recovery. No work lost (git preserved partial).
DED: Agent dies. Grandpa cries. New agent wakes. Reads STATE. "Oh T-18 search? On it". 1 min. Grandpa stops crying. SAIPEN remembers what dead agent forgot.
User: "saipen translate"
- TRANSLATE loads rules
- Agent reads EN root docs: README.md (v7.80.0), SECURITY.md, CONTRIBUTING.md, SPEC.md
- Reads
.saipen/saitranslate/kitchen/: 32 locales, 5 files each -
git diff 40242f3..e2ded74 -- README.md SECURITY.md CONTRIBUTING.md SPEC.md→ empty (content unchanged) - Badge drift: EN v7.80.0, locales at v7.64.0
- Core: bumps RU/ET/DED badges to v7.80.0
- Non-Core: tickets 29 stale as T-186 for subSaipen
- LOG:
translate → done @e2ded74
After:
python tools/validate.py
PASS: all 32 locale README badges match VERSION (7.80.0)
DED: "Translate to Japanese". Agent: "こんにちは世界". 29 other locales? "Not my problem". SAIPEN tickets them. Sub-agents handle. Grandpa doesn't do 29 languages. Neither should you.
User: "saipen clean"
- CLEAN phase loads
- Board Scrub: moves old DONE tickets off (preserved in LOG.md). Blocker resolved? Move to TODO. Merge duplicate sections. Fix malformed lines.
-
Orphan Hunt:
old_script.py— no refs, 3mo old. Deleted.notes/— unclear ownership. Ticketed. -
Link Audit: GUIDE.md link to
./old_path.md404s → fixed. -
Trash Removal:
__pycache__/in 3 dirs → cleaned..tmpin kitchen → deleted. LOG.md 312 lines → seals toLOG-002.md. Fresh LOG starts from continuing E-###. - Freshness Check: VERSION matches badge. git clean. validate.py PASS.
- LOG:
clean → done @a1b2c3d - STATE → DONE
Result: 3 stale files removed, 1 link fixed, LOG sealed, board decluttered.
DED: "Where is this file from?". Nobody knows. CLEAN finds. CLEAN kills. Roomba for repo. Grandpa approves. No orphans in HIS project.
User: "Export button crashes on empty state"
Initial STATE:
phase: BUILD
task: T-14 implement CSV export
next_action: "BUILD T-14: wire export endpoint"
Flow:
- Pause T-14. Create ticket:
- [/] T-15 [P1] fix export crash empty state | verify: export([]) returns valid empty CSV- [ ] T-14 [P2] CSV export (paused for T-15) - SCOUT: reads
export.py(210 lines).[row for row in data]assumed non-empty. Empty →data[0].keys()raises IndexError. No test. No guard. - BUILD: guard at function entry:
def export_csv(data): if not data: return "header1,header2,header3\n" headers = data[0].keys()
- VERIFY:
export_csv([])returns headers.export_csv([{...}])still works. pytest green. - REVIEW: 3-line diff, no side effects, tests cover empty case
- SHIP: commit "fix: export crash on empty data (T-15)"
After fix: T-14 unaffected. Resume T-14.
Agent A (Claude Code) worked 2h, reached SHIP on T-42. User opens Agent B (Gemini) → "saipen continue"
Agent B reads:
.saipen/STATE.md:
phase: SHIP
task: T-42 implement user preferences panel
next_action: "SHIP T-42: verify tests pass, commit v1.3.0, tag, push"
agent: claude-code
.saipen/BOARD.md:
## DOING
- [/] T-42 [P2] implement user prefs panel | owner: claude-code | claim_time: ... | verify: pytest tests/test_prefs.py
.saipen/LOG.md (tail):
[E-88] SCOUT — read prefs API, found PATCH /preferences endpoint, frontend missing
[E-89] BUILD — panel rendered, 5 toggles wired, save calls PATCH
[E-90] VERIFY — all tests pass, toggles persist after refresh
Agent B:
- Reads BOOT → STATE (SHIP) → BOARD (T-42 DOING) → LOG tail
- Executes
SHIP T-42 - Runs
pytest tests/test_prefs.py— all green - Bumps VERSION, CHANGELOG, commits, tags v1.3.0, pushes
- Checkpoints
Result: Agent B shipped Agent A's work in 2 minutes. Zero briefing.
Core agent building feature. User says "saihunt" then "saitranslate". Both run parallel.
-
saihuntauto-spawns at.saipen/extensions/subs/saihunt/:phase: HUNT, task: 6-category sweep, mode: read-only - saihunt reads project (read-only), runs 6 categories:
- Tests: 9/9 PASS
- Commits: all verified
- TODOs: clean
- Silent failures: none
- Symmetry: bootstrap sh+ps1 pairs ✓
- Dead code: 2 stale kitchen files (tickets DONE)
- saihunt OUTBOX:
HUNT-001: clean sweep, 1 finding — 2 stale files, owning tickets DONE -
saitranslateauto-spawns, runs structure validation:- 32/32 locales complete
- 3 Core up to date
- 29 non-Core stale (ticketed T-186)
-
collect→ main agent reads both OUTBOXes. Deletes 2 stale files. Notes T-186. - Main agent continues BUILD — never interrupted.
User: "saipen goal make UI responsive"
-
PLAN generates wave 1:
T-1: viewport meta tag | verify: <meta name="viewport"> in <head> T-2: convert hardcoded widths to %/rem | needs: T-1 T-3: mobile breakpoint 768px | needs: T-2 T-4: hamburger nav on mobile | needs: T-3 -
goal_waves=1, goal_tickets=4
-
Execute T-1→T-4: each SCOUT→BUILD→VERIFY→REVIEW→SHIP→DONE
-
After each DONE:
phase: DONE | goal_waves: 1 | goal_tickets: 4/20 -
All wave 1 done. More improvements possible? Yes → wave 2 (T-5..T-8: tablet breakpoint, font scaling, touch targets, reduce motion).
-
goal_waves=2, goal_tickets=8
-
Wave 2 done. Product meets responsive bar. Mature exit.
-
Report:
Goal complete: UI responsive 8 tickets shipped across 2 waves
Agent crashed mid-BUILD. New agent opens project.
Sees:
STATE: phase: BUILD, task: T-18 implement search
next_action: "BUILD T-18: wire search input to backend"
agent: dead-agent, updated: 3h ago
BOARD: [/] T-18 | owner: dead-agent | claim_time: 3h ago
Recovery (RFC 1.5):
- Detects stale
claim_time(>15 min) - LOG:
[E-91] RECOVERY: T-18 claim by dead-agent stale, resetting - Resets claim: remove owner, claim_time. BOARD line unchanged.
- Reads LOG tail for progress:
[E-85] SCOUT — /search?q= endpoint exists [E-86] BUILD — input rendered, onChange wired, 300ms debounce - Checks
git diff:search.jsxpartially written (input + onChange done, results not started) - Reclaims T-18: new owner, new claim_time
- Continues BUILD from where dead agent left off
Result: <1 min recovery. No work lost (git preserved partial).
User: "saipen translate"
- TRANSLATE loads rules
- Agent reads EN root docs: README.md (v7.80.0), SECURITY.md, CONTRIBUTING.md, SPEC.md
- Reads
.saipen/saitranslate/kitchen/: 32 locales, 5 files each -
git diff 40242f3..e2ded74 -- README.md SECURITY.md CONTRIBUTING.md SPEC.md→ empty (content unchanged) - Badge drift: EN v7.80.0, locales at v7.64.0
- Core: bumps RU/ET/DED badges to v7.80.0
- Non-Core: tickets 29 stale as T-186 for subSaipen
- LOG:
translate → done @e2ded74
After:
python tools/validate.py
PASS: all 32 locale README badges match VERSION (7.80.0)
User: "saipen clean"
- CLEAN phase loads
- Board Scrub: moves old DONE tickets off (preserved in LOG.md). Blocker resolved? Move to TODO. Merge duplicate sections. Fix malformed lines.
-
Orphan Hunt:
old_script.py— no refs, 3mo old. Deleted.notes/— unclear ownership. Ticketed. -
Link Audit: GUIDE.md link to
./old_path.md404s → fixed. -
Trash Removal:
__pycache__/in 3 dirs → cleaned..tmpin kitchen → deleted. LOG.md 312 lines → seals toLOG-002.md. Fresh LOG starts from continuing E-###. - Freshness Check: VERSION matches badge. git clean. validate.py PASS.
- LOG:
clean → done @a1b2c3d - STATE → DONE
Result: 3 stale files removed, 1 link fixed, LOG sealed, board decluttered.
SAIPEN v7.158.0 — One command. Zero dependencies. Zero amnesia. — MIT