-
Notifications
You must be signed in to change notification settings - Fork 0
Scenarios
Common workflow walkthroughs with concrete STATE.md and BOARD.md snapshots at each step.
User says: "Add dark mode toggle"
Initial STATE.md:
phase: DONE
next_action: "Wait for user command"
What happens:
-
Agent reads STATE (phase: DONE) -> BOARD (empty TODO) -> no active work
-
Enters PLAN phase. Agent reads existing UI code: finds light theme only, CSS variables in
theme.css, no dark palette -
Produces tickets on BOARD:
## TODO - [ ] T-1 [P2] add dark mode CSS variables | verify: toggle switches CSS class on <body> - [ ] T-2 [P2] add theme toggle button to header | needs: T-1 | verify: button visible, clickable - [ ] T-3 [P1] persist theme preference in localStorage | needs: T-2 | verify: refresh preserves choice -
Agent claims T-1, transitions SCOUT -> BUILD
During SCOUT: reads
theme.css(180 lines), finds 12 color variables. Creates parallel:root.darkblock with complementary values. Reads neighbor fileheader.jsxfor import patterns.During BUILD: adds 12 dark-mode CSS variables, wires toggle to CSS class switch
-
VERIFY: toggle switches body class, colors invert, text remains readable (contrast ratio checked)
-
REVIEW: diff is 30 lines, no scope creep, no dead code, tests pass
-
SHIP: commit "v1.1.0: add dark mode toggle", tag, push
Updated STATE.md:
phase: DONE
next_action: "Wait for user command"
Total time from user command to shipped: ~8 minutes (agent working time)
User says: "The export button crashes on empty state"
Initial STATE.md:
phase: BUILD
task: T-14 implement CSV export
next_action: "BUILD T-14: wire export endpoint"
What happens:
-
Agent pauses T-14 to handle the bug. Creates ticket:
## DOING - [/] T-15 [P1] fix export crash on empty state | verify: export([]) returns valid empty CSV with headers ## TODO - [ ] T-14 [P2] implement CSV export (paused for T-15) -
SCOUT: reads
export.py(210 lines). Finds[row for row in data]assumed non-empty. Whendatais empty, next linedata[0].keys()raisesIndexError. No test for empty input. No guard clause. -
BUILD: adds guard at function entry:
def export_csv(data): if not data: return "header1,header2,header3\n" # return headers only headers = data[0].keys() ...
-
VERIFY:
export_csv([])returns"header1,header2,header3\n".export_csv([{...}])still works.pytest tests/test_export.py— all pass. -
REVIEW: 3-line diff, no side effects, tests cover empty case now
-
SHIP: commit "fix: export crash on empty data (T-15)", push
After fix, agent checks if T-14 is impacted by the fix (it's not). Resumes T-14.
Scenario: Agent A (Claude Code) worked for 2 hours, reached SHIP on T-42. User opens Agent B (Gemini Code Assist) and says "saipen continue"
What 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 (tail):
## DOING
- [/] T-42 [P2] implement user preferences panel | owner: claude-code | claim_time: 2026-07-27T14:30:00Z | verify: pytest tests/test_prefs.py
## DONE
- [x] T-40 ...
- [x] T-41 ...
.saipen/LOG.md (last 3 lines):
- 27.07.26 14:30 [E-88] [parent: E-87] [T-42] RUN: SCOUT — read prefs API, found PATCH /preferences endpoint exists, frontend panel missing
- 27.07.26 15:45 [E-89] [parent: E-88] [T-42] RUN: BUILD — preferences panel rendered, all 5 toggles wired, save button calls PATCH
- 27.07.26 16:10 [E-90] [parent: E-89] [T-42] RUN: VERIFY — all tests pass, manual check: toggles persist after refresh
Agent B execution:
- Reads BOOT.md -> STATE.md (phase: SHIP) -> BOARD.md (T-42 in DOING) -> LOG.md tail
- Executes
next_action: "SHIP T-42" - Runs
pytest tests/test_prefs.py— all green - Bumps VERSION, updates CHANGELOG, commits, tags
v1.3.0, pushes - Checkpoints: LOG -> BOARD -> STATE
Result: Agent B shipped Agent A's work in 2 minutes. Zero briefing. No chat history shared.
Scenario: Core agent building main feature. User says "saihunt" to delegate a bug sweep. Then "saitranslate" for a translation audit. Both run in parallel.
What happens:
-
User says "saihunt" -> saihunt subSaipen auto-spawns at
.saipen/extensions/subs/saihunt/.saipen/extensions/subs/saihunt/STATE.md: phase: HUNT task: run 6-category sweep against HEAD mode: read-only -
saihunt reads the main project (read-only), runs all 6 HUNT categories:
- Tests:
python tools/run_scenarios.py— 9/9 PASS - Commits: all verified against
git log - TODOs: no stale code markers found
- Silent failures: no bare
except:blocks - Symmetry: bootstrap scripts all have sh+ps1 pairs ✓
- Dead code: 2 stale kitchen files found (markhunt relics, tickets DONE)
- Tests:
-
saihunt writes OUTBOX:
## HUNT-001: clean sweep, 1 finding - finding: 2 stale files in .saipen/kitchen/ — owning tickets DONE, content superseded - severity: cleanup -
Meanwhile user says "saitranslate" -> saitranslate subSaipen auto-spawns at
.saipen/extensions/subs/saitranslate/, runs translation structure validation:- 32/32 locales have all required files
- All files valid UTF-8
- 3 Core locales up to date
- 29 non-Core stale (ticketed as T-186)
- Writes OUTBOX
-
User says "collect" -> main agent reads both OUTBOXes:
- saihunt finding: delete 2 stale files (actioned)
- saitranslate finding: noted, T-186 covers it
-
Main agent continues its BUILD work — never interrupted.
User says: "saipen goal make the UI responsive"
What happens:
-
PLAN generates ticket wave:
## TODO (wave 1) - [ ] T-1 [P2] add viewport meta tag | verify: <meta name="viewport"> in <head> - [ ] T-2 [P2] convert hardcoded widths to %/rem | needs: T-1 | verify: no px in layout CSS - [ ] T-3 [P2] add mobile breakpoint at 768px | needs: T-2 | verify: layout reflows at 767px - [ ] T-4 [P1] navigation collapses to hamburger on mobile | needs: T-3 -
goal_waves=1, goal_tickets=4
-
Agent executes wave 1: T-1 -> SCOUT -> BUILD -> VERIFY -> REVIEW -> SHIP -> DONE. Then T-2, T-3, T-4.
-
After each DONE,
saipen statusupdates:phase: DONE | goal_waves: 1 | goal_tickets: 4/20 next tickets: T-1 (DONE), T-2 (DONE), T-3 (DONE), T-4 (DONE) -
All wave 1 tickets done. Agent checks: are more responsive improvements possible? Yes -> PLAN generates wave 2 (T-5..T-8: tablet breakpoint, font scaling, touch targets, reduce motion).
-
goal_waves=2, goal_tickets=8
-
Wave 2 executes. After completion, agent checks: product now meets responsive standard. Calls mature exit.
-
Reports:
Goal complete: UI responsive 8 tickets shipped across 2 waves All verify criteria pass
Scenario: Agent crashed mid-BUILD. New agent opens project.
What new agent sees:
STATE.md:
phase: BUILD
task: T-18 implement search
next_action: "BUILD T-18: wire search input to backend"
blocker: none
agent: dead-agent
updated: 2026-07-26T12:00:00Z # <-- 3 hours ago! Stale claim
BOARD.md:
## DOING
- [/] T-18 [P2] implement search | owner: dead-agent | claim_time: 2026-07-26T11:45:00Z
Recovery (RFC 1.5):
- Agent detects stale
claim_time(>15 min since current time) - Appends LOG:
[E-91] RECOVERY: T-18 claim by dead-agent stale, resetting - Resets claim: removes
owner:andclaim_time:from T-18, moves BOARD line unchanged - Reads LOG tail to understand how much was done:
[E-85] SCOUT — read search API, found /search?q= endpoint [E-86] BUILD — search input rendered, onChange wired, debounce at 300ms - Checks git diff for unstaged work — finds
search.jsxpartially written (input + onChange done, results display not started) - Reclaims T-18: sets
owner:to new agent,claim_time:to now - Continues BUILD from where dead agent left off
Result: <1 minute recovery. No lost work (git preserved the partial).
User says: "saipen translate"
What happens:
- TRANSLATE phase loads the translation rules
- Agent reads EN root docs: README.md (v7.80.0), SECURITY.md (v7.80.0), CONTRIBUTING.md (v7.80.0), SPEC.md (v7.80.0)
- Reads existing
.saipen/saitranslate/kitchen/:- 32 locale directories, 5 files each
- Check against EN source for drift
-
git diff 40242f3..e2ded74 -- README.md SECURITY.md CONTRIBUTING.md SPEC.md-> empty (no content change, only badge)
- Version badge drift detected: EN at v7.80.0, most locales at v7.64.0
- Core execution: bumps RU/ET/DED README badges to v7.80.0
- Non-Core: tickets 29 stale locales as T-186 for subSaipen instances
- Logs completion:
translate -> done @e2ded74
After translate:
python tools/validate.py
PASS: all 32 locale README badges match VERSION (7.80.0)
User says: "saipen clean"
What happens:
- CLEAN phase loads (phases/clean.md)
-
Board Scrub: scans BOARD.md:
- Finds 2 DONE tickets from last week: moves them off (preserved in LOG.md)
- Finds T-12 in BLOCKED where blocker was already resolved last week: moves to TODO
- Finds duplicate
## DONEsections: merges into one - Fixes 1 malformed ticket line (missing space after
-)
-
Orphan Hunt: scans repo for files not referenced anywhere:
- Finds
old_script.py— no imports, no references, last modified 3 months ago. Deleted. - Finds
notes/directory — unclear ownership. Ticketed for human review.
- Finds
-
Link Audit: checks all markdown files:
- GUIDE.md has a link to
./old_path.mdthat 404s. Fixed to./new_path.md. - README.md badge links to correct path ✓
- GUIDE.md has a link to
-
Trash Removal:
-
__pycache__/in 3 directories -> cleaned -
.tmpfiles in kitchen/ -> deleted - LOG.md is 312 lines (past 300 cap) -> seals to
.saipen/logs/LOG-002.mdvia crash-safe temp+rename - Fresh LOG.md starts with E-### continuing from sealed segment
-
- Freshness Check: VERSION matches README badge. git status clean. validate.py PASS.
- LOG:
clean -> done @a1b2c3d - STATE -> DONE
Result: 3 stale files removed, 1 link fixed, LOG sealed, board decluttered. validate.py PASS.
SAIPEN v7.158.0 — One command. Zero dependencies. Zero amnesia. — MIT