@manhquy/flow-skill 0.1.0-rc.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE +21 -0
  3. package/README.md +152 -0
  4. package/README_VN.md +134 -0
  5. package/SECURITY.md +69 -0
  6. package/bin/cli.mjs +382 -0
  7. package/package.json +52 -0
  8. package/skills/flow/SKILL.md +234 -0
  9. package/skills/flow/_templates/00-idea.md +16 -0
  10. package/skills/flow/_templates/00-inspect.md +42 -0
  11. package/skills/flow/_templates/01-research.md +59 -0
  12. package/skills/flow/_templates/02-scope.md +71 -0
  13. package/skills/flow/_templates/03-prd.md +57 -0
  14. package/skills/flow/_templates/04-adr.md +21 -0
  15. package/skills/flow/_templates/05-contract.md +59 -0
  16. package/skills/flow/_templates/card.md +26 -0
  17. package/skills/flow/_templates/constitution.md +22 -0
  18. package/skills/flow/eval/fixtures/f01a/flow/01-research.md +77 -0
  19. package/skills/flow/eval/fixtures/f01b/flow/01-research.md +75 -0
  20. package/skills/flow/eval/fixtures/f02a/flow/02-scope.md +56 -0
  21. package/skills/flow/eval/fixtures/f02b/flow/02-scope.md +65 -0
  22. package/skills/flow/eval/fixtures/fcda/.flow/.gitkeep +0 -0
  23. package/skills/flow/eval/fixtures/fcda/cards/C-001.md +46 -0
  24. package/skills/flow/eval/fixtures/fcdb/.flow/.gitkeep +0 -0
  25. package/skills/flow/eval/fixtures/fcdb/cards/C-001.md +35 -0
  26. package/skills/flow/eval/manifest.tsv +7 -0
  27. package/skills/flow/harness/README.md +117 -0
  28. package/skills/flow/harness/_db.py +228 -0
  29. package/skills/flow/harness/_domain.py +161 -0
  30. package/skills/flow/harness/_presence.py +109 -0
  31. package/skills/flow/harness/flow_harness.py +1103 -0
  32. package/skills/flow/harness/repo_map.py +93 -0
  33. package/skills/flow/harness/schema/001-init.sql +129 -0
  34. package/skills/flow/harness/schema/002-story-verify.sql +9 -0
  35. package/skills/flow/harness/schema/003-tool-registry.sql +15 -0
  36. package/skills/flow/harness/schema/004-intervention.sql +15 -0
  37. package/skills/flow/harness/schema/005-tool-extensions.sql +20 -0
  38. package/skills/flow/harness/schema/009-accessed-count.sql +11 -0
  39. package/skills/flow/harness/schema/010-usage-event.sql +42 -0
  40. package/skills/flow/harness/schema/011-usage-gate-reason.sql +8 -0
  41. package/skills/flow/harness/schema/012-usage-ephemeral.sql +10 -0
  42. package/skills/flow/law/CLAUDE.md +140 -0
  43. package/skills/flow/law/DESIGN.md +141 -0
  44. package/skills/flow/law/RETRO.md +13 -0
  45. package/skills/flow/playbooks/README.md +28 -0
  46. package/skills/flow/playbooks/cloudflare-ai-gateway-qwen.md +346 -0
  47. package/skills/flow/playbooks/docker-deploy-stale-cache.md +32 -0
  48. package/skills/flow/playbooks/rag-lite-postgres-cloudflare.md +192 -0
  49. package/skills/flow/playbooks/windows-gitbash-jsonl-telemetry.md +57 -0
  50. package/skills/flow/references/adversarial-review.md +197 -0
  51. package/skills/flow/references/agent-detection.md +88 -0
  52. package/skills/flow/references/agent-stage-mapping.md +114 -0
  53. package/skills/flow/references/antigravity-integration.md +92 -0
  54. package/skills/flow/references/auto-run.md +81 -0
  55. package/skills/flow/references/claudekit-skills.md +128 -0
  56. package/skills/flow/references/codex-integration.md +104 -0
  57. package/skills/flow/references/command-dispatch.md +54 -0
  58. package/skills/flow/references/debt-and-halts.md +41 -0
  59. package/skills/flow/references/design-review-checklist.md +42 -0
  60. package/skills/flow/references/gate-eval.md +186 -0
  61. package/skills/flow/references/gate-rules.md +171 -0
  62. package/skills/flow/references/ground-truth-gates.md +49 -0
  63. package/skills/flow/references/loop-harness-2026-principles.md +52 -0
  64. package/skills/flow/references/mode-work.md +37 -0
  65. package/skills/flow/references/project-types.md +42 -0
  66. package/skills/flow/references/stage-state-machine.md +47 -0
  67. package/skills/flow/references/ui-patterns-tcr.md +49 -0
  68. package/skills/flow/runner/flow.cmd +18 -0
  69. package/skills/flow/runner/flow.sh +3297 -0
  70. package/skills-manifest.json +70 -0
  71. package/src/constants.mjs +65 -0
  72. package/src/detect.mjs +36 -0
  73. package/src/help.mjs +42 -0
  74. package/src/installer.mjs +231 -0
  75. package/src/prompt.mjs +60 -0
  76. package/src/tty.mjs +11 -0
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env python3
2
+ """Reference-count repo-map: rank source files by how widely the symbols they DEFINE are
3
+ referenced across the codebase (Aider's ranking idea, stdlib-only — no tree-sitter dependency,
4
+ so it runs anywhere python 3 does). Best-effort: prints nothing and exits 0 when there is nothing
5
+ rankable, so the caller (flow.sh assess) falls back to its flat scan.
6
+
7
+ Usage: python repo_map.py <project_root> [top_n]
8
+ """
9
+ import os
10
+ import re
11
+ import sys
12
+ from collections import Counter
13
+
14
+ SKIP_DIRS = {".git", "node_modules", ".flow", "plans", "dist", "build", "__pycache__",
15
+ ".venv", "venv", "vendor", ".idea", ".vscode", "target", "coverage", "cards",
16
+ "tests", "test", "spec", "__tests__", "e2e"}
17
+ EXTS = {".py", ".js", ".ts", ".tsx", ".jsx", ".go", ".rs", ".sh", ".rb", ".java", ".kt"}
18
+ MAX_BYTES = 512 * 1024 # skip very large files (binary-adjacent / generated) to bound memory + time
19
+ # generic identifiers that carry no "this file is important" signal even when frequent
20
+ STOPWORDS = {"main", "init", "name", "self", "this", "data", "value", "values", "item", "items",
21
+ "list", "index", "test", "tests", "args", "kwargs", "result", "results", "error",
22
+ "get", "set", "run", "make", "type", "config", "setup", "build", "parse", "func"}
23
+ WORD = re.compile(r"[A-Za-z_]\w+")
24
+ DEF_PATTERNS = [
25
+ re.compile(r"^\s*(?:async\s+)?def\s+([A-Za-z_]\w+)"), # python
26
+ re.compile(r"^\s*class\s+([A-Za-z_]\w+)"), # python/js/ts/java/kt
27
+ re.compile(r"^\s*(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_]\w+)"), # js/ts
28
+ re.compile(r"^\s*(?:export\s+)?const\s+([A-Za-z_]\w+)\s*(?::[^=]+)?="), # js/ts (incl. typed arrows: const x: T = )
29
+ re.compile(r"^\s*func\s+([A-Za-z_]\w+)"), # go
30
+ re.compile(r"^\s*(?:pub\s+)?fn\s+([A-Za-z_]\w+)"), # rust
31
+ re.compile(r"^\s*(?:pub\s+)?struct\s+([A-Za-z_]\w+)"), # rust
32
+ re.compile(r"^\s*([A-Za-z_]\w+)\s*\(\)\s*\{"), # shell name() {
33
+ ]
34
+
35
+
36
+ def iter_files(root):
37
+ # os.walk does NOT follow symlinks by default (no symlink-loop risk).
38
+ for dp, dirs, files in os.walk(root):
39
+ dirs[:] = [d for d in dirs if d not in SKIP_DIRS and not d.startswith(".")]
40
+ for fn in files:
41
+ if os.path.splitext(fn)[1] in EXTS:
42
+ yield os.path.join(dp, fn)
43
+
44
+
45
+ def _defs_in(lines):
46
+ syms = set()
47
+ for ln in lines:
48
+ for pat in DEF_PATTERNS:
49
+ m = pat.match(ln)
50
+ if m:
51
+ name = m.group(1)
52
+ if len(name) >= 4 and name.lower() not in STOPWORDS:
53
+ syms.add(name)
54
+ return syms
55
+
56
+
57
+ def main(argv):
58
+ root = argv[1] if len(argv) > 1 else "."
59
+ top_n = int(argv[2]) if len(argv) > 2 else 10
60
+ files = list(iter_files(root))
61
+ if not files:
62
+ return 0
63
+ defs, def_files, freq = {}, Counter(), Counter()
64
+ for f in files:
65
+ try:
66
+ if os.path.getsize(f) > MAX_BYTES:
67
+ continue
68
+ with open(f, "r", encoding="utf-8", errors="ignore") as fh:
69
+ lines = fh.read().splitlines()
70
+ except OSError:
71
+ continue
72
+ syms = _defs_in(lines)
73
+ defs[f] = syms
74
+ for s in syms:
75
+ def_files[s] += 1
76
+ freq.update(WORD.findall("\n".join(lines))) # tokenize ONCE per file (O(corpus) total)
77
+ ranked = []
78
+ for f in files:
79
+ # only symbols UNIQUELY defined in this file score it — a name defined in many files
80
+ # (utils, helper) is ambiguous and would give every definer the same inflated count.
81
+ uniq = [s for s in defs.get(f, ()) if def_files[s] == 1]
82
+ score = sum(max(0, freq.get(s, 0) - 1) for s in uniq) # minus the definition itself
83
+ if score > 0:
84
+ top = sorted(uniq, key=lambda s: -freq.get(s, 0))[:3]
85
+ ranked.append((score, os.path.relpath(f, root).replace("\\", "/"), top))
86
+ ranked.sort(key=lambda x: (-x[0], x[1]))
87
+ for i, (score, rel, top) in enumerate(ranked[:top_n], 1):
88
+ print(f"{i}. {rel} (score {score}; {', '.join(top)})")
89
+ return 0
90
+
91
+
92
+ if __name__ == "__main__":
93
+ sys.exit(main(sys.argv))
@@ -0,0 +1,129 @@
1
+ -- Harness v0 schema — migration 001
2
+ -- Durable layer for operational harness data.
3
+ -- Policy docs (HARNESS.md, FEATURE_INTAKE.md, ARCHITECTURE.md) stay as
4
+ -- human-readable references. This database stores the operational records
5
+ -- that agents produce and query during work.
6
+
7
+ PRAGMA journal_mode = WAL;
8
+ PRAGMA foreign_keys = ON;
9
+
10
+ ----------------------------------------------------------------------
11
+ -- Schema version
12
+ ----------------------------------------------------------------------
13
+ CREATE TABLE IF NOT EXISTS schema_version (
14
+ version INTEGER PRIMARY KEY,
15
+ applied_at TEXT NOT NULL DEFAULT (datetime('now'))
16
+ );
17
+
18
+ INSERT INTO schema_version (version) VALUES (1);
19
+
20
+ ----------------------------------------------------------------------
21
+ -- Intake: classifying incoming work
22
+ ----------------------------------------------------------------------
23
+ CREATE TABLE intake (
24
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
25
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
26
+ input_type TEXT NOT NULL
27
+ CHECK(input_type IN (
28
+ 'new_spec','spec_slice','change_request',
29
+ 'new_initiative','maintenance','harness_improvement'
30
+ )),
31
+ summary TEXT NOT NULL,
32
+ risk_lane TEXT NOT NULL
33
+ CHECK(risk_lane IN ('tiny','normal','high_risk')),
34
+ risk_flags TEXT, -- JSON array, e.g. ["auth","data_model"]
35
+ affected_docs TEXT, -- JSON array of doc paths
36
+ story_id TEXT, -- links to story.id when one is created
37
+ notes TEXT
38
+ );
39
+
40
+ ----------------------------------------------------------------------
41
+ -- Story: work packets and their validation status
42
+ -- Replaces hand-edited TEST_MATRIX.md rows.
43
+ ----------------------------------------------------------------------
44
+ CREATE TABLE story (
45
+ id TEXT PRIMARY KEY, -- e.g. US-001
46
+ title TEXT NOT NULL,
47
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
48
+ risk_lane TEXT NOT NULL
49
+ CHECK(risk_lane IN ('tiny','normal','high_risk')),
50
+ contract_doc TEXT, -- path to product doc
51
+ status TEXT NOT NULL DEFAULT 'planned'
52
+ CHECK(status IN (
53
+ 'planned','in_progress','implemented','changed','retired'
54
+ )),
55
+ unit_proof INTEGER NOT NULL DEFAULT 0,
56
+ integration_proof INTEGER NOT NULL DEFAULT 0,
57
+ e2e_proof INTEGER NOT NULL DEFAULT 0,
58
+ platform_proof INTEGER NOT NULL DEFAULT 0,
59
+ evidence TEXT,
60
+ notes TEXT
61
+ );
62
+
63
+ ----------------------------------------------------------------------
64
+ -- Decision: durable records with optional verification
65
+ ----------------------------------------------------------------------
66
+ CREATE TABLE decision (
67
+ id TEXT PRIMARY KEY, -- e.g. 0001
68
+ title TEXT NOT NULL,
69
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
70
+ status TEXT NOT NULL DEFAULT 'proposed'
71
+ CHECK(status IN (
72
+ 'proposed','accepted','superseded','rejected'
73
+ )),
74
+ doc_path TEXT, -- path to the markdown ADR
75
+ verify_command TEXT, -- optional check command
76
+ last_verified_at TEXT,
77
+ last_verified_result TEXT
78
+ CHECK(last_verified_result IN ('pass','fail') OR
79
+ last_verified_result IS NULL),
80
+ predicted_impact TEXT,
81
+ actual_outcome TEXT,
82
+ notes TEXT
83
+ );
84
+
85
+ ----------------------------------------------------------------------
86
+ -- Backlog: harness improvement proposals with evidence loop
87
+ ----------------------------------------------------------------------
88
+ CREATE TABLE backlog (
89
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
90
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
91
+ title TEXT NOT NULL,
92
+ discovered_while TEXT,
93
+ current_pain TEXT,
94
+ suggested_improvement TEXT,
95
+ risk TEXT CHECK(risk IN ('tiny','normal','high_risk')),
96
+ status TEXT NOT NULL DEFAULT 'proposed'
97
+ CHECK(status IN (
98
+ 'proposed','accepted','implemented','rejected'
99
+ )),
100
+ predicted_impact TEXT,
101
+ actual_outcome TEXT,
102
+ implemented_at TEXT,
103
+ notes TEXT
104
+ );
105
+
106
+ ----------------------------------------------------------------------
107
+ -- Trace: agent task execution records (observability foundation)
108
+ ----------------------------------------------------------------------
109
+ CREATE TABLE trace (
110
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
111
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
112
+ task_summary TEXT NOT NULL,
113
+ intake_id INTEGER REFERENCES intake(id),
114
+ story_id TEXT REFERENCES story(id),
115
+ agent TEXT,
116
+ actions_taken TEXT, -- JSON array
117
+ files_read TEXT, -- JSON array
118
+ files_changed TEXT, -- JSON array
119
+ decisions_made TEXT, -- JSON array
120
+ errors TEXT, -- JSON array
121
+ outcome TEXT
122
+ CHECK(outcome IN (
123
+ 'completed','blocked','partial','failed'
124
+ )),
125
+ duration_seconds INTEGER,
126
+ token_estimate INTEGER,
127
+ harness_friction TEXT,
128
+ notes TEXT
129
+ );
@@ -0,0 +1,9 @@
1
+ -- Harness v0 schema - migration 002
2
+ -- Story-level mechanical verification.
3
+
4
+ ALTER TABLE story ADD COLUMN verify_command TEXT;
5
+ ALTER TABLE story ADD COLUMN last_verified_at TEXT;
6
+ ALTER TABLE story ADD COLUMN last_verified_result TEXT
7
+ CHECK(last_verified_result IN ('pass','fail') OR last_verified_result IS NULL);
8
+
9
+ INSERT INTO schema_version (version) VALUES (2);
@@ -0,0 +1,15 @@
1
+ -- Harness v0 schema - migration 003
2
+ -- Machine-readable registry for user-provided project tools.
3
+
4
+ CREATE TABLE tool (
5
+ name TEXT PRIMARY KEY,
6
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
7
+ provider TEXT NOT NULL DEFAULT 'custom',
8
+ command TEXT NOT NULL,
9
+ description TEXT NOT NULL,
10
+ args TEXT,
11
+ responsibility TEXT NOT NULL,
12
+ since TEXT NOT NULL DEFAULT 'registered'
13
+ );
14
+
15
+ INSERT INTO schema_version (version) VALUES (3);
@@ -0,0 +1,15 @@
1
+ -- Harness v0 schema - migration 004
2
+ -- Review, human, CI, or agent interventions separated from normal traces.
3
+
4
+ CREATE TABLE intervention (
5
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
6
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
7
+ trace_id INTEGER REFERENCES trace(id),
8
+ story_id TEXT,
9
+ type TEXT NOT NULL CHECK(type IN ('correction','override','escalation','approval')),
10
+ description TEXT NOT NULL,
11
+ source TEXT NOT NULL CHECK(source IN ('human','reviewer','ci','agent')),
12
+ impact TEXT
13
+ );
14
+
15
+ INSERT INTO schema_version (version) VALUES (4);
@@ -0,0 +1,20 @@
1
+ -- Harness v0 schema - migration 005
2
+ -- Inbound tool registry: kind-aware presence + capability binding.
3
+ -- These columns turn the tool table from "declared intent" into
4
+ -- "intent + last-scanned reality" without breaking existing rows.
5
+ -- Adopted verbatim from repository-harness scripts/schema/005-tool-extensions.sql
6
+ -- to keep migrations 001-005 a faithful port of the upstream harness schema.
7
+
8
+ ALTER TABLE tool ADD COLUMN kind TEXT NOT NULL DEFAULT 'cli';
9
+ ALTER TABLE tool ADD COLUMN capability TEXT;
10
+ ALTER TABLE tool ADD COLUMN scan_target TEXT;
11
+ ALTER TABLE tool ADD COLUMN status TEXT NOT NULL DEFAULT 'unknown';
12
+ ALTER TABLE tool ADD COLUMN checked_at TEXT;
13
+
14
+ -- Backfill kind for tools registered before kinds existed, inferring it from
15
+ -- the agent-neutral command prefix convention so an upgrade does not mis-type
16
+ -- (and then falsely flag as broken) MCP servers or skills that are not on PATH.
17
+ UPDATE tool SET kind = 'mcp' WHERE command LIKE 'mcp:%';
18
+ UPDATE tool SET kind = 'skill' WHERE command LIKE 'skill:%';
19
+
20
+ INSERT INTO schema_version (version) VALUES (5);
@@ -0,0 +1,11 @@
1
+ -- Harness v0 schema - migration 009 (re-homed from 005 to free version 5 for the
2
+ -- upstream tool-extensions migration; flow-specific, not in repository-harness).
3
+ -- Usage signal: accessed_count tracks how often a durable row is surfaced by recall/query.
4
+ -- Read-only reuse signal: incremented on read only, NEVER used to delete or prune a row
5
+ -- (a rare-but-critical one-time lesson must survive a low access count). Surfaces what is reused.
6
+
7
+ ALTER TABLE decision ADD COLUMN accessed_count INTEGER NOT NULL DEFAULT 0;
8
+ ALTER TABLE trace ADD COLUMN accessed_count INTEGER NOT NULL DEFAULT 0;
9
+ ALTER TABLE backlog ADD COLUMN accessed_count INTEGER NOT NULL DEFAULT 0;
10
+
11
+ INSERT INTO schema_version (version) VALUES (9);
@@ -0,0 +1,42 @@
1
+ -- Harness schema - migration 010 (re-homed from 006; flow-specific, not in repository-harness).
2
+ -- Mechanical usage-log mirror. The append-only JSONL sinks (.flow/events.jsonl full,
3
+ -- ~/.claude/flow/usage.jsonl compact) are the source of truth; this table is a derived,
4
+ -- queryable rollup for `flow usage` stats. Idempotency rests on UNIQUE(src,line_no):
5
+ -- re-rolling the same append-only line is ignored. rollup_cursor stores the last line
6
+ -- number processed per source file (a skip-ahead optimization; correctness is the UNIQUE key).
7
+
8
+ CREATE TABLE usage_event (
9
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
10
+ src TEXT NOT NULL, -- absolute path of the JSONL sink the row came from
11
+ line_no INTEGER NOT NULL, -- 1-based line number within that file
12
+ epoch_s INTEGER,
13
+ session_id TEXT,
14
+ cycle_id TEXT,
15
+ project TEXT,
16
+ command TEXT,
17
+ args TEXT,
18
+ exit_code INTEGER,
19
+ gate_pass INTEGER, -- 1 / 0 / NULL (non-gate command)
20
+ duration_s INTEGER,
21
+ stage_from TEXT,
22
+ stage_to TEXT,
23
+ card TEXT,
24
+ project_type TEXT,
25
+ mode TEXT,
26
+ flow_version TEXT,
27
+ tier TEXT,
28
+ host TEXT,
29
+ read_only INTEGER,
30
+ UNIQUE(src, line_no)
31
+ );
32
+
33
+ CREATE INDEX idx_usage_event_cycle ON usage_event(cycle_id);
34
+ CREATE INDEX idx_usage_event_cmd ON usage_event(command);
35
+
36
+ CREATE TABLE rollup_cursor (
37
+ src TEXT PRIMARY KEY,
38
+ last_line INTEGER NOT NULL DEFAULT 0,
39
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
40
+ );
41
+
42
+ INSERT INTO schema_version (version) VALUES (10);
@@ -0,0 +1,8 @@
1
+ -- Harness schema - migration 011 (re-homed from 007; flow-specific, not in repository-harness).
2
+ -- Record WHICH gate check failed (not just the gate_pass bool) so "stage X fails often" is
3
+ -- diagnosable from the usage log. Additive column on the existing mirror; no new table.
4
+ -- Old JSONL lines without the field roll up as NULL (back-compatible).
5
+
6
+ ALTER TABLE usage_event ADD COLUMN gate_fail_reason TEXT;
7
+
8
+ INSERT INTO schema_version (version) VALUES (11);
@@ -0,0 +1,10 @@
1
+ -- Harness schema - migration 012 (re-homed from 008; flow-specific, not in repository-harness).
2
+ -- Mark throwaway/test runs so device-wide analytics aren't dominated by them. A run is
3
+ -- ephemeral when its project root is under the system temp dir or named like an mktemp dir.
4
+ -- Additive column; old JSONL lines without the field roll up as NULL and are treated as
5
+ -- non-ephemeral, except the read-time `project LIKE 'tmp.%'` fallback still excludes legacy
6
+ -- temp runs from the default view (back-compatible, no log rewrite).
7
+
8
+ ALTER TABLE usage_event ADD COLUMN ephemeral INTEGER;
9
+
10
+ INSERT INTO schema_version (version) VALUES (12);
@@ -0,0 +1,140 @@
1
+ # Project rules — buildflow project
2
+
3
+ This repo is a project run with the **buildflow** method. Planning artifacts live in
4
+ `flow/`, build cards in `cards/`. The method: every stage/card has a GATE; no gate pass,
5
+ no advance. Read `README.md` once for the method; THESE rules govern every session here.
6
+
7
+ ## /flow commands
8
+
9
+ `/flow` (status) · `/flow next` (gate-check + unlock stage) · `/flow card` (new card) ·
10
+ `/flow check C-NNN` (validate card) · `/flow mode teach|work` (who writes the plan) ·
11
+ `/flow retro` (3 questions → RETRO.md / playbooks/ / FLOW-FEEDBACK.md) ·
12
+ `/flow ready` (what's buildable now, parallel-safe groups) · `/flow auto` (autonomous
13
+ build run — preflight via runner, then drive per SKILL.md AUTO PRINCIPLES: subagent per
14
+ card, planner reviews + verifies, worktree isolation for parallel groups, operator-gated
15
+ cards halt by design, state in card files + AUTO-LOG.md).
16
+ Runner: `bash .claude/skills/flow/runner/flow.sh <cmd>`.
17
+
18
+ Modes (`MODE` file at root; default `teach`): **teach** — the user writes every artifact,
19
+ the AI only gatekeeps. **work** — the AI interviews the operator once, drafts stages 00-05
20
+ itself, pauses only for scope sign-off, delivers the card set as one summary. Gates and
21
+ done-rules are identical in both modes.
22
+
23
+ ## Build-session discipline (when implementing a card)
24
+
25
+ 1. ONE card per session. The card IS the session brief: build exactly its `## Scope`,
26
+ touch ONLY its `## Allowed files`. Need another file? Stop — amend the card first.
27
+ Default is serial, in card order. Parallel is allowed ONLY per the worktree protocol below.
28
+ 2. Two law files: the contract (`flow/05-contract.md`) for shapes, `DESIGN.md` for pixels.
29
+ Every UI card (mock + frontend) is built AND reviewed against DESIGN.md — tokens,
30
+ affordance ladder, object-first pattern, never-do list. Read it before any UI work.
31
+ The contract: never improvise a request/response shape.
32
+ If the contract is wrong, amend `flow/05-contract.md` FIRST, then code to it.
33
+ When the contract requires a field whose FEATURE belongs to a later card: honor the
34
+ SHAPE now (null/stub value, commented as such), deliver the VALUE in that feature's
35
+ card. Never omit the field — the UI card will consume the shape you ship.
36
+ 3. Run every `## Verify` step for real before claiming done. Paste actual output/URLs
37
+ into `## Evidence`. Only then set `status: done`, then run `/flow check C-NNN`.
38
+ 4. Done-evidence = world-state (deployed URL, curl output, DB row). "Tests pass" /
39
+ "code merged" are mid-pipeline, never done.
40
+ 5. Never check a gate box or write a planning artifact on the user's behalf.
41
+ Never set a card `done` without pasted evidence.
42
+ 6. Read any file flow.sh just created before first editing it.
43
+ 7. **Playbooks** (`playbooks/`): paid-for stack knowledge. Before building a card that
44
+ touches a stack with a playbook (check `playbooks/README.md` index), READ it and run
45
+ its smoke tests before committing to a design on that stack. After a card pays for a
46
+ non-obvious lesson, HARVEST it back into a playbook — the card review isn't done
47
+ until the lesson is filed. More stacks → more playbooks.
48
+
49
+ ## Standard card sequence
50
+
51
+ 1. **Scaffold + CI/CD** — repo, deploy pipeline, `/healthz` on a public URL. The scaffold
52
+ picks the spec-serving mechanism (FastAPI: free at `/docs` + `/openapi.json`; other
53
+ stacks: choose the generator in the ADR) — API docs are plumbing, not a later feature.
54
+ 2. **Vertical slice** — one contract endpoint + one ugly page calling it, deployed.
55
+ From this card on, `/docs` is LIVE on the deployed URL and shows the endpoint.
56
+ 3. **Backend cards** — one endpoint-group per card, built TO the contract.
57
+ **Swagger lands WITH the API**: every backend card's verify includes "the card's
58
+ endpoints appear in the live `/docs` with correct request/response schemas" — its
59
+ done-evidence includes the docs URL. Docs are never a catch-up card.
60
+ 4. **Contract-test card** — automated suite hitting EVERY contract endpoint with edge +
61
+ failure cases against the deployed API. The objective "feel safe" gate before UI.
62
+ If the framework serves OpenAPI (FastAPI: `/openapi.json`), the suite ALSO asserts
63
+ every `flow/05-contract.md` endpoint exists in the live spec with matching shapes —
64
+ planning contract and runtime swagger must never drift.
65
+ 5. **UI mock card** — static HTML, real copy, no logic/framework, rendered per `DESIGN.md`
66
+ (its tokens + patterns; the mock IS the design review). Done-evidence = the operator
67
+ viewed it in a browser and approved. Iterate here: mock retries cost seconds,
68
+ framework retries cost deploys.
69
+ 6. **Frontend cards** — implement the approved mock, consuming the contract, reviewed
70
+ against `DESIGN.md`.
71
+ 7. **E2E card** — automated browser test over the DEPLOYED app covering the PRD's user
72
+ actions; its run doubles as verify-live.
73
+
74
+ ## PR & merge protocol
75
+
76
+ Once the scaffold card lands, **main = deployable** (auto-deploy watches it). From then on:
77
+
78
+ 1. **Branch per card**: `card/C-NNN`, serial or parallel alike. No direct commits to main.
79
+ 2. **Commits**: plain ASCII messages (smart quotes / arrows can break CI+deploy hooks),
80
+ prefixed with the card id (`C-003: resident reply endpoint`), one logical change each.
81
+ 3. **PR per card** when the repo has a remote: title = the card's title; body = the card's
82
+ scope + the verify outputs (paste real runs). The card review — diff vs scope, vs
83
+ allowed-files, vs contract shapes, vs DESIGN.md for UI — happens ON the PR diff,
84
+ BEFORE merge. A card with failing verify steps does not get a PR.
85
+ 4. **Merge rules**:
86
+ - Merge in card-number order (deps guarantee order makes sense).
87
+ - After `gh pr create`, pushing more commits is a trap on squash-merge — trailing
88
+ commits can silently drop. If you must push post-create, re-check the PR's commit
89
+ list before merging, and verify the merged SHA on main contains every change.
90
+ - Delete the branch (and worktree) after merge — never with unmerged work.
91
+ 5. **Merge ≠ shipped.** After merge: deploy runs → verify the change on the LIVE URL
92
+ (deploy-success is not proof the surface changed). Only then does the card's
93
+ `## Evidence` get its world-state proof and `status: done`.
94
+ 6. **Auto runs**: the planner opens the PR, reviews the diff, merges green cards without
95
+ asking (Tier-A), and logs PR URL + merged SHA per card in AUTO-LOG.md. A red review
96
+ goes back to a fresh subagent (two-strikes rule applies).
97
+ 7. **No remote?** Local-only projects keep the same shape minus the PR: branch per card,
98
+ review the diff before merging to main, same live-verify rule.
99
+
100
+ ## Debt (deliberate gate-skips)
101
+
102
+ Reordering past the standard sequence or skipping a gate is a legitimate OPERATOR call
103
+ (demo-first, riskiest-first). But a skipped gate is a loan, and loans get written down:
104
+
105
+ 1. Every deliberate skip opens a line in `DEBT.md` (create it on first use):
106
+ `- [ ] DEBT: <what was skipped> — <the exposure, concretely> — close before: <named
107
+ condition, e.g. "any real user touches this"> — opened <date> (cards: C-NNN…)`
108
+ 2. **Security-class skips** (auth, public exposure of admin surfaces, tenancy, payments)
109
+ are NEVER silent and never planner-decided: the operator explicitly accepts the
110
+ exposure, in writing, in the DEBT line. In auto runs this is a Tier-C halt.
111
+ 3. A debt's close condition is checked at every retro and before anything is given to a
112
+ real user. Closing a project run with open security debt requires an explicit
113
+ operator acknowledgment — "temporary" is one forgotten step from production.
114
+ 4. Cards blocked by a debt (built but can't honestly reach done-evidence) stay
115
+ `todo` with PARTIAL evidence naming the debt — never half-done, never rounded up.
116
+
117
+ ## Parallel builds (worktree protocol)
118
+
119
+ Cards declare `deps:` (card ids, or "none"). `bash .claude/skills/flow/runner/flow.sh ready`
120
+ computes which todo cards have deps met AND no allowed-files overlap — only those may run
121
+ in parallel. The runner advises; the OPERATOR dispatches. Rules:
122
+
123
+ 1. One card = one worktree = one session:
124
+ `git worktree add ../<project>-C-NNN -b card/C-NNN`
125
+ 2. A session in a worktree obeys its card's allowed-files exactly (overlap was checked
126
+ against the card text — drifting outside it breaks the parallel-safety guarantee).
127
+ 3. Merge back in card-number order, one at a time: `/flow check C-NNN` passes →
128
+ merge to main → run the merged app once (deps-done means INTERFACE done, not proven
129
+ integration) → only then merge the next. Conflicts on merge = the overlap check was
130
+ gamed; stop and re-plan.
131
+ 4. Remove the worktree after merge: `git worktree remove ../<project>-C-NNN`.
132
+ 5. Cards whose verify needs the deployed app (contract-tests, e2e) are SERIAL by nature —
133
+ don't parallelize them.
134
+
135
+ ## Forbidden
136
+
137
+ - Building two cards in the SAME worktree/session, or in parallel without `flow.sh ready`
138
+ marking them safe (planning all cards up front is fine).
139
+ - Editing `_templates/` or `flow.sh` during a project run.
140
+ - Frontend code before the UI mock card is approved.
@@ -0,0 +1,141 @@
1
+ # Design law — buildflow projects
2
+
3
+ This file is LAW for every UI card in this project — the UI mock card and every
4
+ frontend card MUST be built and reviewed against it. If a change conflicts with a rule
5
+ here, the rule wins (or the rule is changed deliberately, in this file, with a dated note).
6
+
7
+ Two layers, treat them differently:
8
+ - **Structure is law**: the affordance ladder, object-first pattern, forms rules, and the
9
+ never-do list apply to any product. Don't relitigate these per project.
10
+ - **Tokens are taste**: the colors, fonts, and gradients below are one good default.
11
+ A project MAY replace them — deliberately, in this file, all at once, with a dated
12
+ note — never ad-hoc per component.
13
+
14
+ ## North Star
15
+
16
+ **Simple stupid UI for non-technical users; full power kept available — but never in the way.**
17
+
18
+ Users think in *their* objects ("my workshop", "my ticket", "my booking") — never in
19
+ engine concepts. Engine words (workflow, trigger, action, job, queue, webhook, agent,
20
+ prompt…) NEVER appear in user-facing copy. Define this project's vocabulary in the
21
+ table below and use it everywhere.
22
+
23
+ ### Project vocabulary (fill per project — strings, never code paths)
24
+
25
+ | Engine concept | This project's user word |
26
+ |---|---|
27
+ | _(e.g. async agent run)_ | _(e.g. "đang phân loại…")_ |
28
+
29
+ ## Five rules that override everything
30
+
31
+ 1. **Object-first, not feature-first.** The home page of a thing IS the thing. Tabs are
32
+ lenses on the same object — the user never navigates "out" to reach something related.
33
+ 2. **WYSIWYG, edited in place.** The daily 80% of edits happen inline on the object's own
34
+ page (see the affordance ladder). A separate Edit page exists only for the structural 20%.
35
+ 3. **Defaults beat configuration.** Creatable in ≤6 visible fields; everything else behind
36
+ one "More options" disclosure. If a default serves 80%, ship it and demote the toggle.
37
+ 4. **Plain language beats power syntax.** "4 days after it ends" — never cron. A field-picker
38
+ chip — never `{{ raw.templates }}`. No JSON in any simple surface.
39
+ 5. **Power behind a door.** If a power surface exists, it's a `Simple | Pro` toggle that
40
+ never loses data, plus a visible "switch to simple" path back. 95% never flip it.
41
+
42
+ ## Edit-affordance ladder (inline ↔ popup is a spectrum, not a switch)
43
+
44
+ Choose by the field's SEMANTIC SHAPE — always the lightest rung the shape allows.
45
+ Decision rule: count the inputs the user must touch to finish the edit.
46
+
47
+ | Rung | Field shape | Interaction |
48
+ |---|---|---|
49
+ | 1. Inline text | one free-text value | click → input in place → save on blur/Enter (optimistic) |
50
+ | 2. Inline control | one value, known set/format | click → the right native control in place (date picker, stepper, select) |
51
+ | 3. Popover composite | ONE displayed line composed of 2–4 sub-choices | click → popover anchored to the field, type-switch + matching input → "Done" writes one line |
52
+ | 4. Modal | a multi-field object, or a collection | "+ Add" / "Edit" → centered dialog with all fields |
53
+
54
+ - Popover edits **one display value**, dims nothing. Modal edits **an object or list**, dims the page.
55
+ Finishing produces one chip → popover. A new row in a list → modal. Never swap them.
56
+ - Inline-editable fields: text by default; hover reveals dotted underline + a 12px pencil;
57
+ click becomes the right affordance.
58
+ - **Empty state rides the same ladder**: a missing value renders as a dashed `+ Add {label}`
59
+ that opens its own rung. No field is ever a dead-end.
60
+
61
+ ## Object page pattern (the Luma pattern)
62
+
63
+ Every object-detail page:
64
+ - **Pulse strip** — at-a-glance metrics inline (calm, no stat-tile cards, no shadows).
65
+ - **Up to 3 hero action cards** — the top things a user does on this object. Big targets,
66
+ gradient-tinted, one click. NOT a kebab menu.
67
+ - **Tabs as lenses** — all on the same object. Active tab: 2px bottom border `var(--fg-base)`.
68
+ - **Modal-first sub-actions** — small focused modals, one CTA. No multi-screen flows.
69
+ - **The overview shows less, not more.** Heavy lifting goes to specialized tabs.
70
+
71
+ ## Editorial Minimal tokens (locked)
72
+
73
+ | Token | Value | Use |
74
+ |---|---|---|
75
+ | `--bg-base` | `#FFFFFF` | page bg, cards |
76
+ | `--bg-subtle` | `#FAFAFA` | sidebar, savebar, secondary surfaces |
77
+ | `--bg-muted` | `#F4F4F5` | hover, muted chips |
78
+ | `--fg-base` | `#09090B` | primary text, primary buttons |
79
+ | `--fg-muted` | `#52525B` | body, descriptions |
80
+ | `--fg-subtle` | `#71717A` | helper text, timestamps |
81
+ | `--border` | `#E4E4E7` | all 1px borders |
82
+ | `--accent` | `#4F46E5` | focus rings, accent links, validate-ok |
83
+
84
+ **Typography**: `Inter` body/labels/buttons · `Fraunces` h1, card titles, prominent stat
85
+ values ONLY · `JetBrains Mono` identifiers, dates, counts, machine-shaped content ONLY.
86
+ Don't sprinkle serif on body text or mono on prose.
87
+
88
+ **Borders**: 1px `var(--border)`. No drop shadows except focus rings, active sidebar item,
89
+ and hero-card hover lift. One purposeful elevation, never shadow noise.
90
+
91
+ ## Soft gradients (highlight, not decorate)
92
+
93
+ Hero surfaces ONLY (hero action cards, gallery/list covers, pulse backdrop). NEVER on
94
+ tables, form inputs, sidebars, page backgrounds, or body rows.
95
+
96
+ ```css
97
+ --grad-peach: linear-gradient(135deg, #FFF4EC 0%, #FEE7D6 100%); /* action / first in a series */
98
+ --grad-mint: linear-gradient(135deg, #ECFDF3 0%, #D1F4DD 100%); /* money / success / all-green */
99
+ --grad-sky: linear-gradient(135deg, #EEF4FF 0%, #DCE7FF 100%); /* info / context banners */
100
+ --grad-lavender: linear-gradient(135deg, #F3EEFF 0%, #E2D6FB 100%); /* primary surface / pulse */
101
+ --grad-rose: linear-gradient(135deg, #FFF1F4 0%, #FDDDE3 100%); /* social / sharing / accent */
102
+ --grad-pulse: linear-gradient(90deg, #FAFAFA 0%, #F3EEFF 50%, #FAFAFA 100%); /* subtle strips */
103
+ ```
104
+
105
+ Hover on gradient cards: lift `translateY(-1px)` + `box-shadow: 0 8px 24px rgba(9,9,11,.06)`;
106
+ no hard accent border.
107
+
108
+ ## Forms
109
+
110
+ - Max 6 visible fields on any create/edit page; more → disclosure.
111
+ - One column, max-width 640px for focused forms. No multi-step wizards for editing.
112
+ - Sticky savebar: white, 1px top border, optional 4px gradient accent strip.
113
+ - Labels 12px / 500 / `var(--fg-muted)`. Inputs 38px tall, 1px border, accent focus ring.
114
+
115
+ ## Iconography
116
+
117
+ Stroke line icons (Heroicons/Lucide style), stroke-width 1.6–2, no fill.
118
+ **No emojis. Anywhere. Ever.** Use SVGs.
119
+
120
+ ## VN conventions (when the project is Vietnamese-facing)
121
+
122
+ - Vietnamese copy throughout the user surface — written natively, not translated.
123
+ - Prices: `₫750,000` — symbol leading, comma groups. Never "VND 750000.00".
124
+ - VietQR scan-to-pay as the default payment presentation; cards demoted to "Thẻ quốc tế".
125
+ - Zalo as a first-class support-channel option, not only email.
126
+
127
+ ## What to never do
128
+
129
+ - Never leak engine words into user-facing copy (see vocabulary table).
130
+ - Never show raw `{{ }}` templates or JSON outside a power-user surface.
131
+ - Never use multi-step wizards for editing.
132
+ - Never gradient form inputs, body backgrounds, or table rows.
133
+ - Never stack shadows. Never add emojis. Never write design comments in HTML.
134
+
135
+ ## How this binds the cards
136
+
137
+ - The **UI mock card** renders these tokens/patterns in static HTML — the mock IS the
138
+ design review; the operator approves against this file.
139
+ - Every **frontend card**'s review checks the diff against this file the same way it
140
+ checks shapes against `flow/05-contract.md`. DESIGN.md is to pixels what the contract
141
+ is to shapes.
@@ -0,0 +1,13 @@
1
+ # Retro
2
+
3
+ After all cards are done, append ONE line per project run:
4
+ *Which gate did I skip or rush, and what did it cost?*
5
+
6
+ **Optional aid — the `retro` SKILL (opt-in).** Before writing the line, you may offer the `retro`
7
+ skill (git-history-driven: commit/velocity/code-health numbers) so the retro is backed by real
8
+ figures, not memory. It INFORMS the operator's line — **the operator still writes the line; the
9
+ skill never authors it** (the teach-mode rule holds). Distinct from the `journal-writer` agent
10
+ (narrative) — see `claudekit-skills.md`. After it runs at this gate, record the lazy durable
11
+ metric via `flow.sh harness intervention add`.
12
+
13
+ ---