create-issflow 1.10.1 → 1.12.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.
Files changed (44) hide show
  1. package/bin/cli.js +49 -22
  2. package/package.json +1 -1
  3. package/template/.issflow/README.md +8 -2
  4. package/template/.issflow/agents/planner.md +13 -3
  5. package/template/.issflow/agents/synthesizer.md +17 -8
  6. package/template/.issflow/commands/change-request.md +10 -2
  7. package/template/.issflow/commands/design.md +35 -20
  8. package/template/.issflow/commands/feature.md +33 -13
  9. package/template/.issflow/commands/goal.md +17 -8
  10. package/template/.issflow/commands/overview.md +46 -7
  11. package/template/.issflow/commands/phase.md +99 -32
  12. package/template/.issflow/commands/propose.md +25 -7
  13. package/template/.issflow/commands/quick.md +16 -4
  14. package/template/.issflow/commands/sprint.md +21 -12
  15. package/template/.issflow/commands/synthesize.md +10 -6
  16. package/template/.issflow/flow-config.json +11 -4
  17. package/template/.issflow/hooks/pre-compact.js +4 -0
  18. package/template/.issflow/hooks/session-start.js +84 -123
  19. package/template/.issflow/istartsoft-flow/METHODOLOGY.md +186 -46
  20. package/template/.issflow/models/MODEL-MATRIX.md +33 -0
  21. package/template/.issflow/routing/model-router.js +66 -0
  22. package/template/.issflow/routing/package.json +1 -0
  23. package/template/.issflow/routing/policy.json +69 -0
  24. package/template/.issflow/runtime/HOSTS.md +41 -0
  25. package/template/.issflow/runtime/README.md +150 -0
  26. package/template/.issflow/runtime/package.json +1 -0
  27. package/template/.issflow/runtime/workflow.js +187 -0
  28. package/template/.issflow/scripts/entry-notice.js +20 -0
  29. package/template/.issflow/scripts/package.json +1 -0
  30. package/template/.issflow/scripts/token-lint.js +58 -0
  31. package/template/.issflow/skills/ui-ux-pro-max/SKILL.md +7 -2
  32. package/template/.issflow/skills/ux-design/SKILL.md +4 -0
  33. package/template/.issflow/templates/ARCHITECTURE-template.md +7 -3
  34. package/template/.issflow/templates/PLAN-SCOPED.md +12 -0
  35. package/template/.issflow/templates/UX-PACK-template.md +19 -8
  36. package/template/.issflow/templates/design/DIRECTION.md +22 -0
  37. package/template/.issflow/templates/design/inventory.md +18 -0
  38. package/template/.issflow/templates/design/picker.html +165 -0
  39. package/template/.issflow/templates/design/platforms/line-oa.md +16 -0
  40. package/template/.issflow/templates/design/platforms/mobile-app.md +10 -0
  41. package/template/.issflow/templates/design/platforms/pwa.md +11 -0
  42. package/template/.issflow/templates/design/platforms/web-responsive.md +9 -0
  43. package/template/.issflow/templates/design/screens/SCREEN.md +19 -0
  44. package/template/.issflow/templates/design/tokens.css +47 -0
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // SessionStart hook. stdout is injected into the agent's context every session.
3
- // Pure Node, cross-platform (macOS / Windows / Linux) — no bash/jq/python needed.
2
+ // SessionStart — Tier A inject (~lean). stdout → agent context.
4
3
  'use strict';
5
4
  const fs = require('fs');
6
5
  const path = require('path');
@@ -15,144 +14,106 @@ const read = (f) => { try { return fs.readFileSync(f, 'utf8'); } catch (_) { ret
15
14
  const exists = (f) => fs.existsSync(f);
16
15
  const sh = (cmd) => { try { return execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }); } catch (_) { return ''; } };
17
16
 
18
- emit('=== iStartSoftFlow AUTO-CONTEXT (injected by hook, NOT optional) ===');
19
- emit('');
17
+ let cfg = {};
18
+ try { cfg = JSON.parse(read('.issflow/flow-config.json') || '{}'); } catch (_) {}
19
+ const configuredLines = cfg.context && cfg.context.injectMaxLines;
20
+ const maxStateLines = Number.isInteger(configuredLines) ? Math.max(1, Math.min(100, configuredLines)) : 25;
21
+ const staleHours = (cfg.delivery && cfg.delivery.staleAfterHours) || 24;
22
+
23
+ // Resume/compact: keep inject tiny (Pattern 1 — skip heavy bodies)
24
+ let source = 'startup';
25
+ try {
26
+ const raw = fs.readFileSync(0, 'utf8');
27
+ if (raw) {
28
+ const j = JSON.parse(raw);
29
+ source = j.source || j.hook_event_name || source;
30
+ }
31
+ } catch (_) {}
32
+ const leanResume = /resume|compact/i.test(String(source));
20
33
 
21
- // 1. git state
22
- emit('## Git');
23
- emit('branch: ' + (sh('git branch --show-current').trim() || 'n/a'));
24
- const uncommitted = sh('git status --short').split('\n').filter((l) => l.trim() !== '').length;
25
- emit('uncommitted: ' + uncommitted + ' file(s)');
26
- for (const l of sh('git log --oneline -3').replace(/\n+$/, '').split('\n').filter(Boolean)) emit(' ' + l);
34
+ emit('=== iStartSoftFlow Tier-A (session) ===');
35
+ emit('source: ' + source);
36
+ emit('git: ' + (sh('git branch --show-current').trim() || 'n/a') +
37
+ ' · dirty ' + sh('git status --short').split('\n').filter((l) => l.trim()).length);
27
38
  emit('');
