SuperAPI AI Directory

br

Agents & models

View repository

Updated 10-16 01:13

About this skill

Skill: br — Ralph production line (BR-skill → frames → loop with harness)

BR = Business Requirements — the finalized requirements specification, located at br/BR.md. The skill is named after the central artifact it produces, not after a verb. Every frame and every clause traces back to that file, so "product bug ⇔ BR bug" (GH#15, 2026-07-03) is a premise of the whole line, not a slogan.

1-name hub: the user describes the scope (interview / compile / slice / run / status), NOT having to remember many commands. Foundation: council 028 (thin-slice, human-in-the-loop) + council 031/032 (loop v1 with 6 mandatory conditions — winner Taleb mean-rank 1.0).

WHAT

Purpose and context

  • Purpose: turn the user's raw requirements document into a disciplined product through the BR-skill → frames → loop with harness line, every frame and clause tracing back to br/BR.md.
  • Trigger (when to use):
    • User has a requirements document (raw/unstructured) and wants to turn it into a disciplined product.
    • User says: interview / requirements interview / draft BR / slice frame / run frame / line status / ralph.
  • Non-goals: does not write to llmwiki/raw/; does not rewrite the deterministic tooling already built (frame-lint.py, loop-runner.py, build-line-status.py…); does not commit/merge on the human's behalf; does not edit UI by hand outside /br run; does not hook auto-fire.

Mental model

llmwiki/raw/ → interview (spec-filled S1–S10 + câu hỏi hỏi-bù) → compile (BR.md có clause_id + "Giả định đang gánh" + BR.clauses.json) → slice (frames có depends_on, frame-lint gác) → run (loop-runner 6 phanh, commit per-frame, sổ trace) → qc / find / status (truy ngược lỗi→frame→clause). The user only describes the SCOPE; the hub picks the mode.

Input and output contract

Field Required? Meaning
In raw document in llmwiki/raw/ present (mode interview) read only; empty → ask the user to drop the document in
In br/interview/NNN-answers.md filled in present (mode compile) the user's real answers by field-id
In scope described by the user present interview · compile · slice · run · find · qc · status · sync · contract · rail
In flag --proactive · --lens-fill · --ack-tier · --worktree · --dry-run no optional branch (see Branches)
Out br/spec-filled.md, br/interview/NNN-{questions.html,answers.md} mode interview field has status + provenance
Out br/BR.md, br/BR.clauses.json, br/DESIGN.md (if there is a UI) mode compile check-contract green
Out br/frames/*.md, br/frames/index.md, br/prompts.md mode slice frame-lint green
Out commit frame(<id>), br/frames/<id>.run.json, .checkpoints.jsonl mode run one-line summary + medic
Out br/line-status.{json,html} + llmwiki/html/line-status.html mode status 3-line summary

Rules and capabilities

  • RULE-01 (MUST): The human is the final gate — DO NOT auto-commit/merge the output frame; dry-run + human approval (council 028).
  • RULE-02 (MUST): Inviolable brakes — never raise max_iter or disable a guard "so it finishes." Too many brakes is cheaper than too few (council 031/032).
  • RULE-03 (MUST): Prompt instructions are NOT a safety layer — scope-jail/test-hash are deterministic code (loop-runner guard 5/6), not wording in the prompt (council 5/5 seats).
  • RULE-04 (MUST): Lens-fill is always verified: false — never mixed with real answers; always shown in the "Assumptions being carried" table.
  • RULE-05 (MUST): Human-in-the-loop slicer in the first round — not yet full-auto (a slicer error is a correlated error, blast-radius = the whole BR).
  • RULE-06 (MUST): File-first, on-demand — every artifact is a travel-able file; the skill is invoked manually, NOT an auto-fire hook (ADR-004).
  • RULE-07 (MUST): HTML generated for humans to view must explain terminology + print the full path (R16).
  • Capabilities: read raw documents + codebase; write artifacts under br/; run deterministic tools (lint, loop, monitor) locally; call model adapters with narrowly scoped tools; create issues in an external tracker only after confirmation.

Failure boundaries

  • llmwiki/raw/ empty → clarify: ask the user to add the document.
  • br-fill.py check-contract RED → compile failed, fix the BR until it is green.
  • frame-lint.py check red, or a dirty working tree → /br run blocked (refuse to run).
  • Frame tier: compensable/irreversible has no --ack-tier → blocked (TIER-GATE).
  • KILL condition (e.g. diff-jail triggers ≥2 times / test-hash triggers once) → cancelled the whole run, no rescue, no raising the brakes.
  • Red frame → branch under status: blocked (partial), unrelated branches still run.
  • UI check without a real IMAGE FILE + MANIFEST.json → treat as failed (never happened).

HOW

Main workflow

Step Type Inputs Action Outputs/exit Failure/next
W01 judgment the user's words Choose the mode based on the scope the user described (1-name hub) mode ambiguous → ask again
W02 judgment llmwiki/raw/ + spec-template Mode 1 interview: extract raw into S1–S10, gap-diff, generate questions.html + answers.md 2 file NNN raw empty → clarify; --proactive → B01
W03 deterministic — STOP — user opens HTML + fills answers.md answers filled --lens-fill → B02
W04 judgment spec-filled + answers Mode 2 compile: BR.md + BR.clauses.json (+ DESIGN.md if UI exists) BR —
W05 deterministic BR Gate br-fill.py check-contract green red → fix BR, repeat W05
W06 judgment BR.md Mode 3 slice: propose slices, STOP for user to approve EACH slice, write frame per template frames + index —
W07 deterministic frames Guard frame-lint.py check + br-prompts.py sync lint green red → fix frame, repeat W07
W08 effect frame Mode 4 run: br-run.py run (tier-gate, lint, clean tree, loop-runner, commit, run_log_ref, trace ledger) commit frame + run log red → block downstream branches; KILL → discard run
W09 deterministic frames + run log + BR Mode 5 status: build-line-status.py build + 3-line summary line-status.html error falls into assumed → return W02 next round

Details of each step (source of truth for W01–W09 and all sub-modes):

Deterministic toolset (already built + selftest — DO NOT rewrite)

Tool Task selftest
skills/br/assets/spec-template.md standard spec set S1–S10 (reference frame for every project) —
skills/br/assets/frame-template.md DETERMINISTIC template for every frame (frontmatter + 4 body sections a human can understand) —
skills/br/assets/design-template.md reusable design template (Google design-doc frame + design system loaded from /high-end-visual-design) → copy to br/DESIGN.md —
fdk/tools/frame-lint.py guard frame with 7 rules (schema · scope · test-first · freshness · DAG · exclusive-scope has lease · content) frame-lint.py selftest
harness/scripts/loop-runner.py loop with 6 brakes (max_iter·budget·no_progress·escalate·diff-jail·test-hash) loop-runner.py selftest
fdk/tools/build-line-status.py deterministic monitor (frame·run-log·BR → json+html, --check) build-line-status.py selftest

Runtime artifacts live in br/ at the project root (not inside the skill): br/spec-filled.md, br/interview/NNN-{questions.html,answers.md}, br/BR.md, br/BR.clauses.json, br/frames/*.md, br/frames/index.md, br/frames/<id>.run.json, br/line-status.{json,html}.

Mode 1 — /br interview

  1. Read ALL files in llmwiki/raw/ (read-only — rule forbids writing to raw/). If empty → ask the user to drop in documents.
  2. Cross-check against the standard spec set skills/br/assets/spec-template.md: extract information from the raw map into each field S1–S10 → write br/spec-filled.md. EACH field write status (filled|missing|conflict|assumed) + provenance (raw:<file>).
  3. Gap-diff: field missing/conflict → generate the question set. Each field is ONE clear spec (rigor /orca-workflow): the question states WHAT the field DOES + "what counts as ENOUGH of an answer" (the field's acceptance criteria), no vague questions. Write 2 files (same ordinal NNN):
    • br/interview/NNN-questions.html — view by section, with term explanations + sufficiency criteria for each field, print full-path (R16), dark-mode. Ask ONLY about the missing parts.
    • br/interview/NNN-answers.md — block to fill in by field-id (e.g. ## S4.2 … blanks), for the user to type answers. 3b. --proactive (T-260714-01, short for /br auto) — the user wants the machine to fill in the missing parts instead of asking everything: run python3 fdk/tools/br-fill.py fill --root . (deterministic, no model). The tool looks up registry defaults (skills/br/assets/defaults.yaml — table of 26 loop conditions + github/spec-kit convention; project override br/defaults.yaml wins on field collision) and prints 2 groups:
    • MACHINE-FILL SUGGESTIONS → paste into NNN-answers.md, KEEP filled_by: <source>:<refs> + verified: false every item AS IS (lens-fill discipline applies to every machine-fill tier).
    • REAL QUESTIONS (field carve-out — auth/permissions, trust boundary, money — and fields with no default): pick ≤5 questions by Impact × Uncertainty (carve-outs are ranked first, taking question slots first) and put them into questions.html; anything over the cap gets lens-filled (step 5). A carve-out NEVER receives a machine value — even if the registry has an entry, even via lens.
  4. STOP — tell the user to open the HTML to view + fill in answers.md.
  5. If the user enables --lens-fill (or says "let an expert fill in the uncertain parts"): pick a lens with python3 harness/scripts/council.py roster --case product --json, fill the fields missing that the user marked "uncertain" → stamp each field filled_by: lens:<tên> + verified: false. Do NOT mix with the user's real answers.

Mode 2 — /br compile

  1. Read the filled-in br/spec-filled.md + br/interview/*-answers.md .
  2. Generate br/BR.md: each clause has clause_id (inherits field-id, e.g. S4.2) + provenance (raw|user|lens:<tên>). The top of the file is a table "Assumptions currently carrying" listing every clause lens/assumed (fail-fast: one glance shows what is being bet on).
    • Product has UI (S7.5): settle one NFR clause (e.g. N01 giao-diện) POINTING to br/DESIGN.md, do NOT copy design rules into the BR. Also copy skills/br/assets/design-template.md → br/DESIGN.md and fill in §1/§2/§4/§6/§7 for the product (keep §3/§5 inherited). BR = must have theme/design; DESIGN.md = what the design looks like.
  3. Generate br/BR.clauses.json: {clause_id: {provenance, assumed: bool, fields: ["S4.2", …]}} — fields declaring the S1–S10 spec fields that the clause implements (the contract checksum key); the monitor (/br status) reads this file to color assumed clauses orange. The "Assumptions currently carrying" table grouped by fill source (default / spec-kit / lens) so the reviewer sees what is being bet on and from where.
  4. Contract checksum gate (patch G1 — council c9dc13d): python3 fdk/tools/br-fill.py check-contract --root . — every required field S1–S10 must have a counterpart clause; RED means compile FAIL, fix the BR until it's green, there's no such thing as "compile finished but the contract has holes".

Mode 3 — /br slice

  1. Read br/BR.md. PROPOSE a list of slices: each slice = {clause_ids, expected scope_code (≤3 files), scope_test, acceptance_test, depends_on}. STOP for user to approve/edit/merge/split EACH slice (human-in-the-loop — the guard against slicer correlation errors). First batch ≤ 3–5 frames.
    • depends_on is mandatory to think about, not mandatory to have (GH#75, distill Atomic Task Graph): the chain is a GRAPH, not a list. Frame B declares depends_on: [frame-A] when B cannot be green if A isn't green yet (B calls an API/store/schema that A builds). If it depends on no one → depends_on: []. Declared correctly, you get three things free at mode 4: the run order is automatically right, a red frame automatically blocks the branch below it, and fixing one frame only requires rerunning its own branch. Declared carelessly (linking just so it "looks plausible"), you lose parallelism and create fake waits — only link when there's a REAL dependency.
  2. Write br/frames/frame-NNN-<slug>.md FOLLOWING THE TEMPLATE skills/br/assets/frame-template.md (schema v0 + 5 mandatory body sections: Business · Input/Output · Spec (FR/SC) · Acceptance criteria · Out of scope — written for a LATER PERSON to read and understand, frame-lint R7 enforces hard: frame_id must have a business slug, muc_tieu must not be generic, each frame has clear FR-id/SC-id, sections must not be empty) + parent_br_hash = sha256(br/BR.md).
  3. Generate registry br/frames/index.md (table frame_id · clause_ids · scope_code · status · run_log_ref) from the frames' frontmatter.
  4. Gate: python3 fdk/tools/frame-lint.py check br/frames --root . — all green before a slice counts as done (including R6 exclusive-scope: 2 frames not done must not tread on the same file).
    • R6 is a LEASE CONTRACT, not a land title: a frame that is done (run-log verdict: SUCCESS) releases the right to hold the file. Thanks to that, a new frame can be connected to the starting point (main.ts, state.ts, server.ts…) that an old frame used to hold — without a lease, new code goes green but never reaches the user (walleye 2026-09-10: 4 green frames, the player sees nothing). Two unfinished frames still holding the same file is still RED — unless depends_on has already arranged them in sequence (this frame is an ancestor of that one): in that case they never modify at the same time, and multiple features can be connected to the same main.ts one after another. _manifest.json hands the file to the last renter (the descendant).
    • Each feature must have a WIRING slice to the starting point, and a UI frame must be accepted by a test that goes through the real interface (e2e/route-shots), not by a unit test of the module standing alone.
  5. python3 fdk/tools/br-prompts.py sync — append prompt entry for new frames to the log br/prompts.md (the user can edit it by hand immediately).

Mode 4 — /br run <frame>

Deterministic invocation (already wired — default IN-PLACE, a SINGLE working tree):

python3 fdk/tools/br-run.py run br/frames/<frame>.md --root .
# xem prompt sẽ gửi mà không chạy: thêm --print-prompt
# chạy cả hàng đợi resumable: python3 fdk/tools/br-queue.py run --queue br/queue.yaml
# sửa 1 frame → chạy lại ĐÚNG nhánh của nó, không cả dây chuyền:
#   python3 fdk/tools/br-queue.py affected <frame_id> --queue br/queue.yaml --reset
#   python3 fdk/tools/br-queue.py run --queue br/queue.yaml
# cần cô lập thư mục thật sự (hiếm): thêm --worktree

Queue runs by GRAPH, not by hand-written order (GH#75 — distill Atomic Task Graph, arXiv 2607.01942):

  • Topo order: br-queue reads depends_on of each frame and orders them automatically (if there are no dependencies, the declared order is kept — the old queue runs exactly as before).
  • A red frame BLOCKS the entire branch below it (status: blocked, write blocked_by): the input of that branch is already broken; running on only burns model turns on something that is certain to fail. Unrelated branches still run normally — one broken frame no longer blocks the entire chain.
  • Local repair (affected): fix one frame → only that frame + the branch below it return to pending, every other green frame stays as is. This is where it pays off: previously one broken frame in the middle of a chain forced more reruns than necessary.
  • NO subgraph-reuse cache (the paper has it; we deliberately omit it): status: done already skips green frames; adding a hash-based cache at the scale of a few dozen frames only breeds stale bugs. The paper's own limitation applies here too — the benefit remains when the graph is small and acceptance_test is deterministic; for a very large graph or a test/tool that returns erratic results, this scheduling stops being useful. br-run.py itself: (0) TIER-GATE — a frame that declares tier: compensable|irreversible in its frontmatter (irreversible effect: calling an external API/sending mail/writing DB) is BLOCKED until a human reruns with --ack-tier (SHEPHERD gate-before-materialize), (1) frame-lint, (2) check the working tree is clean, (3) run loop-runner RIGHT IN the current tree with revise already pointed at fdk/tools/br-revise.py (render skills/br/assets/revise-prompt.md → claude -p tools narrowed), (4) green frame → commit to the current branch, message tagged frame_id (revert/blame marker), (5) print a 1-line summary, (6) write run_log_ref into the frame, (7) write the marker into the TRACE LOG .checkpoints.jsonl (checkpoint-trace/SHEPHERD — the record already points to the commit, no double-commit) → view the entire chain: python3 fdk/tools/checkpoint.py list; roll back the whole pipeline to any frame by NAME: checkpoint.py rollback <frame_id> (keeps history, warns about irreversible effect tiers after the marker). Why in-place is the default (user feedback 05/07): N frames = N worktrees = N ghost folders nobody digs through; the usual human flow is open the app and see, the fix must appear immediately in the tree the app is running from. Out-of-scope control lives in the HARNESS (diff-jail revert every round + FINAL SCOPE SWEEP + test-hash + scope_clean + R6 exclusive-scope), not in folder isolation. Don't like the result → git revert <commit frame>.

Equivalent manual steps (if fine-tuning by hand is needed):

  1. frame-lint check that frame is green. Check working-tree CLEAN (git status --porcelain empty) — if dirty, refuse.
  2. Create separate git worktree from baseline_ref of the frame (jail filesystem — the first frame does NOT touch harness/hook/CI).
  3. Run loop — commit per-frame INTO WORKTREE BRANCH (not main); human still merges manually:
    python3 harness/scripts/loop-runner.py run \
      --verify "<acceptance_test>" --revise "<adapter claude -p>" \
      --state "<scope_code>" --scope "<scope_code>" --protect "<scope_test>" \
      --baseline "<baseline_ref>" --commit-on-success \
      --commit-message "frame(<frame_id>): <muc_tieu> [<clause_ids>]" \
      --max-iter <g> --budget-seconds <g> --no-progress-k <g> --escalate-after <g> \
      --log br/frames/<id>.run.json --cwd <worktree>
    
    Adapter revise = claude -p with narrowly scoped tools (--allowedTools Edit,Write,Read,Grep,Glob — NO free Bash, no network), prompt built from muc_tieu + scope_code + latest failed verify output. Trace frame→code (prerequisite — ensure which frame created which code + no scope violation):
    • Run-log records changed_files = files the frame ACTUALLY changed (≠ intended scope); scope_clean=true when every file ⊆ scope_code; attempted_out_of_scope = files the frame INTENDED to write out of scope but that were reverted.
    • FINAL SCOPE SWEEP: on every loop stop (including PROTECT_VIOLATION), loop-runner cleanly reverts every file outside scope_code → worktree is ALWAYS scope-clean, changed_files ALWAYS ⊆ scope_code. Full control, not just relying on prompt instructions.
    • --commit-on-success only commits when verdict=SUCCESS AND scope_clean; message tagged with frame_id → git blame to trace back to the exact frame. --baseline = base commit for diff computation (usually the worktree HEAD at start).
Prompt & queue (run multiple frames, resumable)
  • 📒 MASTER PROMPT BOOK (PRIORITY source #1, user edits by hand without needing model): br/prompts.md — ONE file, each frame one entry ## <frame_id>. Open it, find the frame, edit/ADD content freely (placeholder {{...}} stays as-is for the machine to fill in at run time). python3 fdk/tools/br-prompts.py sync automatically adds entries for new frames, NEVER overwrites hand-edited entries (run after each /br slice); list/get <frame_id> to check. Priority order when running: prompt book > inline queue > prompt_file > default template.
  • Original template (seed for the book): skills/br/assets/revise-prompt.md. Adapter fdk/tools/br-revise.py renders the winning source → calls claude -p (narrowly scoped tools). See the prompt that will be sent: br-revise.py run --frame <f> --verify "<cmd>" --print.
  • QUEUE file (br/queue.yaml, template skills/br/assets/queue.example.yaml): LIST of frames to run sequentially; each entry is either prompt_file: (points to a template file) OR prompt: (writes text directly, still supports placeholders). Driver fdk/tools/br-queue.py run --queue br/queue.yaml runs each entry, writes status back after EACH entry → re-running the queue = skip done, continue (resume). --dry-run shows which prompt each entry uses; list shows status.
  • Adapter claude -p is the boundary verified:false (BNAL) — template + queue + render are all deterministic + selftest (br-revise.py selftest, br-queue.py selftest).
  1. KILL conditions written BEFOREHAND (via negativa): e.g. diff-jail bites ≥2 times / test-hash bites once → discard the whole run, no rescue, no loosening the brakes.
  2. Loop stops → prints ONE-LINE summary (verdict · round count · diffstat · final verify command) + run python3 fdk/tools/medic.py --ci. STOP — the reader reviews the diff in the worktree, decides for themselves whether to merge/continue/discard.
  3. Fill in run_log_ref + outcome into the frame + registry. Record lessons (including what did NOT happen — which brake has never bitten).

Mode 4b — /br find <file-hoặc-từ-khoá> — point at the fault location, get back the responsible frame/prompt

Normal-person flow: open the app → see the bug → point at that spot:

python3 fdk/tools/br-find.py "src/auth/login.py"     # theo file
python3 fdk/tools/br-find.py "đăng nhập"              # theo từ khoá / clause

Print out: responsible frame (matched by the ACTUAL changed file > scope_code > keyword) · BR clause · where the prompt lives (inline in queue.yaml / prompt_file / default template) · the command to re-run EXACTLY that frame after fixing the prompt. This works because R6 exclusive-scope (frame-lint) forces each file to belong to only ONE frame at a time — if a file's owner has changed via lease, the responsible frame is the last lessee (_manifest.json), while history is git blame by commit frame(<id>).

Mode 4c — /br qc [frame] — senior QC audit (4-point LLM) on the mockup/frame

Once you have a green mockup/frame, run the SENIOR EYES (expensive=LLM, called by hand — the cheap deterministic part already ran automatically after each /br run):

  • Code: call /qc-code (Skill tool → qc-code) to review the frame diff — 4 items security/performance/naming/logic + generate a reproduction test qc-*.
  • UI/UX: call /qc-uiux (Skill tool → qc-uiux) audit the mockup — 4 items a11y/hierarchy/consistency/antipattern; the measurable part (contrast/tap-target/overlap/misalign/missing-label) runs through the visual-qa headless engine:
    node skills/visual-qa/assets/route-shots.mjs <base-url-mockup> --audit
    
  • Verdict NEEDS FIX → fix before locking the frame. Advisory — the LLM verdict is an opinion; engine measurements + tests qc-* are what hard-gate it (already ran automatically at /br run and verify-before-commit step 3b). No frame specified → audit the existing mockup routes.

Mode 5 — /br status

  1. python3 fdk/tools/build-line-status.py build --root . → br/line-status.json + llmwiki/html/line-status.html.
  2. Print a 3-line summary (overall status · most notable frame · HTML path). Page for tracing back bug→frame→clause; assumed clauses shaded orange → go back to /br interview next round if the bug falls under assumed.

Mode 6 — /br sync (frame ↔ GitHub sub-issue)

Distill automazeio/ccpm: each frame → one GitHub sub-issue so the team can see progress + hand-off. Do NOT redo provenance (clause_id/manifest already go deeper than ccpm); just a thin sync layer on top of gh.

  1. python3 fdk/tools/br-sync.py sync br/frames --root . --repo <owner/repo> --dry-run — ALWAYS dry-run first (no gh calls, no mapping writes).
  2. Drop --dry-run once sure → create a sub-issue for unmapped frames, write br/frames/issue-mapping.json. Idempotent. --epic creates the epic issue. status/selftest is available.
  3. Creating an issue is an action outside the repo → confirm before dropping --dry-run.

Mode 7 — /br contract (UI Contract locks in the implementation, md+html)

Separate the CODE axis (frame) from the DISPLAY axis (screen/route). The standard for every project:

  1. Frame declares ui_role: none|screen|panel|widget|form|action + ui_screen (frame-template) + section "## How the UI works".
  2. br/ui-layout.yaml: nav_style + screens[] (id·title·real route·frames[]). Editing this file gathers screens WITHOUT touching frames.
  3. python3 fdk/tools/br-contract.py build br/frames --layout br/ui-layout.yaml --root . → br/UI-CONTRACT.md + .html. Table frame·what it does·ui_role·screen·route·clause·acceptance + count of frames/screens/routes + mismatch warnings. selftest is available.

Branches

ID Kind Guard Behavior Skip / failure Rejoin
B01 user_optional --proactive (abbreviated /br auto) at interview br-fill.py fill proposes machine-filled (verified: false) + ≤5 real questions by Impact × Uncertainty; carve-out does not accept machine values exceeds ceiling → lens-fill W03
B02 user_optional --lens-fill or "let the expert fill in uncertain items" council.py roster --case product --json, fill missing fields the user marked uncertain, stamp filled_by: lens:<tên> + verified: false not mixed with real answers W04
B03 conditional_required product has UI (S7.5) clause NFR points to br/DESIGN.md; copy design-template.md → br/DESIGN.md, fill in §1/§2/§4/§6/§7 no UI → skip W05
B04 conditional_required frame has ui_role other than none /design-twice before coding; acceptance_test is visual-qa route-shots.mjs --assert missing item ## Thiết kế (design-twice) → frame not done W08
B05 conditional_required frame declares tier: compensable or irreversible blocks until rerun with --ack-tier no ack → does not run W08
B06 capability_optional needs real directory isolation (rare) add --worktree, or an equivalent manual step (separate worktree from baseline_ref) — W08
B07 user_optional run multiple frames / edit one frame br-queue.py run --queue br/queue.yaml in topo order; affected <frame_id> --reset rerun the correct branch red frame blocks downstream branches W09
B08 user_optional /br find <file-hoặc-từ-khoá> Mode 4b: br-find.py in the responsible frame + clause + prompt place + rerun command — W08 (edit prompt then rerun)
B09 user_optional /br qc [frame] Mode 4c: /qc-code + /qc-uiux (advisory); verdict NEEDS FIXING → fix before locking the frame — W08
B10 user_optional /br sync Mode 6: br-sync.py sync --dry-run first, confirm then remove --dry-run not confirmed → stop at dry-run end
B11 user_optional /br contract Mode 7: br-contract.py build → br/UI-CONTRACT.md + .html — end
B12 user_optional /br rail off or skip turn off SOFT gate (R7 content · visual-qa UI · assumption-gate) via frame-lint … --soft-off; hard brake stays as is skip auto re-enables after 1 run W08

Validation and stopping

Deterministic: frame-lint.py check (7 rules), br-fill.py check-contract, loop-runner 6 brakes + FINAL SCOPE SWEEP, medic.py --ci after each loop, each tool's selftest (frame-lint.py selftest, loop-runner.py selftest, build-line-status.py selftest, br-revise.py selftest, br-queue.py selftest). Review needed (human is the final gate): approve answers, approve EACH slice in the slice, read frame diff then decide merge/continue/discard. Mode stops at the recorded STOP points; loop stops according to brakes, no brake escalation.

Examples

  • Positive: user drops 3 requested files into llmwiki/raw/, says "draft BR" → interview generates br/interview/001-questions.html asks for the 7 missing fields → user fills them in → compiles to br/BR.md + check-contract green → slice proposes 4 slices, user approves → frame-lint.py check br/frames --root . green → br-run.py run br/frames/frame-001-dang-nhap.md --root . → SUCCESS, commit frame(frame-001-dang-nhap): …, one-line summary + medic.
  • Boundary/failure: /br run when git status --porcelain is not empty → refuse to run. Mail-sending frame declares tier: irreversible → TIER-GATE blocks until --ack-tier. Frame-003 red → frame-004 (depends_on: [frame-003]) becomes status: blocked, unrelated frame-005 still runs.

Reference — Unified Stream UI + Clear Spec (distill hallmark + orca-workflow)

Two gaps of the multi-frame pipeline, patched by two distill mechanisms:

A. UI/UX unified ACROSS FRAMES (distill hallmark). Each frame runs independently through loop-runner → easy for each frame to look different, patchwork mockups. hallmark mechanism: br/DESIGN.md = LOCKED TOKEN SYSTEM, read first and overrides all choices; INVERSION rule — frames must be SIMILAR (share the system), not diversified; locked-token — every color/font/spacing points to a named token (var(--…)), inline FORBIDDEN. Applied to /br:

  • /br compile copy design-template.md→br/DESIGN.md with token table §4 + §4.1 (locked tokens) as the SOURCE OF TRUTH.
  • Frame UI in ## UI hoạt động ra sao uses only DESIGN.md tokens; adding a new value = add a token to DESIGN.md then point to it, do not make one up at the frame.
  • Token drift is caught by /qc-uiux (consistency) + visual-qa engine → the "stream" runs by deterministic gate, not by verbal reminders. Result: frame-01 and frame-09 look like ONE product.

B. Every frame + interview screen needs a clear SPEC (learn from /orca-workflow). Propose FR/SC durable ids + acceptance; /br carry that rigor down every link in the chain:

  • Frame: frame-template has section ## Spec (FR/SC) (frame-lint R7 enforces hard) — each frame declares an FR-id (system MUST…) + SC-id (measure a PERSON), acceptance_test is the evidence for the SC, each acceptance line traces back to an FR. A frame missing clear FR/SC = not done, just like an interview missing fields.
  • Interview: each field S1–S10 asked must yield ONE clear spec — the question states what the field is for + the criterion for "what counts as ENOUGH of an answer" (no vague questions). Fields still missing/assumed = spec not sufficient, shown in the "Assumptions currently carrying" table so they don't drift.

Reference — DESIGN round for UI frames (skill /design-twice) — run BEFORE coding

Mandatory for every frame ui_role≠none: before writing a single line of UI code, run /design-twice to get 2–3 FUNDAMENTALLY DIFFERENT options, compare, pick 1, then write section ## Thiết kế (design-twice) into the frame itself (3 options + chosen option + reasons + ideas merged from the losers).

  • Why: the first idea is the easiest idea to think of, not the best idea. With no options to compare, the agent only knows how to patch the single option — each patch round spawns a new bug (Lume theme: 5 patch rounds).
  • Signal to go back to the design round: currently patching for the 2nd time in the same place, or the user complains "ugly/crappy/don't like it" without pointing out a specific flaw ⇒ wrong shape, more patching is wasted effort.
  • UI frame missing section ## Thiết kế (design-twice) = not done (R7 content treats it as missing content).
  • Only after design is done do we get to ## UI hoạt động ra sao → code → gate /visual-qa below.

Reference — VISUAL self-check round for UI frames (skill /visual-qa)

Principle (not a separate re-check rule): editing UI = edit the spec + code OF THAT FRAME then /br run again. If you want "re-running the frame self-re-verifies the UI", then acceptance_test of the UI frame must BE visual-qa — the test hits the UI, not a unit-test on the side. This is a high-leverage point: no need to tell the agent "remember to re-check", because the frame's own verify loop already embraces the UI check.

  • Frame ui_role≠none sets: acceptance_test: "node skills/visual-qa/assets/route-shots.mjs --base <url> --route <route> --assert --user <u> --pass <p> --out <dir>" → exit 1 if the route is not 200/empty → frame RED until the UI renders correctly. /br run again after each fix = self re-verify.
  • After green, the agent Read image (skill /visual-qa) → FINDINGS.md (route·level·fix) → each finding is a fix to the frame's spec+code → /br run again. Catches theme/brand/empty-state bugs unit-tests can't see; use when the MCP extension breaks on localhost.
  • Do not manually edit the UI outside /br run (debt p28 05/07): manual edit = lose gate + no re-verify. All UI edits must go through the frame.

Reference — Rail — the pipeline's harness switch (/br rail on|off|skip)

"On the rails" = currently within guard scope. DEFAULT ON — auto-on for the whole session when using /br.

  • python3 fdk/tools/br-rail.py status --root . → status + ALWAYS remind that it can be turned on/off.
  • on (fully guarded) · off (turn off SOFT gate until re-enabled) · skip (skip soft gate EXACTLY 1 time then auto re-enable + warning).
  • SAFETY (invariant): off/skip ONLY turns off soft gate — R7 content · visual-qa UI · assumption-gate. HARD BRAKE (diff-jail · test-hash · scope-clean) + R1–R6 structure + security hook are NEVER turned off via this.
  • Wiring: start of /br run, reads br-rail.py consume → if off/skip then calls frame-lint … --soft-off (skips R7+assumption), loop-runner hard brake remains intact; PRINT Rail status + reminder line on every run.

Reference — Evidence > words (UI check rule — feedback 2026-07-13)

UI/visual check is only valid when there is REAL IMAGE FILE + MANIFEST.json listing route→image→bytes (skill /visual-qa). No file = NEVER DONE = fail, regardless of what the model says. After editing the UI you must RE-capture + re-read before green. Forbidden to "let it pass" by reasoning. (Also the /fdk rule.)