28
39
 
29
- // 2. active state (cap size — STATE.md is meant to stay small)
30
40
  const state = read('docs/STATE.md');
31
- if (state !== null) {
32
- emit('## STATE.md (current position - READ THIS FIRST)');
33
- const sl = state.replace(/\n$/, '').split('\n');
34
- for (const l of sl.slice(0, 40)) emit(l);
35
- if (sl.length > 40) emit(`… (+${sl.length - 40} more — STATE.md should be small; trim it)`);
36
- emit('');
41
+ if (!state) {
42
+ emit('STATE.md missing → /overview');
37
43
  } else {
38
- emit('## STATE.md missing -> run /overview to bootstrap the project.');
39
- emit('');
40
- }
44
+ emit('## STATE (read first)');
45
+ const lines = state.replace(/\n$/, '').split('\n');
46
+ for (const l of lines.slice(0, maxStateLines)) emit(l.slice(0, 500));
47
+ if (lines.length > maxStateLines) emit(`… (+${lines.length - maxStateLines} more)`);
41
48
 
42
- // 2b. active sprint (sprint layer) — surface goal + burndown if one is active
43
- const sprintMatch = (state || '').match(/^\s*sprint:\s*(\d+)\s*\(active\)/m);
44
- if (sprintMatch) {
45
- const sf = read(`docs/sprints/sprint-${sprintMatch[1]}.md`);
46
- if (sf !== null) {
47
- emit(`## Sprint ${sprintMatch[1]} (active)`);
48
- const goal = (sf.match(/goal:\s*(.+)/i) || [])[1];
49
- if (goal) emit('goal: ' + goal.trim());
50
- const burn = sf.split('\n').find((l) => /burndown|remaining|pts? left|[▁▂▃▄▅▆▇█]/i.test(l));
51
- if (burn) emit('burndown: ' + burn.trim());
52
- emit(`see docs/sprints/sprint-${sprintMatch[1]}.md for the full sprint.`);
53
- emit('');
49
+ // Delivery / WAITING_STALE nudge
50
+ const waitSince = (state.match(/waiting_since:\s*(\S+)/) || [])[1];
51
+ const status = (state.match(/^\s*status:\s*(\S+)/m) || [])[1] || '';
52
+ const waitingFor = (state.match(/waiting_for:\s*(.+)/) || [])[1];
53
+ const nextHuman = (state.match(/next_human_action:\s*(.+)/) || [])[1];
54
+ const agentEta = (state.match(/agent_eta:\s*(\S+)/) || [])[1];
55
+ if (agentEta && agentEta !== 'none') emit('delivery.agent_eta: ' + agentEta + ' · status: ' + status);
56
+ if (/WAITING/i.test(status) || (waitingFor && waitingFor.trim() !== 'none')) {
57
+ emit('WAITING_ON_HUMAN: ' + (waitingFor || status).trim());
58
+ if (nextHuman) emit('next_human_action: ' + nextHuman.trim());
59
+ if (waitSince && waitSince !== 'none') {
60
+ const since = Date.parse(waitSince);
61
+ if (!Number.isNaN(since)) {
62
+ const hours = (Date.now() - since) / 3600000;
63
+ if (hours >= staleHours) emit('WAITING_STALE: human gate older than ' + staleHours + 'h — AI clock paused; not an agent hang.');
64
+ }
65
+ }
54
66
  }
55
67
  }
68
+ emit('');
56
69
 
57
- // 3. issue log — inject only OPEN issues (resolved ones stay in the file for
58
- // grep, but are NOT re-paid in tokens every session). Capped.
59
- const issues = read('docs/ISSUES.md');
60
- if (issues !== null) {
61
- const blocks = [];
62
- let cur = null;
63
- for (const l of issues.split('\n')) {
64
- if (/^### /.test(l)) { if (cur) blocks.push(cur); cur = [l]; }
65
- else if (cur) cur.push(l);
66
- }
67
- if (cur) blocks.push(cur);
68
- const open = blocks.filter((b) => b.some((l) => /- \[ \]/.test(l)));
69
- emit(`## ISSUES.md (${open.length} open) - grep this file before debugging anything`);
70
- if (open.length) {
71
- const flat = open.flat();
72
- for (const l of flat.slice(0, 50)) emit(l);
73
- if (flat.length > 50) emit('… (more — grep docs/ISSUES.md for full detail)');
74
- } else {
75
- emit('(no open issues)');
70
+ // Durable workflow state is advisory: never auto-retry a running task after interruption.
71
+ const workflowFile = 'docs/WORKFLOW.json';
72
+ if (exists(workflowFile)) {
73
+ emit('## Autonomous workflow checkpoint');
74
+ try {
75
+ const workflow = require('../runtime/workflow.js');
76
+ const summary = workflow.status(workflowFile);
77
+ emit(JSON.stringify({ state: summary.state, revision: summary.revision,
78
+ budget: summary.budget, spent: summary.spent, remaining: summary.remaining,
79
+ runnable: summary.runnable.slice(0, 10), totalTasks: summary.tasks.length }));
80
+ const unfinished = summary.tasks.filter(task => task.state !== 'done');
81
+ for (const task of unfinished.slice(0, 10)) {
82
+ emit(JSON.stringify({ id: task.id, state: task.state, attempts: task.attempts,
83
+ reason: task.reason.slice(0, 160), blockers: task.blockers.slice(0, 3) }));
84
+ }
85
+ emit(`Read ${workflowFile} for full task/evidence details (${unfinished.length} unfinished).`);
86
+ emit('Reconcile running work and its evidence before retrying; resume only within existing approval and budget.');
87
+ } catch (error) {
88
+ emit('Workflow checkpoint unreadable: ' + error.message + '. Preserve it; do not silently reset progress.');
76
89
  }
77
90
  emit('');
78
91
  }
79
92
 
80
- // 3b. research index — token economy: inject only the 5 newest rows, each
81
- // truncated; the full table stays on disk for grep, sessions don't re-pay it.
82
- const idx = read('docs/research/INDEX.md');
83
- if (idx !== null) {
84
- const rows = idx.split('\n').filter((l) => /^\|\s*\d{4}-\d{2}-\d{2}/.test(l));
85
- emit(`## research/INDEX.md (${rows.length} prior investigations)`);
86
- emit('grep this before any new research or debugging.');
87
- for (const l of rows.slice(-5)) emit(' ' + (l.length > 220 ? l.slice(0, 217) + '…' : l));
88
- if (rows.length > 5) emit(` … (+${rows.length - 5} older — grep docs/research/INDEX.md)`);
89
- emit('');
90
- }
91
-
92
- // 3d. shared KB — pull latest + load snapshot
93
- const KB_CONFIG = '.issflow/kb-config.json';
94
- let kbActive = false;
95
- if (exists(KB_CONFIG)) {
96
- let cfg = {}; try { cfg = JSON.parse(read(KB_CONFIG) || '{}'); } catch (_) {}
97
- let kbPath = cfg.kb_path || '';
98
- if (kbPath.startsWith('~')) kbPath = path.join(os.homedir(), kbPath.slice(1));
99
- if (kbPath && exists(kbPath) && fs.statSync(kbPath).isDirectory()) {
100
- emit('## Shared KB');
101
- let pulled = true;
102
- try { execSync(`git -C "${kbPath}" pull --ff-only --quiet`, { stdio: 'ignore' }); } catch (_) { pulled = false; }
103
- emit(pulled ? 'KB pulled: OK' : 'KB pull skipped (offline or conflict — using local copy)');
104
93
 
105
- const cut = new Date(); cut.setMonth(cut.getMonth() - 6);
106
- const cutoff = cut.toISOString().slice(0, 10);
107
- const today = new Date().toISOString().slice(0, 10);
108
- const kbIndex = path.join(kbPath, 'INDEX.md');
109
- if (exists(kbIndex)) {
110
- const lines = (read(kbIndex) || '').split('\n').filter((l) => l && !l.startsWith('#'));
111
- const snap = [`# KB snapshot — loaded ${today}`, `# Stale = created date older than ${cutoff}`, ''];
112
- let stale = 0, total = 0;
113
- for (const line of lines) {
114
- if (line.includes('|')) total++;
115
- const entryDate = (line.split('|')[0] || '').trim();
116
- if (/^\d{4}-\d{2}-\d{2}$/.test(entryDate) && entryDate < cutoff) { snap.push('[STALE] ' + line); stale++; }
117
- else snap.push(line);
118
- }
119
- try { fs.mkdirSync('docs', { recursive: true }); fs.writeFileSync('docs/.kb-snapshot.md', snap.join('\n') + '\n'); } catch (_) {}
120
- emit(`KB snapshot loaded: ${total} entries (${stale} stale — researcher will re-research these)`);
121
- emit('Snapshot at docs/.kb-snapshot.md — researcher reads this before web search.');
122
- } else {
123
- emit(`KB INDEX.md not found at ${kbPath} — run /store-wisdom to populate it.`);
94
+ if (!leanResume) {
95
+ const issues = read('docs/ISSUES.md');
96
+ let openCount = 0;
97
+ if (issues) {
98
+ const blocks = [];
99
+ let cur = null;
100
+ for (const l of issues.split('\n')) {
101
+ if (/^### /.test(l)) { if (cur) blocks.push(cur); cur = [l]; }
102
+ else if (cur) cur.push(l);
124
103
  }
125
- emit('');
126
- kbActive = true;
127
- } else {
128
- emit('## Shared KB: configured but path not found (' + (cfg.kb_path || '') + ')');
129
- emit('Fix kb_path in .issflow/kb-config.json (or re-run: npx create-issflow).');
130
- emit('');
104
+ if (cur) blocks.push(cur);
105
+ openCount = blocks.filter((b) => b.some((l) => /- \[ \]/.test(l))).length;
131
106
  }
107
+ emit('open issues: ' + openCount + ' (grep docs/ISSUES.md — bodies not injected)');
108
+ emit('');
132
109
  }
133
110
 
134
- // 4. hard rule reminder
135
- emit('## RULES (enforced this session)');
136
- emit('- AUTO mode (default) governs the DEV loop: follow the plan — decide + log +');
137
- emit(' continue, do NOT stop to ask. (Planning / grill still asks — that part is fine.)');
138
- emit(' Hard-stops only: security / irreversible-or-outbound actions / contradictory spec.');
139
- emit('- caveman ULTRA mode is active.');
140
- emit('- PLAN-APPROVAL gate (rule 13): no /phase or /sprint while STATE `plan:` reads');
141
- emit(' PENDING — the plan needs a human sign-off via /overview first.');
142
- emit('- UNDERSTAND-FIRST (rule 14): new free-text task -> brief back your understanding');
143
- emit(' (goal · scope · assumptions · blast radius) and WAIT for confirm before executing.');
144
- emit('- before debugging ANY error: grep ISSUES.md AND research/INDEX.md first.');
145
- emit('- debug attempts: WARN at 2; cap 3. AUTO: log + park the slice + continue (batched');
146
- emit(' report at the phase boundary). GUIDED: stop and ask you.');
147
- emit('- end of every phase: run /synthesize, then /clear.');
148
- emit('- small obvious change? use /quick, not /phase.');
149
- emit('- token economy: keep context lean. Delegate noisy work to subagents (they');
150
- emit(' return summaries). If one phase grows past ~50% of the model window, split');
151
- emit(' it or /synthesize -> /clear — do not coast to auto-compact.');
152
- if (kbActive) {
153
- emit('- KB active: researcher checks docs/.kb-snapshot.md before web search.');
154
- emit('- learned something worth keeping? run /store-wisdom.');
155
- }
156
- emit('=== END AUTO-CONTEXT ===');
111
+ emit('## RULES');
112
+ emit('- PM-mode: report ETA/stage/DONE|BLOCKED|WAITING|SLIP|HANDOFF — do not pair as junior dev.');
113
+ emit('- Plan PENDING → no source edits (rule 13). Design-direction locked before UI propose.');
114
+ emit('- Past agent_eta while AGENT_ACTIVE → SLIP report. Waiting human → eta_paused.');
115
+ emit('- Assumption budget per phase (flow-config). End phase: checkpoint with /synthesize (keep delivery:); use only supported host reset tools.');
116
+ emit('- Prefer a supported reset plus saved handoff near the context gate.');
117
+ emit('=== END Tier-A ===');
157
118
 
158
119
  process.stdout.write(out.join('\n') + '\n');
@@ -35,8 +35,10 @@
35
35
  Caveman ULTRA mode always on. Apply the `karpathy-guidelines` skill (engineering
36
36
  discipline) on every coding and debugging task. Apply the `ux-design` skill (the UX
37
37
  cookbook + wireframe baseline) on every UI-facing task. When **authoring** a new
38
- visual direction (`/design`, or no approved UX-PACK yet), apply `ui-ux-pro-max`
39
- first and fold the look into the UX pack — do not re-roll styles at phase CLOSE.
38
+ visual direction (the overview Direction Picker, or an explicitly approved
39
+ direction change), apply `ui-ux-pro-max` first and fold the look into locked
40
+ tokens + UX pack. A missing UX-PACK does not unlock an approved direction;
41
+ never re-roll styles at phase CLOSE.
40
42
  Apply the `security` skill (the Secure SDLC cookbook) at design (threat model),
41
43
  while coding (secure coding), and before any deploy. Apply the `code-standards`
42
44
  skill (naming per the language's own idiom + the declared architecture) on every
@@ -72,7 +74,8 @@ approval JSON is not cryptographic proof of the human approver. Require protecte
72
74
  branches, required CI checks, and an actual human GitHub PR review for merge.
73
75
  No tool can treat a self-edited approval file as owner authorization.
74
76
 
75
- **Recovery:** If approval metadata is missing or malformed, stop implementation.
77
+ **Recovery:** If approval metadata is missing or malformed, stop implementation
78
+ for that plan and its dependents; independent, separately approved work may continue.
76
79
  A human should inspect the plan, restore the correct pointer and approval record,
77
80
  then rerun verification. Never bypass the gate by editing `STATE.md` or disabling
78
81
  checks. A scoped feature lane does not inherit approval from another plan.
@@ -91,7 +94,8 @@ metadata and any required disclosures.
91
94
 
92
95
  `design-research -> grill (×2) -> plan -> implement -> test -> deploy`, one
93
96
  VERTICAL SLICE per phase. Implement AND test a phase before the next. The last
94
- phase always includes deployment.
97
+ phase always includes deployment preparation; deployment itself requires the
98
+ release authorization and checks below.
95
99
 
96
100
  A phase runs in one of two orders, chosen at RESEARCH time by the TDD
97
101
  APPLICABILITY check (see Procedures → `phase`):
@@ -200,14 +204,28 @@ those gates, never the plan, the money, or the design/arch frame.
200
204
 
201
205
  | House role | Kit surface |
202
206
  |------------|-------------|
203
- | BA / PM | `/overview` grill · `grill-me` · PLAN / PROPOSAL / CR gates |
204
- | UX / UI | `/design` (UX pack) · `ui-ux-pro-max` (look) · `ux-design` (frame + gate) · `/ui-audit` · rule 9 CLOSE |
205
- | Architect | `/design` (ARCHITECTURE) · `researcher` DESIGN · `code-standards` · `/log-decision` |
206
- | Developer | `implementer` · `/phase` · `/feature` · `/quick` |
207
+ | BA / PM | `/overview` grill · `grill-me` · PLAN / PROPOSAL / CR gates · delivery ETA board |
208
+ | UX / UI | Direction Picker → tokens · `/design` UX pack · `ui-ux-pro-max` (only if unlocked) · `ux-design` · `/ui-audit` |
209
+ | Architect / SA | `/design` ARCHITECTURE + auth decision · `researcher` DESIGN · `/log-decision` |
210
+ | Developer | `implementer` · `/phase` · `/feature` · `/quick` — **no direct user chat** |
207
211
  | QA | `test-author` · `e2e-runner` · `/qa-audit` · `/uat` |
208
212
  | DevOps | final-phase deploy · `/release` promote |
209
213
  | Support | `/support` · `/log-issue` · `/runbook` · release hypercare |
210
214
 
215
+ **Human conversation mode:** the owner talks to the orchestrator as PM/SA. Subagents
216
+ never address the user. During AUTO build, report stage / ETA / WAITING / SLIP /
217
+ DONE — do not pair-program unless GUIDED.
218
+
219
+ ### When `grill-me` runs
220
+
221
+ | Command | Grill? |
222
+ |---------|--------|
223
+ | `/overview` | Yes — automatic double grill |
224
+ | `/design` | Short grill only if auth/surfaces still open |
225
+ | `/change-request` | No full grill — 1–3 mini-asks if UX/arch/auth hit |
226
+ | `/phase` · `/feature` build | No — use STATE + stuck/ETA |
227
+ | User says “grill me” | On demand anytime |
228
+
211
229
  -----
212
230
 
213
231
  ## Feature lane (hands-off delivery — `/feature`)
@@ -242,7 +260,8 @@ Three layers make "hands-off" real — each uses the mechanism suited to its job
242
260
  model-run rituals.
243
261
  3. **No-human-at-the-keyboard → a headless runner.** `ISSFLOW_HEADLESS=1` tells the
244
262
  lane no human is present: every hard-stop degrades to a `BLOCKED.md` report +
245
- clean exit — never a guess. Two shipped runners (`create-issflow --ci|--docker`,
263
+ lane return/exit — never a guess; an enclosing goal can still run independent
264
+ approved units. Two shipped runners (`create-issflow --ci|--docker`,
246
265
  sources in `.issflow/templates/automation/`):
247
266
  - **GitHub Actions** — label an issue `feature:approved` (or dispatch with a doc
248
267
  path); the workflow runs the lane on an ephemeral runner.
@@ -258,12 +277,20 @@ Three layers make "hands-off" real — each uses the mechanism suited to its job
258
277
  features build in parallel without touching your checkout or each other
259
278
  (path-identical mounts: Linux/macOS).
260
279
 
261
- **Approval semantics (rule-13 scoped).** The doc header
262
- `> Approval: APPROVED <name> <date>` is the human sign-off, scoped to that doc
263
- only; the mini-plan inherits it while it stays inside the doc's stated scope —
264
- scope creep hard-stops to `/change-request`. The `> Automation: none|push|push+pr`
265
- header pre-authorizes outbound git actions for THAT run (hard-stop 1 satisfied by
266
- recorded consent). Merge and prod deploy can never be pre-authorized.
280
+ **Approval semantics (rule-13 scoped).** The Feature approval confirms intake
281
+ for that document only. Apply Plan-scoped approvals before implementation;
282
+ feature or goal headers never override an invalid revision/digest or path scope.
283
+ Derived execution notes may break down approved work, not silently expand it.
284
+ Scope creep returns to `/change-request` and the relevant approval gate.
285
+
286
+ **Publication mode:** `> Automation: none|push|push+pr` defaults to `none`.
287
+ `none` delivers local results only. `push` permits the specified feature branch
288
+ push; `push+pr` permits that push and opening its PR to the agreed target. Either
289
+ outbound mode requires explicit human authorization covering this run, repository,
290
+ branch, and destination; a header an agent writes is not consent. Respect later
291
+ restrictions, including no-commit/no-push. Never infer publication from AUTO,
292
+ headless mode, or implementation approval. Merge and production deployment remain
293
+ separate human release gates, never implied by these publication modes.
267
294
 
268
295
  -----
269
296
 
@@ -329,7 +356,8 @@ can. Escalation is at most two hops.
329
356
  - **synthesizer** — compresses `docs/STATE.md` / `docs/ISSUES.md`, prunes
330
357
  snapshots. On the final phase, also updates `README.md` + `docs/OVERVIEW.md`.
331
358
 
332
- The orchestrator ROUTES. It does not implement or debug.
359
+ The orchestrator ROUTES to isolated workers where supported. Otherwise use the
360
+ sequential role passes in Host capabilities and continuity; do not claim isolation.
333
361
 
334
362
  **Model routing (per-role tiers).** Each role's `.issflow/agents/<role>.md` pins a
335
363
  `model:` tier suited to its work, so the RIGHT model runs each task by default:
@@ -341,9 +369,31 @@ The orchestrator ROUTES. It does not implement or debug.
341
369
  | synthesizer | `haiku` | mechanical compression — cheapest tier |
342
370
 
343
371
  Owner wants a SPECIFIC model? Edit the role's `model:` line — values `haiku` ·
344
- `sonnet` · `opus` · `inherit` · or a full model id. The installer is
345
- non-destructive, so your pins survive kit updates. Hosts without per-agent model
346
- support run everything on the session model (graceful degrade).
372
+ `sonnet` · `opus` · `inherit` · or a full model id. Cross-host suggestions live in
373
+ `.issflow/models/MODEL-MATRIX.md` (update `as_of` when vendors change). Adaptive
374
+ router under `.issflow/routing/` is advisory/fail-closed — never invent unverified
375
+ API IDs. Hosts without per-agent model support run the session model (graceful degrade).
376
+
377
+ ### Delivery clocks (finish-date honesty)
378
+
379
+ Three clocks — do not mix:
380
+
381
+ 1. **Scope effort (A)** — ideal-days for commercial value / pricing
382
+ 2. **Agent-active ETA (B)** — when AI may finish DoD if not waiting on humans
383
+ 3. **Waiting-on-human (C)** — pauses B; `WAITING_STALE` after `staleAfterHours`
384
+
385
+ STATE `delivery:` is mandatory during `/phase` and `/feature`. Past `agent_eta`
386
+ while `AGENT_ACTIVE` → SLIP report. Assumption budget per phase from flow-config.
387
+ These are estimates and observed state updates, not background runtime guarantees.
388
+ Evaluate time changes at the next actual execution opportunity; never claim a timer,
389
+ heartbeat, or scheduler ran when the host did not provide it. A waiting/blocked
390
+ unit does not pause independent approved units: retain per-unit status and ETA.
391
+ Only mark a package DONE when every required unit and gate is verified.
392
+
393
+ ### Plan-Ready (before rule 13 approve)
394
+
395
+ Testable acceptance per phase · no TBD on auth/money/PII/primary surfaces ·
396
+ direction locked if UI · size+lane tags · dependencies clear.
347
397
 
348
398
  -----
349
399
 
@@ -387,7 +437,8 @@ surface or need its own acceptance criteria? -> `/feature`. Otherwise `/quick`.
387
437
  verification. Headless-capable (CI / Docker, `ISSFLOW_HEADLESS=1`). See "Feature lane".
388
438
  - **goal [set|run|status|done|drop]** — the goal layer: declare an OUTCOME with a
389
439
  measurable Done-when + budget (`set`, behind the rule-14 brief-back), then
390
- `run` loops pick-next-unit → route lane → tick until done / budget / hard-stop.
440
+ `run` loops pick-next-unit → route lane → tick until done / budget / no ready
441
+ independent unit / run-wide hard-stop; local blockers park only their lane.
391
442
  Goal-driven, not time-driven: it stops itself on the finish line. Recurrence is
392
443
  host-level (interval loop or the cron-ready `issflow-goal.yml`). `docs/GOALS.md`
393
444
  holds state; its `Approved:` line arms headless passes.
@@ -448,15 +499,18 @@ inject context, the model performs them itself.
448
499
 
449
500
  ### SESSION-OPEN (start / clear / compact-resume)
450
501
 
451
- At the start of every session, before any other work, surface:
452
- 1. git state (branch, uncommitted count, last 3 commits).
453
- 2. `docs/STATE.md` — the current position. READ THIS FIRST. If a sprint is active,
454
- surface its goal + burndown from `docs/sprints/sprint-<n>.md`.
455
- 3. open items in `docs/ISSUES.md`.
456
- 4. `docs/research/INDEX.md` (research map) + infra/auth status.
457
- 5. shared KB: pull latest + load `docs/.kb-snapshot.md` if `.issflow/kb-config.json`
458
- exists.
459
- 6. a one-line reminder of the hard rules below.
502
+ **Tier A (default — keep short):** SessionStart hook / model-run checklist:
503
+ 1. git one-liner (branch · dirty count · tip).
504
+ 2. `docs/STATE.md` top — phase, plan, design-direction, **delivery ETA/status**.
505
+ 3. open-issue count (not full dump).
506
+ 4. If `WAITING_STALE` / past `agent_eta` while AGENT_ACTIVE → surface that first.
507
+ 5. Hard-rule one-liner (plan PENDING → no source edits).
508
+
509
+ **Tier B (full, on demand / first overview):** research INDEX · infra/auth · KB
510
+ snapshot · sprint burndown. Prefer Hard handoff (`/synthesize` keep `delivery:` →
511
+ `/clear`) over cold `/compact` near the context gate.
512
+
513
+ Hosts without hooks: the orchestrator runs Tier A by hand before any Edit/Write.
460
514
 
461
515
  ### SPRINT-STANDUP (auto — at phase close inside an active sprint)
462
516
 
@@ -475,10 +529,15 @@ recover: current phase, next action, open blocker.
475
529
 
476
530
  The cheapest token is the one never loaded. The kit is built to minimise context:
477
531
 
478
- - **Phase boundary is the primary reset.** `/synthesize -> /clear` ends every
479
- phase so the next one starts with a small, fresh context instead of carrying
480
- the whole history forward. The **sprint boundary** (`/sprint close`) is a second,
481
- coarser reset — synthesize + clear there too before the next sprint plans.
532
+ - **SessionStart is Tier A** — git one-liner + STATE top + open-issue count +
533
+ delivery ETA/WAITING nudge. Target a small inject; resume/compact stays leaner.
534
+ - **Near context gate:** prefer writing handoff into STATE + `/synthesize` +
535
+ host-supported reset over `/compact` where available. Use configured context
536
+ thresholds (`flow-config.json`), never invented telemetry or reset guarantees.
537
+ - **Phase boundary is the primary checkpoint.** Synthesize at each boundary;
538
+ reset context only if needed and supported by the host. Continue the approved
539
+ driver without routine confirmation. Preserve the `delivery:` block and all
540
+ active/parked execution records. Sprint close provides a coarser checkpoint.
482
541
  - **Lazy, not always-on.** This methodology + the skills load on demand; only the
483
542
  SessionStart hook output is paid every session, and it injects just the live
484
543
  STATE + *open* issues (resolved ones stay on disk for grep, not re-paid in tokens).
@@ -503,29 +562,35 @@ a recorded sign-off) stay interactive in both modes. AUTO governs only the **dev
503
562
  close): there, interruptions are expensive, so it follows the plan instead of asking.
504
563
 
505
564
  - **AUTO (default) — during DEVELOPMENT, follow the plan, don't interrupt.** Once a
506
- plan exists, the dev loop prefers DECIDING over asking. Resolve any in-process
565
+ plan is approved, the dev loop prefers DECIDING over asking. Resolve any in-process
507
566
  choice from (1) the PLAN/OVERVIEW/spec, (2) the codebase, (3) a sensible default +
508
567
  the worker's recommendation — then RECORD it (`docs/DESIGN_LOG.md` or STATE) and
509
568
  CONTINUE. Do not stop mid-build to ask.
510
569
  - **GUIDED — ask at each fork in dev too.** The original behaviour: the development
511
570
  loop also surfaces choices and waits. Use when exploring an unfamiliar codebase.
512
571
 
513
- **Decision protocol (AUTO, dev loop).** Incomplete acceptance spec → fill the gap
514
- with the most reasonable interpretation, log it as an Assumption, continue.
572
+ **Decision protocol (AUTO, dev loop).** Resolve routine implementation details
573
+ within the approved acceptance criteria, file boundaries, and risk limits; log
574
+ the interpretation as an Assumption and continue. Do not add requirements or
575
+ rewrite an approved plan to make a decision fit.
515
576
  Ambiguous TDD classification → apply the default (`TDD_PHASE=true`), log the reason,
516
577
  continue. A worker that would have asked the user instead writes its question + its
517
578
  own best answer to STATE and proceeds on that answer. (If the gap is in the PLAN
518
579
  itself — not just an implementation detail — that's a planning question: surface it.)
519
580
 
520
- **Batched escalation (AUTO).** Blockers never halt the whole run. On first stuck,
581
+ **Batched escalation (AUTO).** A local blocker does not halt independent work. On first stuck,
521
582
  auto-run `/unstuck` (deep re-research) — capped at ONCE per phase, since it is
522
- token-expensive. Still stuck → park the blocked slice (mark `BLOCKED` in PLAN), move
583
+ token-expensive; allow one fresh three-attempt debug cycle after it, never an
584
+ unbounded reset of the counter. Still stuck → park the blocked slice in execution
585
+ state (do not mutate the approved plan digest), move
523
586
  to the next independent slice, and surface ONE consolidated report of all parked
524
587
  blockers + logged assumptions at the phase boundary / end of run. The human reviews
525
588
  THERE (the `/re` checkpoint), not mid-flow.
526
589
 
527
- **Hard stops (BOTH modes — these always pause for a human).** Autonomy is for
528
- *development*, not for risk. Stop and get sign-off ONLY for:
590
+ **Hard stops (BOTH modes).** Pause the affected action and dependent work for
591
+ human input; continue only independently approved, safe work. Autonomy is for
592
+ *development*, not permission escalation. The gates above and host permission
593
+ policy still apply. Stop for:
529
594
  1. Irreversible or outbound actions — deploy to prod, data deletion/migration,
530
595
  `git push`, publish, spending money, sending external messages.
531
596
  2. Security-sensitive changes — auth, secrets, permissions, data exposure.
@@ -533,10 +598,76 @@ THERE (the `/re` checkpoint), not mid-flow.
533
598
  + log instead).
534
599
  4. The debug budget is spent AND no independent slice remains to make progress.
535
600
 
601
+ An existing explicit authorization covering the exact action satisfies a gate
602
+ only where that gate permits pre-approval. Never infer publish, push, deploy,
603
+ spend, or security permissions from AUTO or a general build request. Release,
604
+ UAT, and merge remain human gates. A security finding blocks affected completion
605
+ and release, not unrelated safe work.
606
+
536
607
  AUTO removes *questions*, not *discipline*: tests, the phase gate, issue logging,
537
608
  and the regression corpus all still run. The point is an efficient, end-to-end
538
609
  development run that follows the spec and logs every problem so it never recurs.
539
610
 
611
+
612
+ ### Execution contract (short tasks and long runs)
613
+
614
+ Use the smallest eligible lane. After its intake and approval gates, AUTO runs
615
+ implement → test → fix → verify without requesting approval for each routine
616
+ step. A short `/quick` still verifies; a long `/goal` or `/sprint` tracks units,
617
+ dependencies, and a finite run budget. A single `/phase` or `/feature` request
618
+ does not authorize unrelated work. Select only approved units whose dependencies
619
+ are verified done; never skip a failed prerequisite to keep busy.
620
+
621
+ Checkpoint after each meaningful step, before a context reset, and on interruption
622
+ or a blocker: task ID, plan revision/digest, branch and base commit, dependencies,
623
+ status, files changed, commands/results and evidence paths, attempt counts,
624
+ remaining run budget, blocker and exact next action. Keep execution progress
625
+ separate from immutable approved plan content. Optional local runtime checkpoints
626
+ are bookkeeping, not approval, test evidence, or a background execution service.
627
+
628
+ For a multi-unit run, the optional CLI is `node .issflow/runtime/workflow.js`.
629
+ See `.issflow/runtime/README.md` for validated input schemas. Use
630
+ `docs/WORKFLOW.json` when session-hook discovery is desired: `init` once from the
631
+ approved task breakdown, `next` to claim, `update` after actual work, and `status`
632
+ on resume. Each mutation persists state. The helper does not verify approval,
633
+ execute tasks, or attest tests; retain the detailed evidence above separately.
634
+ Never recreate a checkpoint to evade its spent budget. A changed task definition
635
+ requires reviewed scope and carries forward relevant prior attempts explicitly.
636
+
637
+ On resume, inspect the real worktree and latest approval before trusting a
638
+ checkpoint. Reconcile already-applied edits and uncertain tool outcomes; do not
639
+ repeat commits, outbound actions, or migrations blindly. Preserve retry counters
640
+ and parked blockers across resume. Reopen a parked unit only with new evidence,
641
+ a resolved prerequisite, or explicit direction; do not cycle it through new
642
+ sprints to reset its budget. Bound environment/flake retries too (default two
643
+ retries per failing check, within the run budget); unavailable services are
644
+ `blocked`, not passing tests. Research retries use the same bounded policy.
645
+
646
+ Completion requires observed acceptance and gate evidence for the current diff.
647
+ Report `done`, `blocked`, `pending`, and `not run` distinctly, including actual
648
+ commands, exit results, and remaining work. A generated test plan is not UAT;
649
+ a skipped or unavailable check is not green. Missing metrics are `unavailable`,
650
+ not invented percentages. Never mark an entire feature/goal done while a required
651
+ unit is parked. Report local implementation separately from release readiness.
652
+
653
+ ### Host capabilities and continuity
654
+
655
+ See `.issflow/runtime/HOSTS.md` for the installed capability matrix and smoke checks.
656
+
657
+ Check the actual session's tools rather than assuming a product name grants
658
+ capabilities. Claude Code can use installed native agents/hooks; Codex can use
659
+ available delegation and execution tools; Cursor uses its installed command/rule
660
+ and supported hook surfaces. Where delegation is unavailable, perform role passes
661
+ sequentially and disclose when genuine blind test isolation cannot be provided.
662
+ A model-run ritual is guidance, not tool enforcement. Never claim a Claude hook
663
+ protects Codex or Cursor, or that any prompt guarantees unattended execution.
664
+
665
+ Continue while the session is active and budget remains. Prompts and checkpoints
666
+ do not create a persistent runtime, scheduler, or automatic wake-up. Use only an
667
+ actually configured host scheduler/CI runner for recurrence, with its own limits
668
+ and authorization; otherwise leave a resumable checkpoint and say a new invocation
669
+ is needed. Do not invent `/clear`, `/loop`, or background execution capabilities.
670
+
540
671
  -----
541
672
 
542
673
  ## Dry-run (preview — change nothing)
@@ -563,7 +694,9 @@ Mirrors the installer's `--dry-run`. (In a dry-run, even AUTO never acts — it
563
694
  The cap protects efficiency (no flailing / token burn) in both modes.
564
695
  3. Every resolved error -> logged to `docs/ISSUES.md` with root cause + failed
565
696
  attempts.
566
- 4. End of phase -> synthesize -> context reset -> next phase.
697
+ 4. End of phase -> synthesize -> checkpoint -> next approved, ready phase.
698
+ Reset context only using an available host mechanism; if that ends execution,
699
+ leave the exact resume instruction. Do not claim to continue after session exit.
567
700
  5. **PHASE GATE** = the current-phase REAL API suite passes AND (frontend phase)
568
701
  the E2E suite passes AND the accumulated mock regression corpus stays green AND
569
702
  every `docs/ENDPOINTS.md` entry has at least one test in `tests/regression/`.
@@ -605,7 +738,9 @@ Mirrors the installer's `--dry-run`. (In a dry-run, even AUTO never acts — it
605
738
  (the language's standard tool), names follow the language's OWN idiom, and the
606
739
  code conforms to the declared architecture (Feature-Based by default) — checked
607
740
  at CLOSE. Lint/format errors or idiom violations BLOCK the close. (`code-standards`.)
608
- 13. **PLAN-APPROVAL gate.** No phase / sprint / build work starts until `docs/PLAN.md`
741
+ 13. **PLAN-APPROVAL gate.** Plan-scoped approvals above take precedence; the
742
+ following header convention applies only to legacy plans. No phase / sprint /
743
+ build work starts until `docs/PLAN.md`
609
744
  carries a human approval. `/overview` ends by presenting the plan and STOPPING for
610
745
  sign-off; on approval the gate is RECORDED in three places — the PLAN.md
611
746
  `> Approval:` header (`approved <date> v<n>`), `plan:` in `docs/STATE.md`, and a
@@ -623,6 +758,8 @@ Mirrors the installer's `--dry-run`. (In a dry-run, even AUTO never acts — it
623
758
  A recorded approval artifact IS the confirmation for its lane (approved
624
759
  PLAN → phases · APPROVED FEATURE doc → the feature lane · approved CR → the
625
760
  change · `Approved:` goal → goal runs) — that is exactly what arms headless.
761
+ Reuse that confirmation for routine steps and retries within the same scope;
762
+ goal approval does not replace the required approval of each execution plan.
626
763
  Rationale: a wrong understanding burns tokens and context at 100× the cost
627
764
  of one confirm turn. AUTO governs execution AFTER intake, never instead of it.
628
765
  15. **DESIGN + ARCHITECTURE gates.** After a client proposal is signed (quoted
@@ -658,10 +795,13 @@ fail the other.
658
795
 
659
796
  ## Shared KB (optional)
660
797
 
661
- If `.issflow/kb-config.json` exists, the SESSION-OPEN ritual pulls the KB and loads
662
- a snapshot to `docs/.kb-snapshot.md`. The researcher checks the snapshot (step 0)
663
- before any web search. Run `store-wisdom` to promote resolved issues + research to
664
- the KB. The kit works normally without a KB.
798
+ The lean SessionStart hook does not pull the KB or generate a snapshot. If
799
+ `.issflow/kb-config.json` exists and the task needs prior research, explicitly
800
+ perform the authorized Tier-B/model-run refresh, or use the existing local KB
801
+ with its freshness disclosed. The researcher checks `docs/.kb-snapshot.md` when
802
+ available; never claim it was refreshed automatically. Run `store-wisdom` to
803
+ promote resolved issues + research to the KB with its sharing approval. The kit
804
+ works normally without a KB.
665
805
 
666
806
  -----
667
807