From 2f10d9de0a34cfde4c8213073fa87a99cd5a403f Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 17:23:56 +0800 Subject: [PATCH 01/10] fix(ci): make anti-patterns-lint hook BSD-portable (macOS) macOS CI failed in anti-patterns-lint.test.sh (Cases 4/5/6) on two BSD-incompatibilities, both in hooks/anti-patterns-lint.sh: - no-consumer used git grep -lE with a \b word boundary. \b is a GNU regex extension that BSD regcomp (macOS) rejects, so cross-file references were never found and referenced symbols were wrongly flagged as orphans. Switched to git grep's own portable -lwF -e (word match + fixed string). - copy-paste / no-consumer self-exclusion stripped $REPO_ROOT/ from an uncanonicalized FILE_PATH. On macOS the worktree sits under /var -> /private/var, so git rev-parse --show-toplevel returns a canonical root the raw path does not match: REL_FILE stayed absolute, REL_DIR collapsed to ".", and a file matched itself. Canonicalize FILE_DIR with pwd -P (POSIX; BSD lacks readlink -f) before deriving repo-relative paths. Reproduced on Linux via a symlinked TMPDIR (TMPDIR=/tmp/link -> /tmp/real); all 14 cases pass normally and under the symlink. Audited comments-lint.sh and code-map-refresh.sh: neither has the self-exclusion nor the git-grep-\b pattern, so no change needed. Co-Authored-By: Claude Opus 4.8 (1M context) --- hooks/anti-patterns-lint.sh | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/hooks/anti-patterns-lint.sh b/hooks/anti-patterns-lint.sh index 24699da..a30e729 100755 --- a/hooks/anti-patterns-lint.sh +++ b/hooks/anti-patterns-lint.sh @@ -82,6 +82,14 @@ if ! command -v git >/dev/null 2>&1; then fi FILE_DIR="$(dirname "$FILE_PATH")" +# Canonicalize the directory so it matches git's symlink-resolved +# --show-toplevel output. On macOS the temp/working tree can sit under +# /var -> /private/var (or /tmp -> /private/tmp); without this the REPO_ROOT +# prefix strip below would fail, leaving REL_FILE absolute and REL_DIR collapsed +# to ".", which breaks both the diff pathspec and the self-exclusion. pwd -P is +# POSIX-portable; readlink -f is not (BSD lacks it). +FILE_DIR="$(cd "$FILE_DIR" 2>/dev/null && pwd -P || printf '%s' "$FILE_DIR")" +FILE_PATH="$FILE_DIR/$(basename "$FILE_PATH")" REPO_ROOT="$(git -C "$FILE_DIR" rev-parse --show-toplevel 2>/dev/null)" if [[ -z "$REPO_ROOT" ]]; then do_it_debug anti-patterns-lint "decision=skip reason=not-a-git-repo" @@ -187,9 +195,11 @@ case "$FILE_PATH" in NO_CONSUMER_NAMES="" while IFS= read -r name; do [[ -z "$name" ]] && continue - # Search for any reference to `name` in other JS/TS files. Use a basic - # word-boundary regex; this catches `Name(`, `Name.`, ` Name `, etc. - REFS="$(_doit_timeout 5s git -C "$REPO_ROOT" grep -lE "\\b${name}\\b" \ + # Search for any reference to `name` in other JS/TS files. Use git + # grep's own `-w` word match with `-F` fixed string — portable to BSD + # (macOS), unlike a GNU `\b` regex which BSD regcomp does not support. + # This still catches `Name(`, `Name.`, ` Name `, etc. at word boundaries. + REFS="$(_doit_timeout 5s git -C "$REPO_ROOT" grep -lwF -e "$name" \ -- '*.ts' '*.tsx' '*.js' '*.jsx' '*.mjs' '*.cjs' 2>/dev/null || true)" # Drop the current file from the result. REL_FILE="${FILE_PATH#"${REPO_ROOT}/"}" From c82166b570d641b70085504fd088801017031970 Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 17:34:03 +0800 Subject: [PATCH 02/10] refactor(handbook): cut 5 skill-duplicating process docs, keep 7 truth files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The handbook scaffolded 12 templates (~869 lines); 5 duplicated content the owning skills already define, and do-it never dogfooded them, so the per-project "customization point" intent (commit 98a380b) never materialized — it was pure duplicate-doc maintenance drift. Removed (owning skill is now the single source of truth): - task-card-template.md -> do-it-planning owns the task-card layout - workflow/review-protocol.md -> do-it-review-loop - workflow/subagent-dispatch -> do-it-subagent-orchestration - workflow/agent-workflow.md -> distilled into do-it-router (Execution Pipeline) - maintenance.md -> folded into do-it-handbook SKILL (Maintenance) Kept (project-specific truth a generic skill cannot carry): README, invariants, architecture, code-map, glossary, backlog, runtime-status. Updated every reference: handbook SKILL file-layout / relationship table / output / related-skills, the /do-it-handbook command description, kept-template cross-links (README, glossary, code-map, invariants), do-it-planning task-card layout, do-it-visual-planning card reference. Regenerated plugins/do-it bundle and index.json. npm test green; check-skill-links: 22 skills, 3 commands, all cross-references resolve. Co-Authored-By: Claude Opus 4.8 (1M context) --- commands/do-it-handbook.md | 2 +- index.json | 2 +- plugins/do-it/skills/_index.md | 2 +- plugins/do-it/skills/do-it-handbook/SKILL.md | 70 +++++++--- .../skills/do-it-handbook/templates/README.md | 25 ++-- .../do-it-handbook/templates/code-map.md | 2 +- .../do-it-handbook/templates/glossary.md | 5 +- .../do-it-handbook/templates/invariants.md | 4 +- .../do-it-handbook/templates/maintenance.md | 76 ---------- .../templates/task-card-template.md | 130 ------------------ .../templates/workflow/agent-workflow.md | 82 ----------- .../templates/workflow/review-protocol.md | 80 ----------- .../templates/workflow/subagent-dispatch.md | 116 ---------------- plugins/do-it/skills/do-it-planning/SKILL.md | 23 +++- plugins/do-it/skills/do-it-router/SKILL.md | 31 +++++ .../skills/do-it-visual-planning/SKILL.md | 2 +- skills/do-it/do-it-handbook/SKILL.md | 70 +++++++--- .../do-it/do-it-handbook/templates/README.md | 25 ++-- .../do-it-handbook/templates/code-map.md | 2 +- .../do-it-handbook/templates/glossary.md | 5 +- .../do-it-handbook/templates/invariants.md | 4 +- .../do-it-handbook/templates/maintenance.md | 76 ---------- .../templates/task-card-template.md | 130 ------------------ .../templates/workflow/agent-workflow.md | 82 ----------- .../templates/workflow/review-protocol.md | 80 ----------- .../templates/workflow/subagent-dispatch.md | 116 ---------------- skills/do-it/do-it-planning/SKILL.md | 23 +++- skills/do-it/do-it-router/SKILL.md | 31 +++++ skills/do-it/do-it-visual-planning/SKILL.md | 2 +- 29 files changed, 237 insertions(+), 1061 deletions(-) delete mode 100644 plugins/do-it/skills/do-it-handbook/templates/maintenance.md delete mode 100644 plugins/do-it/skills/do-it-handbook/templates/task-card-template.md delete mode 100644 plugins/do-it/skills/do-it-handbook/templates/workflow/agent-workflow.md delete mode 100644 plugins/do-it/skills/do-it-handbook/templates/workflow/review-protocol.md delete mode 100644 plugins/do-it/skills/do-it-handbook/templates/workflow/subagent-dispatch.md delete mode 100644 skills/do-it/do-it-handbook/templates/maintenance.md delete mode 100644 skills/do-it/do-it-handbook/templates/task-card-template.md delete mode 100644 skills/do-it/do-it-handbook/templates/workflow/agent-workflow.md delete mode 100644 skills/do-it/do-it-handbook/templates/workflow/review-protocol.md delete mode 100644 skills/do-it/do-it-handbook/templates/workflow/subagent-dispatch.md diff --git a/commands/do-it-handbook.md b/commands/do-it-handbook.md index 8fead3c..ec1f043 100644 --- a/commands/do-it-handbook.md +++ b/commands/do-it-handbook.md @@ -1,5 +1,5 @@ --- -description: 在当前项目里铺一份 .do-it/handbook/ 骨架(invariants / architecture / code-map / glossary / backlog / runtime-status / maintenance / task-card-template + 三个 workflow 文件),仅补齐缺失文件,不覆盖已有内容。 +description: 在当前项目里铺一份 .do-it/handbook/ 骨架(invariants / architecture / code-map / glossary / backlog / runtime-status),仅补齐缺失文件,不覆盖已有内容。 --- # /do-it-handbook diff --git a/index.json b/index.json index 79d5eb6..2f251be 100644 --- a/index.json +++ b/index.json @@ -232,7 +232,7 @@ { "kind": "skill", "name": "do-it-handbook", - "description": "Use when a project needs a durable `.do-it/handbook/` skeleton for architecture, glossary, code map, backlog, runtime, maintenance, and workflow docs.", + "description": "Use when a project needs a durable `.do-it/handbook/` skeleton for architecture, invariants, glossary, code map, backlog, and runtime status.", "origin": "do-it", "optional": false, "group": "maintenance", diff --git a/plugins/do-it/skills/_index.md b/plugins/do-it/skills/_index.md index ef098a6..baba0d8 100644 --- a/plugins/do-it/skills/_index.md +++ b/plugins/do-it/skills/_index.md @@ -34,7 +34,7 @@ router 推荐按需加载:用 Skill 工具 + skill 名加载详情;不要一 ## Handbook & 维护 -- **do-it-handbook** — a project needs a durable `.do-it/handbook/` skeleton for architecture, glossa… +- **do-it-handbook** — a project needs a durable `.do-it/handbook/` skeleton for architecture, invari… - **do-it-context** — repo terms or invariants are drifting and `.do-it/CONTEXT.md` should become th… - **do-it-grill-log** — grill facts or decisions need durable status logging as kind fact or decision… - **do-it-skill-authoring** — creating or updating do-it skills and you need clear triggers, return shape, w… diff --git a/plugins/do-it/skills/do-it-handbook/SKILL.md b/plugins/do-it/skills/do-it-handbook/SKILL.md index b6970cb..87af4b6 100644 --- a/plugins/do-it/skills/do-it-handbook/SKILL.md +++ b/plugins/do-it/skills/do-it-handbook/SKILL.md @@ -1,13 +1,13 @@ --- name: do-it-handbook -description: "Use when a project needs a durable `.do-it/handbook/` skeleton for architecture, glossary, code map, backlog, runtime, maintenance, and workflow docs." +description: "Use when a project needs a durable `.do-it/handbook/` skeleton for architecture, invariants, glossary, code map, backlog, and runtime status." --- # Do-It Handbook ## Purpose -Use this to scaffold a long-lived handbook for a project that uses `do-it`. The handbook is the agent-readable source of truth for terms, invariants, ownership, and review discipline that does not change every turn. It complements the per-task artifacts (`.do-it/grill/`, `.do-it/plans/`, `.do-it/brainstorm/`) and the always-active sediment (`.do-it/CONTEXT.md`). +Use this to scaffold a long-lived handbook for a project that uses `do-it`. The handbook is the agent-readable source of truth for terms, invariants, ownership, and architecture that does not change every turn. It complements the per-task artifacts (`.do-it/grill/`, `.do-it/plans/`, `.do-it/brainstorm/`) and the always-active sediment (`.do-it/CONTEXT.md`). The shape is borrowed from a project that has shipped against it for a year (Do-SOUL Alaya). Files are intentionally small (< 30 KB each) so the agent can read whatever it needs without bloating context. @@ -33,14 +33,16 @@ Skip when: glossary.md # vocabulary (long-stable terms) backlog.md # cross-cutting unresolved issues with close conditions runtime-status.md # implementation status and known wiring gaps - maintenance.md # documentation update rules - task-card-template.md # template for non-trivial work briefs - workflow/ - agent-workflow.md # per-card / per-wave / phase pipelines - review-protocol.md # review mode, severity, evidence expectations - subagent-dispatch.md # how delegated workers are constrained ``` +The handbook holds only **project-specific truth** — the facts a generic skill +cannot carry. Process docs (task-card layout, review protocol, subagent +dispatch, execution pipeline, maintenance rules) are NOT scaffolded here: the +owning skills are their single source of truth (`do-it-planning`, +`do-it-review-loop`, `do-it-subagent-orchestration`, `do-it-router`, and the +`## Maintenance` section below). This keeps the handbook small and removes the +duplicate-doc drift that comes from copying skill prose into every project. + ## Bootstrap Behavior When invoked: @@ -50,7 +52,7 @@ When invoked: - If it does **and** some files are missing, copy only the missing files (additive, never overwrite). - If it does not exist, create the full tree. 2. Templates are copied verbatim from `templates/` under this skill. Each template is a skeleton with placeholder text the project owner replaces; do not hand-edit the project's handbook from inside the bootstrap step. -3. Add a `.gitkeep` to `.do-it/brainstorm/`, `.do-it/grill/`, `.do-it/plans/`, and `.do-it/handbook/workflow/` if any of those directories are missing, so the project tracks them in version control. +3. Add a `.gitkeep` to `.do-it/brainstorm/`, `.do-it/grill/`, and `.do-it/plans/` if any of those directories are missing, so the project tracks them in version control. 4. Print one line per file written, then a one-paragraph "next steps" pointer telling the user to start by filling in `invariants.md` and `glossary.md`. Do **not**: @@ -66,11 +68,14 @@ Do **not**: | `do-it-context` | `.do-it/CONTEXT.md` (active sediment) | `glossary.md` (long-stable terms) | | `do-it-architecture-scan` | inline review output | `architecture.md`, `invariants.md` | | `do-it-grill` | `.do-it/grill/.md` | `invariants.md`, `glossary.md` | -| `do-it-planning` | `.do-it/plans/.md` | `task-card-template.md` | -| `do-it-review-loop` | `.do-it/review/.md` | `workflow/review-protocol.md`, `invariants.md` | -| `do-it-subagent-orchestration` | the dispatch contract | `workflow/subagent-dispatch.md` | +| `do-it-review-loop` | `.do-it/review/.md` | `invariants.md` | | code-mapper agent | summary returned to parent | writes `code-map.md` "Current implementation locations" section | +`do-it-planning` owns the task-card layout itself, `do-it-review-loop` owns the +review protocol, and `do-it-subagent-orchestration` owns the dispatch contract — +none of them read a handbook copy. The handbook only feeds them project-specific +truth (`invariants.md`, `glossary.md`, `architecture.md`). + The handbook is read-mostly. The only file that gets written by an agent on a regular basis is `code-map.md`, and only by `code-mapper` per the contract in its agent definition. ## Term Promotion Rule (`.do-it/CONTEXT.md` ↔ `glossary.md`) @@ -84,12 +89,39 @@ To prevent drift between the active sediment and the stable glossary: This rule is enforced by the agent during `do-it-context` writes, not by tooling. Stating it once here keeps both files honest. +## Maintenance + +When and how to update each handbook file. The per-session sediment +(`.do-it/CONTEXT.md`) and per-task artifacts (`.do-it/grill/`, `.do-it/plans/`, +`.do-it/review/`) live outside the handbook; the project root `README.md` / +`CLAUDE.md` are entry points that delegate detail here. + +Update triggers: + +- **Implementation moved** → update `code-map.md` "Current implementation + locations" (normally the `code-mapper` agent) and `runtime-status.md` if + wiring, readiness, or known gaps changed. +- **Cross-cutting issue opened/closed** → `backlog.md` with a close condition; + per-task acceptance belongs in the plan card, not here. +- **Contract changed** → schema snippets in `architecture.md`, enum values in + `glossary.md`, and the affected plan cards; then search the codebase for + callers. +- **Invariant changed** → open a task card citing the invariant number; after + landing, sweep for contradictions and file backlog issues for any you cannot + fix in the same change. +- **Term stabilized** → promote `.do-it/CONTEXT.md` → `glossary.md` per the + three-session rule above. + +Keep any single handbook file under ~30 KB (it is read on routine agent work; +context budget is the constraint, not disk). After doc edits, sweep for changed +symbols and readiness labels, e.g. `rg -n "" docs .do-it/handbook`. + ## Output The bootstrap command should produce a short, deterministic report: ``` -[do-it-handbook] writing 12 file(s) to .do-it/handbook/ +[do-it-handbook] writing 7 file(s) to .do-it/handbook/ + .do-it/handbook/README.md + .do-it/handbook/invariants.md + .do-it/handbook/architecture.md @@ -97,11 +129,6 @@ The bootstrap command should produce a short, deterministic report: + .do-it/handbook/glossary.md + .do-it/handbook/backlog.md + .do-it/handbook/runtime-status.md - + .do-it/handbook/maintenance.md - + .do-it/handbook/task-card-template.md - + .do-it/handbook/workflow/agent-workflow.md - + .do-it/handbook/workflow/review-protocol.md - + .do-it/handbook/workflow/subagent-dispatch.md next: fill in invariants.md and glossary.md before running grill on any non-trivial task. ``` @@ -110,7 +137,7 @@ Idempotent re-runs print only the files actually written; an empty list means th ## Common Mistakes -- Treating the bootstrap as a one-time action and never refreshing the templates against do-it upstream. When `do-it` ships a new template (e.g. a new workflow file), the bootstrap should be re-runnable to add it. +- Treating the bootstrap as a one-time action and never refreshing the templates against do-it upstream. When `do-it` ships a new template (e.g. a new truth file), the bootstrap should be re-runnable to add it. - Copying the templates and then immediately auto-filling them from the codebase. The placeholders are intentional — they prompt the human owner to make the call. - Letting `code-map.md` drift. The `code-mapper` agent owns its update; if your project is using do-it without code-mapper running periodically, the handbook copy will rot. - Promoting every term from `.do-it/CONTEXT.md` to `glossary.md` as soon as it appears. The three-session rule exists because most session terms do not survive review. @@ -119,6 +146,5 @@ Idempotent re-runs print only the files actually written; an empty list means th - `do-it-context` — owns active sediment; promotes terms to `glossary.md`. - `do-it-architecture-scan` — reads `architecture.md` and `invariants.md`. -- `do-it-planning` — reads `task-card-template.md` shape. -- `do-it-review-loop` — reads `workflow/review-protocol.md`. -- `do-it-subagent-orchestration` — `workflow/subagent-dispatch.md` is the narrative form of its dispatch contract. +- `do-it-grill` — reads `invariants.md` and `glossary.md` for term anchoring. +- `do-it-planning` / `do-it-review-loop` / `do-it-subagent-orchestration` — own their task-card layout / review protocol / dispatch contract directly; the handbook no longer carries a copy. diff --git a/plugins/do-it/skills/do-it-handbook/templates/README.md b/plugins/do-it/skills/do-it-handbook/templates/README.md index 234fcbd..796dc64 100644 --- a/plugins/do-it/skills/do-it-handbook/templates/README.md +++ b/plugins/do-it/skills/do-it-handbook/templates/README.md @@ -1,7 +1,7 @@ # Project Handbook The handbook is the agent-readable, low-token navigation hub for this -project. It captures the rules, terms, ownership, and review discipline +project. It captures the rules, terms, ownership, and architecture that hold across sessions. Per-task artifacts live elsewhere (`.do-it/grill/`, `.do-it/plans/`, `.do-it/brainstorm/`, `.do-it/CONTEXT.md`). @@ -10,16 +10,12 @@ that hold across sessions. Per-task artifacts live elsewhere - `invariants.md` — rules that always win. - `architecture.md` — stable system shape. -- `workflow/agent-workflow.md` — execution flow for non-trivial work. -- `workflow/review-protocol.md` — review mode and evidence rules. - `code-map.md` — current implementation locations (maintained by the `code-mapper` agent). - `runtime-status.md` — current implementation status and known gaps. - `backlog.md` — cross-cutting unresolved issues with explicit close conditions. - `glossary.md` — long-stable vocabulary. -- `task-card-template.md` — template for non-trivial work briefs. -- `maintenance.md` — when and how to update each handbook file. ## Source-Of-Truth Map @@ -31,15 +27,16 @@ that hold across sessions. Per-task artifacts live elsewhere | Implementation status / wiring gaps | `runtime-status.md` | | Cross-cutting issues | `backlog.md` | | Vocabulary | `glossary.md` | -| Per-task brief template | `task-card-template.md` | -| Execution flow | `workflow/agent-workflow.md` | -| Review discipline | `workflow/review-protocol.md` | -| Subagent dispatch | `workflow/subagent-dispatch.md` | -| Doc maintenance rules | `maintenance.md` | + +Process docs are owned by skills, not this handbook: task-card layout → +`do-it-planning`, review protocol → `do-it-review-loop`, subagent dispatch → +`do-it-subagent-orchestration`, execution pipeline → `do-it-router`. The +handbook update rules live in the `do-it-handbook` SKILL `## Maintenance` +section. ## How To Update -See `maintenance.md` for which file to update when, and which targeted -sweeps to run after edits. Do not let `code-map.md` and -`runtime-status.md` drift from the codebase — they are read every -session and bad data here costs more than missing data. +See the `do-it-handbook` SKILL `## Maintenance` section for which file to +update when, and which targeted sweeps to run after edits. Do not let +`code-map.md` and `runtime-status.md` drift from the codebase — they are read +every session and bad data here costs more than missing data. diff --git a/plugins/do-it/skills/do-it-handbook/templates/code-map.md b/plugins/do-it/skills/do-it-handbook/templates/code-map.md index 13a5ecb..3633562 100644 --- a/plugins/do-it/skills/do-it-handbook/templates/code-map.md +++ b/plugins/do-it/skills/do-it-handbook/templates/code-map.md @@ -43,7 +43,7 @@ sections may be hand-maintained. - Tests: __ — run with ``. - Type definitions: __ — convention ``. - Configuration: __ — __. -- Docs: __ — `maintenance.md` governs updates. +- Docs: __ — the `do-it-handbook` SKILL `## Maintenance` section governs updates. ## Conventions diff --git a/plugins/do-it/skills/do-it-handbook/templates/glossary.md b/plugins/do-it/skills/do-it-handbook/templates/glossary.md index 4786240..6300480 100644 --- a/plugins/do-it/skills/do-it-handbook/templates/glossary.md +++ b/plugins/do-it/skills/do-it-handbook/templates/glossary.md @@ -36,11 +36,10 @@ Avoid: ## Process Vocabulary **Light / Standard / Heavy** — Tier classification used by -`do-it-router` to size the workflow for a task. See -`workflow/agent-workflow.md`. +`do-it-router` to size the workflow for a task. See `do-it-router`. **Blocking / Important / Opportunity** — Severity used in review -findings. See `workflow/review-protocol.md`. +findings. See `do-it-review-loop`. **Grill / Brainstorm** — Convergent (`do-it-grill`) and divergent (`do-it-brainstorm`) reasoning passes that run before planning. diff --git a/plugins/do-it/skills/do-it-handbook/templates/invariants.md b/plugins/do-it/skills/do-it-handbook/templates/invariants.md index 50faf4b..a450e7a 100644 --- a/plugins/do-it/skills/do-it-handbook/templates/invariants.md +++ b/plugins/do-it/skills/do-it-handbook/templates/invariants.md @@ -30,8 +30,8 @@ A change to this file is a project-shape decision, not a routine edit. ## Review -9. A worker `DONE` claim is not an acceptance signal; the review - protocol in `workflow/review-protocol.md` decides acceptance. +9. A worker `DONE` claim is not an acceptance signal; `do-it-review-loop` + decides acceptance. 10. Closeout requires fresh verification evidence on the integrated branch; evidence from an isolated worktree alone is not enough. diff --git a/plugins/do-it/skills/do-it-handbook/templates/maintenance.md b/plugins/do-it/skills/do-it-handbook/templates/maintenance.md deleted file mode 100644 index 216b9b1..0000000 --- a/plugins/do-it/skills/do-it-handbook/templates/maintenance.md +++ /dev/null @@ -1,76 +0,0 @@ -# Documentation Maintenance - -When and how to update each handbook file. - -## Directory Roles - -- `.do-it/handbook/` — maintained handbook (this directory). -- `.do-it/CONTEXT.md` — per-session active sediment; owned by - `do-it-context`. -- `.do-it/grill/.md` — per-task grill log. -- `.do-it/plans/.md` — per-task plan card. -- `.do-it/brainstorm/.md` — per-task multi-persona brainstorm. -- `.do-it/review/.md` — per-task review-loop findings (when - used). -- Project root `README.md`, `CLAUDE.md` (or equivalent) — entry - points; delegate detail to the handbook. - -## Update Rules - -When implementation changes: - -- Update `code-map.md` "Current implementation locations" if files, - packages, routes, repos, migrations, or service ownership changed. - This is normally written by the `code-mapper` agent. -- Update `runtime-status.md` if wiring, readiness, or known gaps - changed. -- Update `backlog.md` only for unresolved cross-cutting issues with a - close condition. Per-task acceptance criteria belong in the task - card. - -When dependencies or readiness gates change: - -- Update `Prerequisite`, `Blocks`, `Depends` in the affected task - cards. -- Update `runtime-status.md` status labels. - -When contracts change: - -- Update schema snippets (architecture or interface docs). -- Update enum values in `glossary.md` if any. -- Update acceptance criteria and test expectations in the affected - task cards. -- Update downstream consumer assumptions and search the codebase for - callers. - -When a term stabilizes: - -- Promote it from `.do-it/CONTEXT.md` to `glossary.md` after the - three-session rule (see `do-it-handbook` SKILL). - -When an invariant changes: - -- Open a task card. Cite the invariant number. -- After landing, sweep the codebase for contradictions. File backlog - issues for any you cannot fix in the same change. - -## Large File Rule - -Do not create new handbook files larger than ~30 KB if they are read -on routine agent work. Split lookup-heavy content into smaller pages. -The agent's context budget is the constraint, not disk. - -## Drift Sweep - -After doc edits, run targeted sweeps for changed symbols, events, -dependencies, and readiness labels. Project-specific examples: - -```bash -rg -n "" docs .do-it/handbook -rg -n "schema-ready|implementation-ready|live-event-ready" \ - docs .do-it/handbook -find .do-it/handbook docs -type f -name '*.md' -size +30k -print -``` - -If a sweep surfaces a contradiction, fix it in the same change or -open a backlog issue with a close condition. diff --git a/plugins/do-it/skills/do-it-handbook/templates/task-card-template.md b/plugins/do-it/skills/do-it-handbook/templates/task-card-template.md deleted file mode 100644 index a1f8c13..0000000 --- a/plugins/do-it/skills/do-it-handbook/templates/task-card-template.md +++ /dev/null @@ -1,130 +0,0 @@ -# Task Card Template - -A lightweight template for non-trivial work that benefits from a -written brief — typically multi-file changes, multi-day efforts, -sub-agent dispatches, or anything that needs review-loop discipline. - -For one-shot fixes, just describe scope in the PR body and skip this. - -## File Layout - -- File path: `.do-it/plans/.md` for in-flight task cards; - graduated cards may move into a project-specific directory once - their wave settles. -- File MUST be UTF-8 without BOM, < 30 KB. Localized fixtures inside - the card are fine. - -## Section Order - -``` -# Implementation Brief: - -> Frontmatter (block-quoted bullet list, fields below) - -## 1. Background & Goal -## 2. Allowed Scope -## 3. Deferred -## 4. Acceptance Criteria -## 5. Verification -## 6. Shared File Hazards & Dependencies -``` - -## Frontmatter Fields - -```markdown -> - **Card ID**: <short kebab-case id> -> - **Source/Background**: <link or one-liner> -> - **Target**: `<destination paths inside the repo>` -> - **Size**: <S | M | L | XL> (S ≤ 5 files, M ≤ 20, L ≤ 100, XL > 100) -> - **Tier**: <Light | Standard | Heavy> (matches do-it-router) -> - **Prerequisite**: <comma-separated card IDs, or `none`> -> - **Blocks**: <comma-separated card IDs, or `none`> -> - **Owner**: <`unassigned` until claimed> -> - **Grill**: <slug from .do-it/grill/, or `none`> -> - **Brainstorm**: <slug from .do-it/brainstorm/, or `none`> -``` - -## §1 Background & Goal - -Two short paragraphs: - -1. **Background**: why this work matters; what subsystem it touches; - what depends on it. -2. **Goal**: a single sentence stating the one outcome this card - delivers. One card = one goal. - -## §2 Allowed Scope - -The exhaustive enumeration of files the card touches. Use -sub-sections per file or per file group. For each file include: - -- **Target**: repo-relative path -- **Change**: brief description of what changes and why - -## §3 Deferred - -Anything intentionally NOT in this card. Each deferral MUST cite a -backlog issue: - -```markdown -- <thing> — deferred to backlog #BL-NNN with close condition - "<one-liner>". -``` - -If nothing is deferred, write `Nothing deferred.` exactly. - -## §4 Acceptance Criteria - -A markdown table. Each row has a stable AC ID (AC1, AC2, ...) and an -Evidence column that names a verifiable artifact. - -```markdown -| AC | Criteria | Evidence | -|---|---|---| -| AC1 | … | … | -| AC2 | TypeScript compiles | `pnpm exec tsc --noEmit` is clean | -| AC3 | Unit tests pass | `pnpm exec vitest run` is green | -``` - -## §5 Verification - -Concrete shell commands a reviewer can run to verify §4. Order them -build → test → lint → integration. - -For Heavy, release/install, multi-agent, or explicit durable-plan work, include -an Evidence Ledger table. Ordinary Light work and one-shot Standard fixes can -skip it. - -```markdown -| Claim ID | Readiness target | Truth plane | Ref/path | Evidence | Result | Date | Owner | Residual risk | -|---|---|---|---|---|---|---|---|---| -| C1 | fixture-ready | source-repo | `src/...` | `npm test` | NOT_VERIFIED | YYYY-MM-DD | parent | command not run yet | -``` - -Allowed `Result` values: `VERIFIED`, `FAILED`, `NOT_VERIFIED`, `BLOCKED`, and -`DEFERRED_BY_USER`. - -Allowed truth planes: `source-repo`, `task-worktree`, `integration-worktree`, -`temp-install`, `live-codex`, `live-claude`, `package-artifact`, -`host-behavior`, and `external-blocked`. - -Old projects do not need historical backfill. Record a `NOT_VERIFIED` baseline -only when old state affects the current task. - -## §6 Shared File Hazards & Dependencies - -A short list of shared files this card writes that may collide with -other cards in the same wave. If none, write `No shared-file -hazards.` exactly. - -Plus a short dependency restatement (mirrors frontmatter): - -```markdown -**Prerequisite**: <card IDs>. -**Blocks**: <card IDs>. -``` - -## Path Style - -All paths are repository-relative -(e.g. `packages/core/src/foo.ts`), never absolute. diff --git a/plugins/do-it/skills/do-it-handbook/templates/workflow/agent-workflow.md b/plugins/do-it/skills/do-it-handbook/templates/workflow/agent-workflow.md deleted file mode 100644 index 53fd09f..0000000 --- a/plugins/do-it/skills/do-it-handbook/templates/workflow/agent-workflow.md +++ /dev/null @@ -1,82 +0,0 @@ -# Agent Workflow - -Execution flow for non-trivial work. Light-tier mechanical edits skip -most of this; Standard and Heavy tiers follow it. - -## Per-Card Pipeline - -1. Read the relevant task card (under `.do-it/plans/`) or PR brief. - If the work area only has a README and no card, read the README - and split a task card or get explicit user scope before - implementing code. -2. Read `invariants.md`. -3. Read the affected handbook pages (`architecture.md`, - `code-map.md`, the relevant glossary entries). -4. Freeze scope from the card's §2-§5. -5. For multi-package or live-path work, map the producer / consumer - path before dispatching a worker. -6. Write or update tests first when practical - (see `do-it-tdd`). -7. Implement the smallest change that satisfies the card. -8. Verify using the card's §5 commands. -9. Run `do-it-review-loop` against the diff before marking - the card done. -10. Run a targeted doc/code consistency sweep for changed contracts. - -## Per-Wave Pipeline - -A "wave" is a set of cards that share a goal and may need to land -together. - -1. Confirm every card has a clear `Prerequisite`, `Blocks`, and - readiness target. -2. Execute independent cards in parallel only when their **write - sets do not overlap**. Cards that touch shared barrel files - (e.g. package index files) MUST serialize through a barrel-update - card. -3. Stop dependent workers when the prerequisite card is still under - review or when shared-contract work is not yet green. -4. Review each card against `invariants.md` and its acceptance - criteria. -5. Re-review every fix loop before merge; worker `DONE` is not an - acceptance signal. -6. Update `runtime-status.md` after each completed card. - -## Phase / Worktree Pipeline - -When the work spans multiple waves or touches risky shared files: - -1. Create an isolated worktree (`do-it-worktree-isolation`). -2. Verify the intended base branch and record its current status. -3. Dispatch card or wave workers from the phase controller only - after the controller freezes scope, dependencies, shared-file - ownership, and merge order. -4. Keep phase work out of the main checkout until build, tests, and - review/fix-loop closure on the phase branch are complete. -5. Merge back to main only after the final reviewer pass reports - zero unresolved Blocking or Important findings on the integrated - branch. -6. After merging, rerun gate verification on `main`. Evidence from - the worktree alone is not enough for closeout. - -## Anti-Tail Discipline - -- **One card, one goal.** If you discover the card needs two goals, - split it before continuing. -- **No silent scope expansion.** A new file outside §2 means open a - backlog issue or update §2 explicitly. -- **No mocking the database in integration tests** unless the card - says so. Mock/prod divergence is a recurring incident class. -- **No commit during a fix loop without re-running review** — partial - fixes ship under the cover of "addressed". - -## Light-Tier Shortcut - -For Light-tier work (mechanical refactors, one-symbol renames, -dependency bumps): - -1. Skip the per-card pipeline; describe scope inline in the PR. -2. Verify with the smallest test command that touches the changed - surface. -3. No handbook updates required unless `code-map.md` would otherwise - become wrong. diff --git a/plugins/do-it/skills/do-it-handbook/templates/workflow/review-protocol.md b/plugins/do-it/skills/do-it-handbook/templates/workflow/review-protocol.md deleted file mode 100644 index ef2c5db..0000000 --- a/plugins/do-it/skills/do-it-handbook/templates/workflow/review-protocol.md +++ /dev/null @@ -1,80 +0,0 @@ -# Review Protocol - -Review mode, severity, and evidence expectations. -`do-it-review-loop` is the agent-side counterpart of this document. - -## Review Modes - -- **Self-review** — the implementer re-reads the diff against the - task card §4 acceptance criteria before requesting review. -- **PR-style review** — `reviewer` agent (or a peer) checks the diff - against acceptance criteria, invariants, and contract surface. -- **Multi-perspective review** — additional read-only review agents - (`architect-reviewer`, `red-team-reviewer`, `domain-language-reviewer`, - etc.) run when their lens is needed. - -The default for a Standard-tier task is self-review. Add PR-style review when -the task has a named non-local risk, an interface/module boundary, or an -explicit review/subagent request. Heavy tier adds multi-perspective review. - -## Severity - -- **Blocking** — must resolve before merge. Correctness, contract, - invariants, or unsafe state. -- **Important** — should resolve now. Avoidable rework, review - failure, unclear ownership, or significant maintenance debt. -- **Opportunity** — useful improvement; not a blocker. - -A finding carries exactly one severity. Re-classifying a Blocking -finding as Important is a discussion, not a unilateral move. - -## Evidence Requirements - -Every finding must cite evidence. Acceptable forms: - -- `path:line` reference. -- A grep / rg snippet showing the contradicted assumption. -- A failing test command and its output. -- A schema or contract diff. - -Unacceptable evidence: - -- "It feels wrong." -- "I think this could be a problem." -- "In my experience, ...". - -If a reviewer cannot cite evidence, the finding is downgraded to a -question for the implementer, not a Blocking item. - -## Fix Loop - -1. Address each Blocking and Important finding atomically. -2. After fixes, **re-run review on the same scope**. Spot-fixes - without a re-review let partial fixes ship. -3. Repeat until Blocking and Important are empty. -4. Opportunity findings may merge with the change or get filed as - backlog issues; do not block on them. - -## Closeout - -A card is done when: - -- All §4 acceptance criteria pass with the §5 verification commands. -- All Blocking and Important review findings are resolved. -- Fresh verification evidence is recorded on the integrated branch - (not just the worktree). -- `runtime-status.md` and `code-map.md` are updated if implementation - shape changed. -- The closeout states which brainstorm, grill, subagent, review, and - verification steps were used or skipped, with the reason when the route made - them relevant. - -## Anti-Patterns - -- "DONE" claims without verification output. `do-it-verification-gate` - catches this; do not weaken the gate. -- Reviewers asking the implementer to fix Blocking findings while - approving the PR. Approval after Blocking findings is a process - failure. -- Reviewers re-litigating architecture invariants in PR comments. - Invariant changes go through a task card, not a review thread. diff --git a/plugins/do-it/skills/do-it-handbook/templates/workflow/subagent-dispatch.md b/plugins/do-it/skills/do-it-handbook/templates/workflow/subagent-dispatch.md deleted file mode 100644 index 7b171b3..0000000 --- a/plugins/do-it/skills/do-it-handbook/templates/workflow/subagent-dispatch.md +++ /dev/null @@ -1,116 +0,0 @@ -# Subagent Dispatch - -Narrative form of the `do-it-subagent-orchestration` contract. Read -this before delegating to a subagent for the first time on a project; -read the contract for the exact required fields. - -## When To Delegate - -Delegate when the parent has bounded the slice well enough that -another agent can do the work in isolation, and the parent's context -budget is better spent on integration and verification than on the -slice itself. - -Do **not** delegate when: - -- the parent has not yet verified enough current truth to bound the - slice; -- the work touches the parent's shared files (final integration, branch - closeout, manifest edits); -- two parallel workers would write the same file or hidden shared - state; -- the parent is uncertain about acceptance criteria. - -A delegated worker is evidence to inspect, not a rubber stamp. - -## Required Prompt Fields - -Every subagent prompt must specify: - -- **tier**: Light, Standard, or explicit Heavy. -- **scope**: exact task and non-goals. -- **write ownership**: allowed directories/files, or `read-only`. -- **forbidden paths**: files, directories, generated outputs, or - user-owned edits to avoid. -- **current truth**: facts the parent verified and the child may rely - on. -- **failure-mode forecast**: expected failure classes the child must - cover or refute. -- **path map**: producer → contract/event/schema → transport/client → - state/query → surface/operator action → verification, or - `not applicable`. -- **readiness target**: the readiness label expected after the slice. -- **truth plane**: `source-repo`, `task-worktree`, `integration-worktree`, - `temp-install`, `live-codex`, `live-claude`, `package-artifact`, - `host-behavior`, or `external-blocked`. -- **lane status**: starts as `assigned`; the parent updates it through - `running`, `done_with_evidence`, `integrated`, or `blocking`. -- **must-verify facts**: facts the child must check itself before - acting or reporting. -- **stop condition**: when to return `NEEDS_CONTEXT`, `BLOCKED`, or - `STILL_OPEN`. -- **integrity stance**: failure is a clue to trace, not to hide; do not - swallow errors, weaken checks, skip tests, or claim unverified work is done. -- **output_budget**: token cap selected from `do-it-subagent-orchestration`. -- **return schema**: the exact shape the parent needs. - -Include this guardrail unless Heavy is explicitly assigned: - -> You are a Standard-tier subagent. Do not expand into parent-level -> Heavy flow, broad planning, branch closeout, manifest/docs edits, or -> unrelated cleanup. - -## Standard Return Schemas - -Implementation/debugging workers return: - -- `status`: `DONE`, `DONE_WITH_CONCERNS`, `NEEDS_CONTEXT`, or - `BLOCKED`; -- lane status recommendation: `done_with_evidence` or `blocking`; -- tier used; -- files changed; -- commands run with results; -- facts verified; -- failure modes covered or still open; -- proof path evidence or why it was not applicable; -- assumptions; -- residual risk; -- requested parent action. - -Review/drill workers return: - -- `status`: `CLEAR`, `FINDINGS`, `STILL_OPEN`, `NEEDS_CONTEXT`, or - `BLOCKED`; -- scope reviewed; -- findings ordered by `Blocking`, `Important`, `Opportunity`; -- evidence per finding; -- cause class when known; -- commands or inspections run; -- facts verified; -- assumptions; -- residual risk; -- `NOT_CHECKED`: explicit scope or checks not performed. - -## Parent Duties - -- Inspect diffs and reports before accepting them. -- Resolve duplicate or conflicting findings. -- Re-run verification on the integrated branch — not the worker's - isolated working copy. -- Ensure subagents did not touch forbidden paths. -- Maintain lane state as `assigned`, `running`, `done_with_evidence`, - `integrated`, or `blocking`. -- Treat worker `DONE` as input to inspect; parent acceptance is `integrated`. -- Close or re-dispatch workers only after the stop condition is - satisfied. - -## Common Mistakes - -- Delegating before scope is bounded; the worker spends its budget - re-discovering the parent's question. -- Parallelizing workers that share a write target; one of them - silently overwrites the other. -- Treating a worker's `DONE` as acceptance. `DONE` is a status, not a - signoff. -- Letting a worker make manifest, docs, or release decisions outside - its slice. diff --git a/plugins/do-it/skills/do-it-planning/SKILL.md b/plugins/do-it/skills/do-it-planning/SKILL.md index eb9b367..7cebf26 100644 --- a/plugins/do-it/skills/do-it-planning/SKILL.md +++ b/plugins/do-it/skills/do-it-planning/SKILL.md @@ -112,9 +112,28 @@ mkdir -p .do-it/runtime && printf '%s' "<slug>" > .do-it/runtime/pointer See `do-it-router` § Task Pointer for the full protocol. Inline plans that never produce a `<slug>.md` file do not need to write the pointer. -## Handbook Alignment +## Task Card Layout -When `.do-it/handbook/` exists, a durable `.do-it/plans/<slug>.md` card follows the section order in `.do-it/handbook/task-card-template.md` — frontmatter, then Background & Goal, Allowed Scope, Deferred, Acceptance Criteria, Verification, Shared File Hazards & Dependencies. The template owns the canonical layout; the lenses and required artifacts in this skill fill those sections. When the handbook is absent and the work spans many files or sessions, suggest `do-it-handbook` to scaffold it rather than inventing a one-off structure. +A durable `.do-it/plans/<slug>.md` card uses this canonical layout; the lenses +and required artifacts in this skill fill the sections. + +Frontmatter (block-quoted bullets): **Card ID**, **Source/Background**, +**Target** (repo-relative paths), **Size** (S ≤ 5 files, M ≤ 20, L ≤ 100, +XL > 100), **Tier** (Light/Standard/Heavy), **Prerequisite**, **Blocks**, +**Owner**, **Grill** (slug or `none`), **Brainstorm** (slug or `none`). + +Sections, in order: + +1. **Background & Goal** — why it matters, plus a one-sentence goal (one card = one goal). +2. **Allowed Scope** — exhaustive list of files the card touches, with the change per file. +3. **Deferred** — anything intentionally out of scope, each citing a backlog issue; write `Nothing deferred.` if none. +4. **Acceptance Criteria** — table of stable AC IDs (AC1, AC2, …) each with a verifiable Evidence column. +5. **Verification** — concrete shell commands ordered build → test → lint → integration; put the Evidence Ledger here for Heavy, release/install, multi-agent, or durable-plan work. +6. **Shared File Hazards & Dependencies** — shared files that may collide with other cards in the wave; write `No shared-file hazards.` if none. + +All paths are repository-relative. When the work spans many files or sessions +and no `.do-it/handbook/` exists yet, suggest `do-it-handbook` to scaffold the +project-truth files rather than inventing a one-off structure. ## Required Planning Artifacts diff --git a/plugins/do-it/skills/do-it-router/SKILL.md b/plugins/do-it/skills/do-it-router/SKILL.md index e803d4b..1a6a7e6 100644 --- a/plugins/do-it/skills/do-it-router/SKILL.md +++ b/plugins/do-it/skills/do-it-router/SKILL.md @@ -189,6 +189,37 @@ Use only in the parent agent unless a subagent is explicitly assigned Heavy. Flow: scope lock -> deep truth scan -> grill/interface/architecture/domain drills as needed -> slice plan -> execution and right-sized review gates -> integrated verification -> closeout. +## Execution Pipeline + +Once the route is set, execute non-trivial work in this order (Light-tier +mechanical edits skip most of it): + +1. Read the task card / inline map, the relevant `invariants.md`, and the + affected existing code before editing. +2. Freeze scope from the card's Allowed Scope; map producer -> consumer for + multi-package or live-path work. +3. Write or update tests first when practical (`do-it-tdd`). +4. Implement the smallest change that satisfies the card, then verify with its + own commands. +5. Run `do-it-review-loop` on the diff before marking done; sweep changed + contracts for doc/code drift. + +For a wave (cards that land together) see `do-it-slicing`: run independent cards +in parallel only when their **write sets do not overlap**; serialize shared +barrel/index files. For phase or risky shared-file work, isolate with +`do-it-worktree-isolation` and merge back only after the integrated branch is +review-clean. + +### Anti-tail discipline + +- **One card, one goal** — if a card grows a second goal, split it. +- **No silent scope expansion** — a file outside Allowed Scope means update the + scope explicitly or open a backlog issue. +- **No commit during a fix loop without re-running review** — partial fixes ship + under the cover of "addressed". +- **No mocking the real collaborator chain** in integration tests unless the + card says so. + ## Route Map - Need a plan or design handoff: `do-it-planning`. diff --git a/plugins/do-it/skills/do-it-visual-planning/SKILL.md b/plugins/do-it/skills/do-it-visual-planning/SKILL.md index d7711f4..70b68f1 100644 --- a/plugins/do-it/skills/do-it-visual-planning/SKILL.md +++ b/plugins/do-it/skills/do-it-visual-planning/SKILL.md @@ -55,7 +55,7 @@ Skip it for text-only decisions, one-line questions, or plans where a table is c `templates/` ships ready-made content fragments for two recurring artifacts: -- `templates/plan-card.html` — a plan / task card (goal, scope, acceptance criteria, verification, risks); section order matches `.do-it/handbook/task-card-template.md` so a visual card and a written card stay consistent. +- `templates/plan-card.html` — a plan / task card (goal, scope, acceptance criteria, verification, risks); section order matches the task-card layout in `do-it-planning` so a visual card and a written card stay consistent. - `templates/review-report.html` — review findings grouped by Blocking / Important / Opportunity with evidence. To use one: copy the fragment into the companion `screen_dir`, fill its `slot:` placeholders, and drop unused sections. The server wraps the fragment in `frame-template.html`, which already carries all CSS — the fragment stays small because only the content varies, and a consistent skeleton means the layout is not re-derived each time. diff --git a/skills/do-it/do-it-handbook/SKILL.md b/skills/do-it/do-it-handbook/SKILL.md index b6970cb..87af4b6 100644 --- a/skills/do-it/do-it-handbook/SKILL.md +++ b/skills/do-it/do-it-handbook/SKILL.md @@ -1,13 +1,13 @@ --- name: do-it-handbook -description: "Use when a project needs a durable `.do-it/handbook/` skeleton for architecture, glossary, code map, backlog, runtime, maintenance, and workflow docs." +description: "Use when a project needs a durable `.do-it/handbook/` skeleton for architecture, invariants, glossary, code map, backlog, and runtime status." --- # Do-It Handbook ## Purpose -Use this to scaffold a long-lived handbook for a project that uses `do-it`. The handbook is the agent-readable source of truth for terms, invariants, ownership, and review discipline that does not change every turn. It complements the per-task artifacts (`.do-it/grill/`, `.do-it/plans/`, `.do-it/brainstorm/`) and the always-active sediment (`.do-it/CONTEXT.md`). +Use this to scaffold a long-lived handbook for a project that uses `do-it`. The handbook is the agent-readable source of truth for terms, invariants, ownership, and architecture that does not change every turn. It complements the per-task artifacts (`.do-it/grill/`, `.do-it/plans/`, `.do-it/brainstorm/`) and the always-active sediment (`.do-it/CONTEXT.md`). The shape is borrowed from a project that has shipped against it for a year (Do-SOUL Alaya). Files are intentionally small (< 30 KB each) so the agent can read whatever it needs without bloating context. @@ -33,14 +33,16 @@ Skip when: glossary.md # vocabulary (long-stable terms) backlog.md # cross-cutting unresolved issues with close conditions runtime-status.md # implementation status and known wiring gaps - maintenance.md # documentation update rules - task-card-template.md # template for non-trivial work briefs - workflow/ - agent-workflow.md # per-card / per-wave / phase pipelines - review-protocol.md # review mode, severity, evidence expectations - subagent-dispatch.md # how delegated workers are constrained ``` +The handbook holds only **project-specific truth** — the facts a generic skill +cannot carry. Process docs (task-card layout, review protocol, subagent +dispatch, execution pipeline, maintenance rules) are NOT scaffolded here: the +owning skills are their single source of truth (`do-it-planning`, +`do-it-review-loop`, `do-it-subagent-orchestration`, `do-it-router`, and the +`## Maintenance` section below). This keeps the handbook small and removes the +duplicate-doc drift that comes from copying skill prose into every project. + ## Bootstrap Behavior When invoked: @@ -50,7 +52,7 @@ When invoked: - If it does **and** some files are missing, copy only the missing files (additive, never overwrite). - If it does not exist, create the full tree. 2. Templates are copied verbatim from `templates/` under this skill. Each template is a skeleton with placeholder text the project owner replaces; do not hand-edit the project's handbook from inside the bootstrap step. -3. Add a `.gitkeep` to `.do-it/brainstorm/`, `.do-it/grill/`, `.do-it/plans/`, and `.do-it/handbook/workflow/` if any of those directories are missing, so the project tracks them in version control. +3. Add a `.gitkeep` to `.do-it/brainstorm/`, `.do-it/grill/`, and `.do-it/plans/` if any of those directories are missing, so the project tracks them in version control. 4. Print one line per file written, then a one-paragraph "next steps" pointer telling the user to start by filling in `invariants.md` and `glossary.md`. Do **not**: @@ -66,11 +68,14 @@ Do **not**: | `do-it-context` | `.do-it/CONTEXT.md` (active sediment) | `glossary.md` (long-stable terms) | | `do-it-architecture-scan` | inline review output | `architecture.md`, `invariants.md` | | `do-it-grill` | `.do-it/grill/<task>.md` | `invariants.md`, `glossary.md` | -| `do-it-planning` | `.do-it/plans/<task>.md` | `task-card-template.md` | -| `do-it-review-loop` | `.do-it/review/<task>.md` | `workflow/review-protocol.md`, `invariants.md` | -| `do-it-subagent-orchestration` | the dispatch contract | `workflow/subagent-dispatch.md` | +| `do-it-review-loop` | `.do-it/review/<task>.md` | `invariants.md` | | code-mapper agent | summary returned to parent | writes `code-map.md` "Current implementation locations" section | +`do-it-planning` owns the task-card layout itself, `do-it-review-loop` owns the +review protocol, and `do-it-subagent-orchestration` owns the dispatch contract — +none of them read a handbook copy. The handbook only feeds them project-specific +truth (`invariants.md`, `glossary.md`, `architecture.md`). + The handbook is read-mostly. The only file that gets written by an agent on a regular basis is `code-map.md`, and only by `code-mapper` per the contract in its agent definition. ## Term Promotion Rule (`.do-it/CONTEXT.md` ↔ `glossary.md`) @@ -84,12 +89,39 @@ To prevent drift between the active sediment and the stable glossary: This rule is enforced by the agent during `do-it-context` writes, not by tooling. Stating it once here keeps both files honest. +## Maintenance + +When and how to update each handbook file. The per-session sediment +(`.do-it/CONTEXT.md`) and per-task artifacts (`.do-it/grill/`, `.do-it/plans/`, +`.do-it/review/`) live outside the handbook; the project root `README.md` / +`CLAUDE.md` are entry points that delegate detail here. + +Update triggers: + +- **Implementation moved** → update `code-map.md` "Current implementation + locations" (normally the `code-mapper` agent) and `runtime-status.md` if + wiring, readiness, or known gaps changed. +- **Cross-cutting issue opened/closed** → `backlog.md` with a close condition; + per-task acceptance belongs in the plan card, not here. +- **Contract changed** → schema snippets in `architecture.md`, enum values in + `glossary.md`, and the affected plan cards; then search the codebase for + callers. +- **Invariant changed** → open a task card citing the invariant number; after + landing, sweep for contradictions and file backlog issues for any you cannot + fix in the same change. +- **Term stabilized** → promote `.do-it/CONTEXT.md` → `glossary.md` per the + three-session rule above. + +Keep any single handbook file under ~30 KB (it is read on routine agent work; +context budget is the constraint, not disk). After doc edits, sweep for changed +symbols and readiness labels, e.g. `rg -n "<changed symbol>" docs .do-it/handbook`. + ## Output The bootstrap command should produce a short, deterministic report: ``` -[do-it-handbook] writing 12 file(s) to .do-it/handbook/ +[do-it-handbook] writing 7 file(s) to .do-it/handbook/ + .do-it/handbook/README.md + .do-it/handbook/invariants.md + .do-it/handbook/architecture.md @@ -97,11 +129,6 @@ The bootstrap command should produce a short, deterministic report: + .do-it/handbook/glossary.md + .do-it/handbook/backlog.md + .do-it/handbook/runtime-status.md - + .do-it/handbook/maintenance.md - + .do-it/handbook/task-card-template.md - + .do-it/handbook/workflow/agent-workflow.md - + .do-it/handbook/workflow/review-protocol.md - + .do-it/handbook/workflow/subagent-dispatch.md next: fill in invariants.md and glossary.md before running grill on any non-trivial task. ``` @@ -110,7 +137,7 @@ Idempotent re-runs print only the files actually written; an empty list means th ## Common Mistakes -- Treating the bootstrap as a one-time action and never refreshing the templates against do-it upstream. When `do-it` ships a new template (e.g. a new workflow file), the bootstrap should be re-runnable to add it. +- Treating the bootstrap as a one-time action and never refreshing the templates against do-it upstream. When `do-it` ships a new template (e.g. a new truth file), the bootstrap should be re-runnable to add it. - Copying the templates and then immediately auto-filling them from the codebase. The placeholders are intentional — they prompt the human owner to make the call. - Letting `code-map.md` drift. The `code-mapper` agent owns its update; if your project is using do-it without code-mapper running periodically, the handbook copy will rot. - Promoting every term from `.do-it/CONTEXT.md` to `glossary.md` as soon as it appears. The three-session rule exists because most session terms do not survive review. @@ -119,6 +146,5 @@ Idempotent re-runs print only the files actually written; an empty list means th - `do-it-context` — owns active sediment; promotes terms to `glossary.md`. - `do-it-architecture-scan` — reads `architecture.md` and `invariants.md`. -- `do-it-planning` — reads `task-card-template.md` shape. -- `do-it-review-loop` — reads `workflow/review-protocol.md`. -- `do-it-subagent-orchestration` — `workflow/subagent-dispatch.md` is the narrative form of its dispatch contract. +- `do-it-grill` — reads `invariants.md` and `glossary.md` for term anchoring. +- `do-it-planning` / `do-it-review-loop` / `do-it-subagent-orchestration` — own their task-card layout / review protocol / dispatch contract directly; the handbook no longer carries a copy. diff --git a/skills/do-it/do-it-handbook/templates/README.md b/skills/do-it/do-it-handbook/templates/README.md index 234fcbd..796dc64 100644 --- a/skills/do-it/do-it-handbook/templates/README.md +++ b/skills/do-it/do-it-handbook/templates/README.md @@ -1,7 +1,7 @@ # Project Handbook The handbook is the agent-readable, low-token navigation hub for this -project. It captures the rules, terms, ownership, and review discipline +project. It captures the rules, terms, ownership, and architecture that hold across sessions. Per-task artifacts live elsewhere (`.do-it/grill/`, `.do-it/plans/`, `.do-it/brainstorm/`, `.do-it/CONTEXT.md`). @@ -10,16 +10,12 @@ that hold across sessions. Per-task artifacts live elsewhere - `invariants.md` — rules that always win. - `architecture.md` — stable system shape. -- `workflow/agent-workflow.md` — execution flow for non-trivial work. -- `workflow/review-protocol.md` — review mode and evidence rules. - `code-map.md` — current implementation locations (maintained by the `code-mapper` agent). - `runtime-status.md` — current implementation status and known gaps. - `backlog.md` — cross-cutting unresolved issues with explicit close conditions. - `glossary.md` — long-stable vocabulary. -- `task-card-template.md` — template for non-trivial work briefs. -- `maintenance.md` — when and how to update each handbook file. ## Source-Of-Truth Map @@ -31,15 +27,16 @@ that hold across sessions. Per-task artifacts live elsewhere | Implementation status / wiring gaps | `runtime-status.md` | | Cross-cutting issues | `backlog.md` | | Vocabulary | `glossary.md` | -| Per-task brief template | `task-card-template.md` | -| Execution flow | `workflow/agent-workflow.md` | -| Review discipline | `workflow/review-protocol.md` | -| Subagent dispatch | `workflow/subagent-dispatch.md` | -| Doc maintenance rules | `maintenance.md` | + +Process docs are owned by skills, not this handbook: task-card layout → +`do-it-planning`, review protocol → `do-it-review-loop`, subagent dispatch → +`do-it-subagent-orchestration`, execution pipeline → `do-it-router`. The +handbook update rules live in the `do-it-handbook` SKILL `## Maintenance` +section. ## How To Update -See `maintenance.md` for which file to update when, and which targeted -sweeps to run after edits. Do not let `code-map.md` and -`runtime-status.md` drift from the codebase — they are read every -session and bad data here costs more than missing data. +See the `do-it-handbook` SKILL `## Maintenance` section for which file to +update when, and which targeted sweeps to run after edits. Do not let +`code-map.md` and `runtime-status.md` drift from the codebase — they are read +every session and bad data here costs more than missing data. diff --git a/skills/do-it/do-it-handbook/templates/code-map.md b/skills/do-it/do-it-handbook/templates/code-map.md index 13a5ecb..3633562 100644 --- a/skills/do-it/do-it-handbook/templates/code-map.md +++ b/skills/do-it/do-it-handbook/templates/code-map.md @@ -43,7 +43,7 @@ sections may be hand-maintained. - Tests: _<directory>_ — run with `<command>`. - Type definitions: _<directory>_ — convention `<one-liner>`. - Configuration: _<file>_ — _<env var or file format>_. -- Docs: _<directory>_ — `maintenance.md` governs updates. +- Docs: _<directory>_ — the `do-it-handbook` SKILL `## Maintenance` section governs updates. ## Conventions diff --git a/skills/do-it/do-it-handbook/templates/glossary.md b/skills/do-it/do-it-handbook/templates/glossary.md index 4786240..6300480 100644 --- a/skills/do-it/do-it-handbook/templates/glossary.md +++ b/skills/do-it/do-it-handbook/templates/glossary.md @@ -36,11 +36,10 @@ Avoid: ## Process Vocabulary **Light / Standard / Heavy** — Tier classification used by -`do-it-router` to size the workflow for a task. See -`workflow/agent-workflow.md`. +`do-it-router` to size the workflow for a task. See `do-it-router`. **Blocking / Important / Opportunity** — Severity used in review -findings. See `workflow/review-protocol.md`. +findings. See `do-it-review-loop`. **Grill / Brainstorm** — Convergent (`do-it-grill`) and divergent (`do-it-brainstorm`) reasoning passes that run before planning. diff --git a/skills/do-it/do-it-handbook/templates/invariants.md b/skills/do-it/do-it-handbook/templates/invariants.md index 50faf4b..a450e7a 100644 --- a/skills/do-it/do-it-handbook/templates/invariants.md +++ b/skills/do-it/do-it-handbook/templates/invariants.md @@ -30,8 +30,8 @@ A change to this file is a project-shape decision, not a routine edit. ## Review -9. A worker `DONE` claim is not an acceptance signal; the review - protocol in `workflow/review-protocol.md` decides acceptance. +9. A worker `DONE` claim is not an acceptance signal; `do-it-review-loop` + decides acceptance. 10. Closeout requires fresh verification evidence on the integrated branch; evidence from an isolated worktree alone is not enough. diff --git a/skills/do-it/do-it-handbook/templates/maintenance.md b/skills/do-it/do-it-handbook/templates/maintenance.md deleted file mode 100644 index 216b9b1..0000000 --- a/skills/do-it/do-it-handbook/templates/maintenance.md +++ /dev/null @@ -1,76 +0,0 @@ -# Documentation Maintenance - -When and how to update each handbook file. - -## Directory Roles - -- `.do-it/handbook/` — maintained handbook (this directory). -- `.do-it/CONTEXT.md` — per-session active sediment; owned by - `do-it-context`. -- `.do-it/grill/<task>.md` — per-task grill log. -- `.do-it/plans/<task>.md` — per-task plan card. -- `.do-it/brainstorm/<task>.md` — per-task multi-persona brainstorm. -- `.do-it/review/<task>.md` — per-task review-loop findings (when - used). -- Project root `README.md`, `CLAUDE.md` (or equivalent) — entry - points; delegate detail to the handbook. - -## Update Rules - -When implementation changes: - -- Update `code-map.md` "Current implementation locations" if files, - packages, routes, repos, migrations, or service ownership changed. - This is normally written by the `code-mapper` agent. -- Update `runtime-status.md` if wiring, readiness, or known gaps - changed. -- Update `backlog.md` only for unresolved cross-cutting issues with a - close condition. Per-task acceptance criteria belong in the task - card. - -When dependencies or readiness gates change: - -- Update `Prerequisite`, `Blocks`, `Depends` in the affected task - cards. -- Update `runtime-status.md` status labels. - -When contracts change: - -- Update schema snippets (architecture or interface docs). -- Update enum values in `glossary.md` if any. -- Update acceptance criteria and test expectations in the affected - task cards. -- Update downstream consumer assumptions and search the codebase for - callers. - -When a term stabilizes: - -- Promote it from `.do-it/CONTEXT.md` to `glossary.md` after the - three-session rule (see `do-it-handbook` SKILL). - -When an invariant changes: - -- Open a task card. Cite the invariant number. -- After landing, sweep the codebase for contradictions. File backlog - issues for any you cannot fix in the same change. - -## Large File Rule - -Do not create new handbook files larger than ~30 KB if they are read -on routine agent work. Split lookup-heavy content into smaller pages. -The agent's context budget is the constraint, not disk. - -## Drift Sweep - -After doc edits, run targeted sweeps for changed symbols, events, -dependencies, and readiness labels. Project-specific examples: - -```bash -rg -n "<changed symbol>" docs .do-it/handbook -rg -n "schema-ready|implementation-ready|live-event-ready" \ - docs .do-it/handbook -find .do-it/handbook docs -type f -name '*.md' -size +30k -print -``` - -If a sweep surfaces a contradiction, fix it in the same change or -open a backlog issue with a close condition. diff --git a/skills/do-it/do-it-handbook/templates/task-card-template.md b/skills/do-it/do-it-handbook/templates/task-card-template.md deleted file mode 100644 index a1f8c13..0000000 --- a/skills/do-it/do-it-handbook/templates/task-card-template.md +++ /dev/null @@ -1,130 +0,0 @@ -# Task Card Template - -A lightweight template for non-trivial work that benefits from a -written brief — typically multi-file changes, multi-day efforts, -sub-agent dispatches, or anything that needs review-loop discipline. - -For one-shot fixes, just describe scope in the PR body and skip this. - -## File Layout - -- File path: `.do-it/plans/<task-slug>.md` for in-flight task cards; - graduated cards may move into a project-specific directory once - their wave settles. -- File MUST be UTF-8 without BOM, < 30 KB. Localized fixtures inside - the card are fine. - -## Section Order - -``` -# Implementation Brief: <CARD-ID> — <Title> - -> Frontmatter (block-quoted bullet list, fields below) - -## 1. Background & Goal -## 2. Allowed Scope -## 3. Deferred -## 4. Acceptance Criteria -## 5. Verification -## 6. Shared File Hazards & Dependencies -``` - -## Frontmatter Fields - -```markdown -> - **Card ID**: <short kebab-case id> -> - **Source/Background**: <link or one-liner> -> - **Target**: `<destination paths inside the repo>` -> - **Size**: <S | M | L | XL> (S ≤ 5 files, M ≤ 20, L ≤ 100, XL > 100) -> - **Tier**: <Light | Standard | Heavy> (matches do-it-router) -> - **Prerequisite**: <comma-separated card IDs, or `none`> -> - **Blocks**: <comma-separated card IDs, or `none`> -> - **Owner**: <`unassigned` until claimed> -> - **Grill**: <slug from .do-it/grill/, or `none`> -> - **Brainstorm**: <slug from .do-it/brainstorm/, or `none`> -``` - -## §1 Background & Goal - -Two short paragraphs: - -1. **Background**: why this work matters; what subsystem it touches; - what depends on it. -2. **Goal**: a single sentence stating the one outcome this card - delivers. One card = one goal. - -## §2 Allowed Scope - -The exhaustive enumeration of files the card touches. Use -sub-sections per file or per file group. For each file include: - -- **Target**: repo-relative path -- **Change**: brief description of what changes and why - -## §3 Deferred - -Anything intentionally NOT in this card. Each deferral MUST cite a -backlog issue: - -```markdown -- <thing> — deferred to backlog #BL-NNN with close condition - "<one-liner>". -``` - -If nothing is deferred, write `Nothing deferred.` exactly. - -## §4 Acceptance Criteria - -A markdown table. Each row has a stable AC ID (AC1, AC2, ...) and an -Evidence column that names a verifiable artifact. - -```markdown -| AC | Criteria | Evidence | -|---|---|---| -| AC1 | … | … | -| AC2 | TypeScript compiles | `pnpm exec tsc --noEmit` is clean | -| AC3 | Unit tests pass | `pnpm exec vitest run` is green | -``` - -## §5 Verification - -Concrete shell commands a reviewer can run to verify §4. Order them -build → test → lint → integration. - -For Heavy, release/install, multi-agent, or explicit durable-plan work, include -an Evidence Ledger table. Ordinary Light work and one-shot Standard fixes can -skip it. - -```markdown -| Claim ID | Readiness target | Truth plane | Ref/path | Evidence | Result | Date | Owner | Residual risk | -|---|---|---|---|---|---|---|---|---| -| C1 | fixture-ready | source-repo | `src/...` | `npm test` | NOT_VERIFIED | YYYY-MM-DD | parent | command not run yet | -``` - -Allowed `Result` values: `VERIFIED`, `FAILED`, `NOT_VERIFIED`, `BLOCKED`, and -`DEFERRED_BY_USER`. - -Allowed truth planes: `source-repo`, `task-worktree`, `integration-worktree`, -`temp-install`, `live-codex`, `live-claude`, `package-artifact`, -`host-behavior`, and `external-blocked`. - -Old projects do not need historical backfill. Record a `NOT_VERIFIED` baseline -only when old state affects the current task. - -## §6 Shared File Hazards & Dependencies - -A short list of shared files this card writes that may collide with -other cards in the same wave. If none, write `No shared-file -hazards.` exactly. - -Plus a short dependency restatement (mirrors frontmatter): - -```markdown -**Prerequisite**: <card IDs>. -**Blocks**: <card IDs>. -``` - -## Path Style - -All paths are repository-relative -(e.g. `packages/core/src/foo.ts`), never absolute. diff --git a/skills/do-it/do-it-handbook/templates/workflow/agent-workflow.md b/skills/do-it/do-it-handbook/templates/workflow/agent-workflow.md deleted file mode 100644 index 53fd09f..0000000 --- a/skills/do-it/do-it-handbook/templates/workflow/agent-workflow.md +++ /dev/null @@ -1,82 +0,0 @@ -# Agent Workflow - -Execution flow for non-trivial work. Light-tier mechanical edits skip -most of this; Standard and Heavy tiers follow it. - -## Per-Card Pipeline - -1. Read the relevant task card (under `.do-it/plans/`) or PR brief. - If the work area only has a README and no card, read the README - and split a task card or get explicit user scope before - implementing code. -2. Read `invariants.md`. -3. Read the affected handbook pages (`architecture.md`, - `code-map.md`, the relevant glossary entries). -4. Freeze scope from the card's §2-§5. -5. For multi-package or live-path work, map the producer / consumer - path before dispatching a worker. -6. Write or update tests first when practical - (see `do-it-tdd`). -7. Implement the smallest change that satisfies the card. -8. Verify using the card's §5 commands. -9. Run `do-it-review-loop` against the diff before marking - the card done. -10. Run a targeted doc/code consistency sweep for changed contracts. - -## Per-Wave Pipeline - -A "wave" is a set of cards that share a goal and may need to land -together. - -1. Confirm every card has a clear `Prerequisite`, `Blocks`, and - readiness target. -2. Execute independent cards in parallel only when their **write - sets do not overlap**. Cards that touch shared barrel files - (e.g. package index files) MUST serialize through a barrel-update - card. -3. Stop dependent workers when the prerequisite card is still under - review or when shared-contract work is not yet green. -4. Review each card against `invariants.md` and its acceptance - criteria. -5. Re-review every fix loop before merge; worker `DONE` is not an - acceptance signal. -6. Update `runtime-status.md` after each completed card. - -## Phase / Worktree Pipeline - -When the work spans multiple waves or touches risky shared files: - -1. Create an isolated worktree (`do-it-worktree-isolation`). -2. Verify the intended base branch and record its current status. -3. Dispatch card or wave workers from the phase controller only - after the controller freezes scope, dependencies, shared-file - ownership, and merge order. -4. Keep phase work out of the main checkout until build, tests, and - review/fix-loop closure on the phase branch are complete. -5. Merge back to main only after the final reviewer pass reports - zero unresolved Blocking or Important findings on the integrated - branch. -6. After merging, rerun gate verification on `main`. Evidence from - the worktree alone is not enough for closeout. - -## Anti-Tail Discipline - -- **One card, one goal.** If you discover the card needs two goals, - split it before continuing. -- **No silent scope expansion.** A new file outside §2 means open a - backlog issue or update §2 explicitly. -- **No mocking the database in integration tests** unless the card - says so. Mock/prod divergence is a recurring incident class. -- **No commit during a fix loop without re-running review** — partial - fixes ship under the cover of "addressed". - -## Light-Tier Shortcut - -For Light-tier work (mechanical refactors, one-symbol renames, -dependency bumps): - -1. Skip the per-card pipeline; describe scope inline in the PR. -2. Verify with the smallest test command that touches the changed - surface. -3. No handbook updates required unless `code-map.md` would otherwise - become wrong. diff --git a/skills/do-it/do-it-handbook/templates/workflow/review-protocol.md b/skills/do-it/do-it-handbook/templates/workflow/review-protocol.md deleted file mode 100644 index ef2c5db..0000000 --- a/skills/do-it/do-it-handbook/templates/workflow/review-protocol.md +++ /dev/null @@ -1,80 +0,0 @@ -# Review Protocol - -Review mode, severity, and evidence expectations. -`do-it-review-loop` is the agent-side counterpart of this document. - -## Review Modes - -- **Self-review** — the implementer re-reads the diff against the - task card §4 acceptance criteria before requesting review. -- **PR-style review** — `reviewer` agent (or a peer) checks the diff - against acceptance criteria, invariants, and contract surface. -- **Multi-perspective review** — additional read-only review agents - (`architect-reviewer`, `red-team-reviewer`, `domain-language-reviewer`, - etc.) run when their lens is needed. - -The default for a Standard-tier task is self-review. Add PR-style review when -the task has a named non-local risk, an interface/module boundary, or an -explicit review/subagent request. Heavy tier adds multi-perspective review. - -## Severity - -- **Blocking** — must resolve before merge. Correctness, contract, - invariants, or unsafe state. -- **Important** — should resolve now. Avoidable rework, review - failure, unclear ownership, or significant maintenance debt. -- **Opportunity** — useful improvement; not a blocker. - -A finding carries exactly one severity. Re-classifying a Blocking -finding as Important is a discussion, not a unilateral move. - -## Evidence Requirements - -Every finding must cite evidence. Acceptable forms: - -- `path:line` reference. -- A grep / rg snippet showing the contradicted assumption. -- A failing test command and its output. -- A schema or contract diff. - -Unacceptable evidence: - -- "It feels wrong." -- "I think this could be a problem." -- "In my experience, ...". - -If a reviewer cannot cite evidence, the finding is downgraded to a -question for the implementer, not a Blocking item. - -## Fix Loop - -1. Address each Blocking and Important finding atomically. -2. After fixes, **re-run review on the same scope**. Spot-fixes - without a re-review let partial fixes ship. -3. Repeat until Blocking and Important are empty. -4. Opportunity findings may merge with the change or get filed as - backlog issues; do not block on them. - -## Closeout - -A card is done when: - -- All §4 acceptance criteria pass with the §5 verification commands. -- All Blocking and Important review findings are resolved. -- Fresh verification evidence is recorded on the integrated branch - (not just the worktree). -- `runtime-status.md` and `code-map.md` are updated if implementation - shape changed. -- The closeout states which brainstorm, grill, subagent, review, and - verification steps were used or skipped, with the reason when the route made - them relevant. - -## Anti-Patterns - -- "DONE" claims without verification output. `do-it-verification-gate` - catches this; do not weaken the gate. -- Reviewers asking the implementer to fix Blocking findings while - approving the PR. Approval after Blocking findings is a process - failure. -- Reviewers re-litigating architecture invariants in PR comments. - Invariant changes go through a task card, not a review thread. diff --git a/skills/do-it/do-it-handbook/templates/workflow/subagent-dispatch.md b/skills/do-it/do-it-handbook/templates/workflow/subagent-dispatch.md deleted file mode 100644 index 7b171b3..0000000 --- a/skills/do-it/do-it-handbook/templates/workflow/subagent-dispatch.md +++ /dev/null @@ -1,116 +0,0 @@ -# Subagent Dispatch - -Narrative form of the `do-it-subagent-orchestration` contract. Read -this before delegating to a subagent for the first time on a project; -read the contract for the exact required fields. - -## When To Delegate - -Delegate when the parent has bounded the slice well enough that -another agent can do the work in isolation, and the parent's context -budget is better spent on integration and verification than on the -slice itself. - -Do **not** delegate when: - -- the parent has not yet verified enough current truth to bound the - slice; -- the work touches the parent's shared files (final integration, branch - closeout, manifest edits); -- two parallel workers would write the same file or hidden shared - state; -- the parent is uncertain about acceptance criteria. - -A delegated worker is evidence to inspect, not a rubber stamp. - -## Required Prompt Fields - -Every subagent prompt must specify: - -- **tier**: Light, Standard, or explicit Heavy. -- **scope**: exact task and non-goals. -- **write ownership**: allowed directories/files, or `read-only`. -- **forbidden paths**: files, directories, generated outputs, or - user-owned edits to avoid. -- **current truth**: facts the parent verified and the child may rely - on. -- **failure-mode forecast**: expected failure classes the child must - cover or refute. -- **path map**: producer → contract/event/schema → transport/client → - state/query → surface/operator action → verification, or - `not applicable`. -- **readiness target**: the readiness label expected after the slice. -- **truth plane**: `source-repo`, `task-worktree`, `integration-worktree`, - `temp-install`, `live-codex`, `live-claude`, `package-artifact`, - `host-behavior`, or `external-blocked`. -- **lane status**: starts as `assigned`; the parent updates it through - `running`, `done_with_evidence`, `integrated`, or `blocking`. -- **must-verify facts**: facts the child must check itself before - acting or reporting. -- **stop condition**: when to return `NEEDS_CONTEXT`, `BLOCKED`, or - `STILL_OPEN`. -- **integrity stance**: failure is a clue to trace, not to hide; do not - swallow errors, weaken checks, skip tests, or claim unverified work is done. -- **output_budget**: token cap selected from `do-it-subagent-orchestration`. -- **return schema**: the exact shape the parent needs. - -Include this guardrail unless Heavy is explicitly assigned: - -> You are a Standard-tier subagent. Do not expand into parent-level -> Heavy flow, broad planning, branch closeout, manifest/docs edits, or -> unrelated cleanup. - -## Standard Return Schemas - -Implementation/debugging workers return: - -- `status`: `DONE`, `DONE_WITH_CONCERNS`, `NEEDS_CONTEXT`, or - `BLOCKED`; -- lane status recommendation: `done_with_evidence` or `blocking`; -- tier used; -- files changed; -- commands run with results; -- facts verified; -- failure modes covered or still open; -- proof path evidence or why it was not applicable; -- assumptions; -- residual risk; -- requested parent action. - -Review/drill workers return: - -- `status`: `CLEAR`, `FINDINGS`, `STILL_OPEN`, `NEEDS_CONTEXT`, or - `BLOCKED`; -- scope reviewed; -- findings ordered by `Blocking`, `Important`, `Opportunity`; -- evidence per finding; -- cause class when known; -- commands or inspections run; -- facts verified; -- assumptions; -- residual risk; -- `NOT_CHECKED`: explicit scope or checks not performed. - -## Parent Duties - -- Inspect diffs and reports before accepting them. -- Resolve duplicate or conflicting findings. -- Re-run verification on the integrated branch — not the worker's - isolated working copy. -- Ensure subagents did not touch forbidden paths. -- Maintain lane state as `assigned`, `running`, `done_with_evidence`, - `integrated`, or `blocking`. -- Treat worker `DONE` as input to inspect; parent acceptance is `integrated`. -- Close or re-dispatch workers only after the stop condition is - satisfied. - -## Common Mistakes - -- Delegating before scope is bounded; the worker spends its budget - re-discovering the parent's question. -- Parallelizing workers that share a write target; one of them - silently overwrites the other. -- Treating a worker's `DONE` as acceptance. `DONE` is a status, not a - signoff. -- Letting a worker make manifest, docs, or release decisions outside - its slice. diff --git a/skills/do-it/do-it-planning/SKILL.md b/skills/do-it/do-it-planning/SKILL.md index eb9b367..7cebf26 100644 --- a/skills/do-it/do-it-planning/SKILL.md +++ b/skills/do-it/do-it-planning/SKILL.md @@ -112,9 +112,28 @@ mkdir -p .do-it/runtime && printf '%s' "<slug>" > .do-it/runtime/pointer See `do-it-router` § Task Pointer for the full protocol. Inline plans that never produce a `<slug>.md` file do not need to write the pointer. -## Handbook Alignment +## Task Card Layout -When `.do-it/handbook/` exists, a durable `.do-it/plans/<slug>.md` card follows the section order in `.do-it/handbook/task-card-template.md` — frontmatter, then Background & Goal, Allowed Scope, Deferred, Acceptance Criteria, Verification, Shared File Hazards & Dependencies. The template owns the canonical layout; the lenses and required artifacts in this skill fill those sections. When the handbook is absent and the work spans many files or sessions, suggest `do-it-handbook` to scaffold it rather than inventing a one-off structure. +A durable `.do-it/plans/<slug>.md` card uses this canonical layout; the lenses +and required artifacts in this skill fill the sections. + +Frontmatter (block-quoted bullets): **Card ID**, **Source/Background**, +**Target** (repo-relative paths), **Size** (S ≤ 5 files, M ≤ 20, L ≤ 100, +XL > 100), **Tier** (Light/Standard/Heavy), **Prerequisite**, **Blocks**, +**Owner**, **Grill** (slug or `none`), **Brainstorm** (slug or `none`). + +Sections, in order: + +1. **Background & Goal** — why it matters, plus a one-sentence goal (one card = one goal). +2. **Allowed Scope** — exhaustive list of files the card touches, with the change per file. +3. **Deferred** — anything intentionally out of scope, each citing a backlog issue; write `Nothing deferred.` if none. +4. **Acceptance Criteria** — table of stable AC IDs (AC1, AC2, …) each with a verifiable Evidence column. +5. **Verification** — concrete shell commands ordered build → test → lint → integration; put the Evidence Ledger here for Heavy, release/install, multi-agent, or durable-plan work. +6. **Shared File Hazards & Dependencies** — shared files that may collide with other cards in the wave; write `No shared-file hazards.` if none. + +All paths are repository-relative. When the work spans many files or sessions +and no `.do-it/handbook/` exists yet, suggest `do-it-handbook` to scaffold the +project-truth files rather than inventing a one-off structure. ## Required Planning Artifacts diff --git a/skills/do-it/do-it-router/SKILL.md b/skills/do-it/do-it-router/SKILL.md index e803d4b..1a6a7e6 100644 --- a/skills/do-it/do-it-router/SKILL.md +++ b/skills/do-it/do-it-router/SKILL.md @@ -189,6 +189,37 @@ Use only in the parent agent unless a subagent is explicitly assigned Heavy. Flow: scope lock -> deep truth scan -> grill/interface/architecture/domain drills as needed -> slice plan -> execution and right-sized review gates -> integrated verification -> closeout. +## Execution Pipeline + +Once the route is set, execute non-trivial work in this order (Light-tier +mechanical edits skip most of it): + +1. Read the task card / inline map, the relevant `invariants.md`, and the + affected existing code before editing. +2. Freeze scope from the card's Allowed Scope; map producer -> consumer for + multi-package or live-path work. +3. Write or update tests first when practical (`do-it-tdd`). +4. Implement the smallest change that satisfies the card, then verify with its + own commands. +5. Run `do-it-review-loop` on the diff before marking done; sweep changed + contracts for doc/code drift. + +For a wave (cards that land together) see `do-it-slicing`: run independent cards +in parallel only when their **write sets do not overlap**; serialize shared +barrel/index files. For phase or risky shared-file work, isolate with +`do-it-worktree-isolation` and merge back only after the integrated branch is +review-clean. + +### Anti-tail discipline + +- **One card, one goal** — if a card grows a second goal, split it. +- **No silent scope expansion** — a file outside Allowed Scope means update the + scope explicitly or open a backlog issue. +- **No commit during a fix loop without re-running review** — partial fixes ship + under the cover of "addressed". +- **No mocking the real collaborator chain** in integration tests unless the + card says so. + ## Route Map - Need a plan or design handoff: `do-it-planning`. diff --git a/skills/do-it/do-it-visual-planning/SKILL.md b/skills/do-it/do-it-visual-planning/SKILL.md index d7711f4..70b68f1 100644 --- a/skills/do-it/do-it-visual-planning/SKILL.md +++ b/skills/do-it/do-it-visual-planning/SKILL.md @@ -55,7 +55,7 @@ Skip it for text-only decisions, one-line questions, or plans where a table is c `templates/` ships ready-made content fragments for two recurring artifacts: -- `templates/plan-card.html` — a plan / task card (goal, scope, acceptance criteria, verification, risks); section order matches `.do-it/handbook/task-card-template.md` so a visual card and a written card stay consistent. +- `templates/plan-card.html` — a plan / task card (goal, scope, acceptance criteria, verification, risks); section order matches the task-card layout in `do-it-planning` so a visual card and a written card stay consistent. - `templates/review-report.html` — review findings grouped by Blocking / Important / Opportunity with evidence. To use one: copy the fragment into the companion `screen_dir`, fill its `slot:` placeholders, and drop unused sections. The server wraps the fragment in `frame-template.html`, which already carries all CSS — the fragment stays small because only the content varies, and a consistent skeleton means the layout is not re-derived each time. From ef76f23e6dfd0d8586f85ab4af4f77c14bd46059 Mon Sep 17 00:00:00 2001 From: tdwhere123 <tdwhere123@gmail.com> Date: Fri, 5 Jun 2026 17:45:42 +0800 Subject: [PATCH 03/10] refactor(skills): fold do-it-grill-log into do-it-grill (23 -> 22 skills) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit grill-log was an artifact-format skill, not a routable capability — it only defined the .do-it/grill/<task>.md shape that grill itself writes. Folded the format into do-it-grill as a concise § Grill Log Artifact section (path/slug rule, frontmatter + items format, status rules, append-only discipline) and deprecated the standalone skill. - manifest: removed from skills[]; added to deprecatedTargets with the 0.10.0 legacyHash so existing installs remove it on upgrade. - build scripts (build-skills-index HANDBOOK, build-index-json category map): dropped the entry; regenerated _index.md + index.json + plugins/do-it. - references rewired: do-it-grill inline refs -> § Grill Log Artifact, do-it-brainstorm slug rule + related skills, docs/routing-matrix. Verified: simulated 0.10.0 -> current upgrade removes the installed grill-log skill and doctor reports clean; check-skill-links resolves; validate-agent-bundle passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- docs/routing-matrix.md | 4 +- index.json | 14 +- manifest.json | 14 +- plugins/do-it/skills/_index.md | 1 - .../do-it/skills/do-it-brainstorm/SKILL.md | 5 +- plugins/do-it/skills/do-it-grill-log/SKILL.md | 153 ------------------ plugins/do-it/skills/do-it-grill/SKILL.md | 55 ++++++- scripts/build-index-json.mjs | 1 - scripts/build-skills-index.mjs | 1 - skills/do-it/do-it-brainstorm/SKILL.md | 5 +- skills/do-it/do-it-grill-log/SKILL.md | 153 ------------------ skills/do-it/do-it-grill/SKILL.md | 55 ++++++- 12 files changed, 114 insertions(+), 347 deletions(-) delete mode 100644 plugins/do-it/skills/do-it-grill-log/SKILL.md delete mode 100644 skills/do-it/do-it-grill-log/SKILL.md diff --git a/docs/routing-matrix.md b/docs/routing-matrix.md index ca1bcdb..6645bb6 100644 --- a/docs/routing-matrix.md +++ b/docs/routing-matrix.md @@ -130,8 +130,8 @@ rebuilds it from each `skills/do-it/<name>/SKILL.md` frontmatter and - `do-it-context`: maintains the project's canonical `.do-it/CONTEXT.md` — one-line definitions for terms, invariants, and relationships that downstream skills (grill, planning, review) read before debating semantics. -- `do-it-grill-log`: writes the per-task `.do-it/grill/<task>.md` artifact - (`kind`, falsifier, status, evidence). Read by `do-it-planning` and +- `do-it-grill` § Grill Log Artifact: writes the per-task `.do-it/grill/<task>.md` + artifact (`kind`, falsifier, status, evidence). Read by `do-it-planning` and `do-it-verification-gate` so unresolved facts or execution-blocking decisions block closeout. - `do-it-architecture-scan`: checks ownership, dependency direction, coupling, diff --git a/index.json b/index.json index 2f251be..6474a75 100644 --- a/index.json +++ b/index.json @@ -4,13 +4,13 @@ "package": "@tdwhere/do-it", "repository": "https://github.com/tdwhere123/do-it", "domain": "agentic-workflow", - "total_skills": 23, + "total_skills": 22, "total_agents": 23, "coverage": { "skill_groups": { "index": 1, "mainline": 7, - "maintenance": 4, + "maintenance": 3, "on-demand": 10, "optional": 1 }, @@ -79,16 +79,6 @@ "source": "skills/do-it/do-it-context", "target": "skills/do-it-context" }, - { - "kind": "skill", - "name": "do-it-grill-log", - "description": "Use when grill facts or decisions need durable status logging as kind fact or decision before work continues.", - "origin": "do-it", - "optional": false, - "group": "maintenance", - "source": "skills/do-it/do-it-grill-log", - "target": "skills/do-it-grill-log" - }, { "kind": "skill", "name": "do-it-brainstorm", diff --git a/manifest.json b/manifest.json index ecf4f53..f12e8fc 100644 --- a/manifest.json +++ b/manifest.json @@ -359,6 +359,14 @@ "15619616cf9b0d82f74f81e472ad1669b5cc23f56b8b6adb31d9e33ddb16d79e" ], "reason": "removed after 0.4.x; use do-it-router plus focused planning, TDD/debugging, review-loop, fix-loop, and verification-gate as needed" + }, + { + "name": "do-it-grill-log", + "target": "skills/do-it-grill-log", + "legacyHashes": [ + "3d78d21c9cf63494773970273e750a7893d8dafc78992ce8a02bb01a417dd276" + ], + "reason": "folded into do-it-grill as the Grill Log Artifact section" } ], "skills": [ @@ -398,12 +406,6 @@ "target": "skills/do-it-context", "origin": "do-it" }, - { - "name": "do-it-grill-log", - "source": "skills/do-it/do-it-grill-log", - "target": "skills/do-it-grill-log", - "origin": "do-it" - }, { "name": "do-it-brainstorm", "source": "skills/do-it/do-it-brainstorm", diff --git a/plugins/do-it/skills/_index.md b/plugins/do-it/skills/_index.md index baba0d8..4e49e42 100644 --- a/plugins/do-it/skills/_index.md +++ b/plugins/do-it/skills/_index.md @@ -36,7 +36,6 @@ router 推荐按需加载:用 Skill 工具 + skill 名加载详情;不要一 - **do-it-handbook** — a project needs a durable `.do-it/handbook/` skeleton for architecture, invari… - **do-it-context** — repo terms or invariants are drifting and `.do-it/CONTEXT.md` should become th… -- **do-it-grill-log** — grill facts or decisions need durable status logging as kind fact or decision… - **do-it-skill-authoring** — creating or updating do-it skills and you need clear triggers, return shape, w… ## 其他 (manifest 已声明但未分组) diff --git a/plugins/do-it/skills/do-it-brainstorm/SKILL.md b/plugins/do-it/skills/do-it-brainstorm/SKILL.md index 5694f3b..cc4664f 100644 --- a/plugins/do-it/skills/do-it-brainstorm/SKILL.md +++ b/plugins/do-it/skills/do-it-brainstorm/SKILL.md @@ -148,7 +148,7 @@ When durable handoff is useful, write: .do-it/brainstorm/<task-slug>.md ``` -`<task-slug>` follows the same rule as `do-it-grill-log`: slug from the user title or a short hash, with an optional session prefix. `<cwd>/.do-it/brainstorm/.gitkeep` should exist when the project tracks do-it artifacts. +`<task-slug>` follows the same slug rule as the grill log (see `do-it-grill` § Grill Log Artifact): slug from the user title or a short hash, with an optional session prefix. `<cwd>/.do-it/brainstorm/.gitkeep` should exist when the project tracks do-it artifacts. In the same turn, write the slug to the task pointer so router and other skills can pick it up: @@ -288,7 +288,6 @@ After discussion or artifact creation: - `do-it-router` — sets tier and decides whether brainstorm is useful. - `do-it-subagent-orchestration` — dispatch contract for selected lenses. -- `do-it-grill` — converges the must-discuss stack. -- `do-it-grill-log` — records resolved facts and decisions. +- `do-it-grill` — converges the must-discuss stack and records resolved facts and decisions in its grill log. - `do-it-review-loop` — reviews delivered diff, skill quality, install readiness, and release risk after implementation. - `do-it-context` — sediments terms anchored during brainstorm or grill. diff --git a/plugins/do-it/skills/do-it-grill-log/SKILL.md b/plugins/do-it/skills/do-it-grill-log/SKILL.md deleted file mode 100644 index a5ffe0d..0000000 --- a/plugins/do-it/skills/do-it-grill-log/SKILL.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -name: do-it-grill-log -description: "Use when grill facts or decisions need durable status logging as kind fact or decision before work continues." ---- - -# Do-It Grill Log - -## Purpose - -`.do-it/grill/<task>.md` is the per-task artifact that records every fact or decision grilling has actually pressure-tested, the cheap falsifier you used when one exists, and the resolution. It outlives any single chat turn and feeds `do-it-planning` and `do-it-verification-gate`. - -Without it, grilling is just a vibe — once context compacts, every signal is gone. - -## When To Use - -- Inside `do-it-grill` after a fact has been tested or a user decision has been made — write the result here. -- Inside `do-it-planning` to confirm no unresolved item blocks the plan. -- Inside `do-it-verification-gate` (and the gate hook) — fail closeout only when an unresolved decision still changes execution or a factual premise is still unverified. - -## File Path - -``` -.do-it/grill/<task-slug>.md -``` - -`<task-slug>` should be: - -- the slug from the user's task title (lowercased, dash-separated, ≤32 chars), if one is obvious; -- otherwise the first 8 characters of the SHA-1 of the user's first prompt this turn; -- prefixed with the short session id when collisions are likely (e.g. `s1a2-fix-login`). - -`<cwd>/.do-it/grill/.gitkeep` should exist so the directory tracks in version control. - -## File Format - -```markdown ---- -task: <one-line title> -session_id: <id> -created: <YYYY-MM-DD> -status: open ---- - -## Items tested - -- [ ] **<the load-bearing fact or decision, stated as a claim>** - - kind: <fact | decision> - - falsifier: <the cheap check used to test a fact, or `user choice required` for a decision> - - status: <confirmed | refuted | chosen | deferred | needs_user_decision> - - evidence: <link / file:line / grep output snippet> - -## Anchored terms - -- **<term>**: <definition> ← from CLAUDE.md / .do-it/CONTEXT.md / clarified this turn - -## Failure modes considered - -- correctness: ... -- contract: ... -- migration: ... -- performance: ... -- security: ... -- UX: ... -``` - -Use `confirmed` / `refuted` only for facts. Use `chosen` / `deferred` / `needs_user_decision` only for user preferences or product decisions. A `needs_user_decision` item blocks only when it changes the next execution step. When every blocking item is resolved, change frontmatter `status: open` → `status: resolved`. - -## Style rules - -- One bullet per item. No nested bullets in the bullet body — each item is independent. -- Falsifier must be cheap and deterministic. "Read the spec" is not a falsifier; "grep -F 'createOrder' src/" is. -- Evidence is the literal artifact: a path, a line number, a snippet of output. Never paraphrase. -- "Anchored terms" entries get sedimented to `.do-it/CONTEXT.md` (see `do-it-context`) — this section is just a working pad. -- Failure modes section captures predicted modes by category; it is permission-to-stop-thinking, not a binding promise. -- Do not mark a user preference as `confirmed`; if the user chose it, use `chosen`. -- Do not block closeout on a `deferred` preference unless the current implementation still depends on it. - -## Append-only discipline - -- New items are appended; existing items are mutated in place (`needs_user_decision` → `chosen`/`deferred`, or fact status filled in). Never delete an item — refute or defer it instead. -- The frontmatter `status` flips to `resolved` once no execution-blocking item remains. Do not flip it back to `open` retroactively without a new entry explaining why. - -## Worked example - -```markdown ---- -task: dedupe grill across same session -session_id: s1a2 -created: 2026-05-02 -status: resolved ---- - -## Items tested - -- [x] **Same-session re-grill is wasted unless prompt diverges materially.** - - kind: fact - - falsifier: count tokens injected for back-to-back implement requests in one transcript. - - status: confirmed - - evidence: hooks/grill-prompt.sh:38 — emits ~300 tokens; second call adds zero signal. -- [x] **Question turns must not consume the real same-session grill marker.** - - kind: fact - - falsifier: simulate question prompt followed by work prompt and inspect session state. - - status: confirmed - - evidence: hooks/router.sh sets `last_prompt_kind`, while hooks/grill-prompt.sh treats `grilled=1` as the real de-dup marker. - -## Anchored terms - -- **grilled**: a session-state flag in `${session_dir}/state.json`; value `1` means a real grill reminder fired this session. Question turns use `last_prompt_kind=question`. - -## Failure modes considered - -- correctness: forgetting to flip `grilled=1` would cause repeated injection — covered. -- contract: external scripts reading `state.json` would see new key — acceptable, additive. -``` - -## Common Rationalizations - -- *"I'll record it later."* — Later means after compaction, which means never. -- *"It's obvious why I confirmed this."* — Obvious to you now, not to verification next turn. -- *"This is too small to log."* — Then this premise wasn't load-bearing; you should not have grilled it. -- *"I changed my mind, let me delete that line."* — Mutate decision in place; `refuted` with evidence is more honest. - -## Red Flags - -- Every fact is `confirmed`. (Are you grilling, or rubber-stamping?) -- All facts are `refuted` and the plan still proceeds unchanged. (Why grill?) -- `status: resolved` with execution-blocking `needs_user_decision` items remaining. (Do not flip status until each blocking item resolves.) -- File grows past ~150 lines for a single task. (Probably needs splitting into sub-tasks, or the task is too broad.) - -## Stop Conditions - -Stop and return to `do-it-grill` or the user when: - -- a decision item is `needs_user_decision` and changes the next action; -- a fact has no cheap falsifier but the implementation depends on it; -- the log would need multiple unrelated task slugs to stay coherent; -- the evidence is only paraphrase, memory, or old transcript context. - -## Verification - -Before using the log as closeout evidence: - -- every execution-blocking fact is `confirmed` or `refuted`; -- every execution-blocking decision is `chosen`, `deferred`, or escalated; -- every evidence field points to a file, command, grep result, or explicit user choice; -- frontmatter `status: resolved` appears only when no blocking item remains. - -## Related Skills - -- `do-it-grill` — primary writer. -- `do-it-context` — destination for sediment of "anchored terms". -- `do-it-planning` — must read this file before producing the plan card; references the slug in plan frontmatter. -- `do-it-verification-gate` — must check that no execution-blocking unresolved item remains before allowing closeout. diff --git a/plugins/do-it/skills/do-it-grill/SKILL.md b/plugins/do-it/skills/do-it-grill/SKILL.md index c047c48..11ca100 100644 --- a/plugins/do-it/skills/do-it-grill/SKILL.md +++ b/plugins/do-it/skills/do-it-grill/SKILL.md @@ -21,7 +21,7 @@ A common failure is to dump a 5-question template at the user and call it grilli 2. **Anchor terms before debating intent.** If the user uses a term that has a definition in `CLAUDE.md`, `.do-it/CONTEXT.md`, or visible in code with a different shape — surface the conflict before going further. 3. **Verify, don't ask, when verification is cheap.** If the question can be answered with `rg`, `cat`, or a quick local command, do that and report what you found. 4. **Ask only for decisions.** Ask the user one focused question only when local truth cannot decide a preference, priority, or scope tradeoff that changes execution. Before asking, explain the decision in plain language, list the viable options with benefits/costs/risks, and recommend a default. -5. **Sediment what you learned.** When a term gets clarified or a constraint surfaces, append it to `.do-it/CONTEXT.md` (one line, declarative). Use `do-it-grill-log` for the per-task `.do-it/grill/<task>.md` artifact (`kind: fact|decision`, falsifier, status, evidence). +5. **Sediment what you learned.** When a term gets clarified or a constraint surfaces, append it to `.do-it/CONTEXT.md` (one line, declarative). Record the per-task `.do-it/grill/<task>.md` artifact (`kind: fact|decision`, falsifier, status, evidence) per § Grill Log Artifact below. ## When To Use @@ -71,7 +71,7 @@ Run this loop until every execution-blocking item is resolved: facts become `con 1. **Pick the most load-bearing premise.** What single belief, if wrong, would change the most downstream decisions? 2. **Try to falsify cheaply.** Read the file, grep for the symbol, run the unit test, glance at the schema. If you find evidence, jump to step 4. 3. **Ask one focused question** only when the remaining unknown is a user decision. Start with the minimum context the user needs, then show 2-3 real options with tradeoffs and a recommended default so the user has something concrete to accept or correct. -4. **Record the outcome** in `.do-it/grill/<task>.md` (see `do-it-grill-log`). Use `kind: fact` with `confirmed/refuted` for evidence, or `kind: decision` with `chosen/deferred/needs_user_decision` for user preferences. +4. **Record the outcome** in `.do-it/grill/<task>.md` (see § Grill Log Artifact). Use `kind: fact` with `confirmed/refuted` for evidence, or `kind: decision` with `chosen/deferred/needs_user_decision` for user preferences. 5. **Repeat** with the next-most-load-bearing premise, until the remaining unknowns no longer change the route. ## Assumptions Mode @@ -103,7 +103,7 @@ Convergence flow: 1. **Read the artifact.** Parse `Requirement Shape`, `Product Boundary`, `Core Goal`, `Options`, `Architecture Foundation`, and `Grill Handoff`. Each `Must Resolve In Grill` entry is a candidate premise the brainstorm lenses thought a human, grill, or local verification had to settle. 2. **Rank by route-impact.** Sort candidates by "if this is wrong, how many downstream choices change?" — same rule as the Iterative Loop. Cross-lens tensions usually outrank single-lens one-offs. -3. **Resolve each candidate** via the existing loop (verify cheaply, ask one question if a user decision is needed, log the result in `.do-it/grill/<task>.md` per `do-it-grill-log`). +3. **Resolve each candidate** via the existing loop (verify cheaply, ask one question if a user decision is needed, log the result in `.do-it/grill/<task>.md` per § Grill Log Artifact). 4. **Reference the brainstorm slug** in the grill log frontmatter: add `brainstorm: <task-slug>` so `do-it-planning` and `do-it-verification-gate` can trace the lineage. 5. **Flip brainstorm status.** Once every execution-blocking `Must Resolve In Grill` item has a resolution (`chosen` / `deferred` / `needs_user_decision` for decisions; `confirmed` / `refuted` for facts), edit the brainstorm artifact's frontmatter from `status: open` to `status: converged`. Do not delete the artifact; future sessions read it. @@ -238,10 +238,53 @@ For a heavy grill: - Treating architecture taste as delivery truth. - Using a fuzzy term repeatedly without ever defining it back to the user or to `.do-it/CONTEXT.md`. +## Grill Log Artifact + +Grill records every pressure-tested fact or decision in `.do-it/grill/<task>.md` +so the signal outlives the chat turn and feeds `do-it-planning` and +`do-it-verification-gate`. Without it, grilling is just a vibe — once context +compacts, every signal is gone. + +`<task-slug>` is the user's task title (lowercased, dash-separated, ≤32 chars) +when one is obvious, else the first 8 chars of the SHA-1 of the first prompt; +prefix with the short session id when collisions are likely. Keep +`.do-it/grill/.gitkeep` so the directory tracks in git. + +Format: + +```markdown +--- +task: <one-line title> +session_id: <id> +created: <YYYY-MM-DD> +status: open # flips to `resolved` when no execution-blocking item remains +brainstorm: <slug> # only when converging a brainstorm artifact +--- + +## Items tested + +- [ ] **<the load-bearing fact or decision, stated as a claim>** + - kind: <fact | decision> + - falsifier: <the cheap deterministic check for a fact, or `user choice required` for a decision> + - status: <confirmed | refuted | chosen | deferred | needs_user_decision> + - evidence: <file:line / grep output / explicit user choice — the literal artifact, never paraphrase> + +## Anchored terms + +- **<term>**: <definition> ← from CLAUDE.md / .do-it/CONTEXT.md / clarified this turn +``` + +Rules: use `confirmed`/`refuted` only for facts, `chosen`/`deferred`/`needs_user_decision` +only for decisions. A `needs_user_decision` item blocks only when it changes the +next execution step. Append new items and mutate existing ones in place — never +delete an item; refute or defer it with evidence. Anchored-terms entries get +sedimented to `.do-it/CONTEXT.md` (see `do-it-context`); this section is a +working pad. Flip `status: resolved` once no execution-blocking item remains, and +do not flip it back without a new entry explaining why. + ## Related Skills -- `do-it-context` — set up and maintain `.do-it/CONTEXT.md` with project terms and invariants. -- `do-it-grill-log` — write per-task `.do-it/grill/<task>.md` artifacts (`kind`, falsifier, status, evidence). +- `do-it-context` — set up and maintain `.do-it/CONTEXT.md` with project terms and invariants (sediment destination for anchored terms). - `do-it-brainstorm` — divergent persona pass that runs before grill; produces the open decisions grill converges on. -- `do-it-planning` — consume the grill outcome into a plan card under `.do-it/plans/<task>.md`. +- `do-it-planning` — consume the grill outcome into a plan card under `.do-it/plans/<task>.md`; reads the grill slug. - `do-it-review-loop` — apply pressure to the delivered diff after grilling has set the bar. diff --git a/scripts/build-index-json.mjs b/scripts/build-index-json.mjs index 74159aa..402092f 100644 --- a/scripts/build-index-json.mjs +++ b/scripts/build-index-json.mjs @@ -33,7 +33,6 @@ const SKILL_GROUPS = new Map([ ["do-it-subagent-orchestration", "on-demand"], ["do-it-handbook", "maintenance"], ["do-it-context", "maintenance"], - ["do-it-grill-log", "maintenance"], ["do-it-skill-authoring", "maintenance"], ["do-it-visual-planning", "optional"] ]); diff --git a/scripts/build-skills-index.mjs b/scripts/build-skills-index.mjs index 09ebde8..c6be17a 100644 --- a/scripts/build-skills-index.mjs +++ b/scripts/build-skills-index.mjs @@ -42,7 +42,6 @@ const ON_DEMAND = [ const HANDBOOK = [ "do-it-handbook", "do-it-context", - "do-it-grill-log", "do-it-skill-authoring" ]; diff --git a/skills/do-it/do-it-brainstorm/SKILL.md b/skills/do-it/do-it-brainstorm/SKILL.md index 5694f3b..cc4664f 100644 --- a/skills/do-it/do-it-brainstorm/SKILL.md +++ b/skills/do-it/do-it-brainstorm/SKILL.md @@ -148,7 +148,7 @@ When durable handoff is useful, write: .do-it/brainstorm/<task-slug>.md ``` -`<task-slug>` follows the same rule as `do-it-grill-log`: slug from the user title or a short hash, with an optional session prefix. `<cwd>/.do-it/brainstorm/.gitkeep` should exist when the project tracks do-it artifacts. +`<task-slug>` follows the same slug rule as the grill log (see `do-it-grill` § Grill Log Artifact): slug from the user title or a short hash, with an optional session prefix. `<cwd>/.do-it/brainstorm/.gitkeep` should exist when the project tracks do-it artifacts. In the same turn, write the slug to the task pointer so router and other skills can pick it up: @@ -288,7 +288,6 @@ After discussion or artifact creation: - `do-it-router` — sets tier and decides whether brainstorm is useful. - `do-it-subagent-orchestration` — dispatch contract for selected lenses. -- `do-it-grill` — converges the must-discuss stack. -- `do-it-grill-log` — records resolved facts and decisions. +- `do-it-grill` — converges the must-discuss stack and records resolved facts and decisions in its grill log. - `do-it-review-loop` — reviews delivered diff, skill quality, install readiness, and release risk after implementation. - `do-it-context` — sediments terms anchored during brainstorm or grill. diff --git a/skills/do-it/do-it-grill-log/SKILL.md b/skills/do-it/do-it-grill-log/SKILL.md deleted file mode 100644 index a5ffe0d..0000000 --- a/skills/do-it/do-it-grill-log/SKILL.md +++ /dev/null @@ -1,153 +0,0 @@ ---- -name: do-it-grill-log -description: "Use when grill facts or decisions need durable status logging as kind fact or decision before work continues." ---- - -# Do-It Grill Log - -## Purpose - -`.do-it/grill/<task>.md` is the per-task artifact that records every fact or decision grilling has actually pressure-tested, the cheap falsifier you used when one exists, and the resolution. It outlives any single chat turn and feeds `do-it-planning` and `do-it-verification-gate`. - -Without it, grilling is just a vibe — once context compacts, every signal is gone. - -## When To Use - -- Inside `do-it-grill` after a fact has been tested or a user decision has been made — write the result here. -- Inside `do-it-planning` to confirm no unresolved item blocks the plan. -- Inside `do-it-verification-gate` (and the gate hook) — fail closeout only when an unresolved decision still changes execution or a factual premise is still unverified. - -## File Path - -``` -.do-it/grill/<task-slug>.md -``` - -`<task-slug>` should be: - -- the slug from the user's task title (lowercased, dash-separated, ≤32 chars), if one is obvious; -- otherwise the first 8 characters of the SHA-1 of the user's first prompt this turn; -- prefixed with the short session id when collisions are likely (e.g. `s1a2-fix-login`). - -`<cwd>/.do-it/grill/.gitkeep` should exist so the directory tracks in version control. - -## File Format - -```markdown ---- -task: <one-line title> -session_id: <id> -created: <YYYY-MM-DD> -status: open ---- - -## Items tested - -- [ ] **<the load-bearing fact or decision, stated as a claim>** - - kind: <fact | decision> - - falsifier: <the cheap check used to test a fact, or `user choice required` for a decision> - - status: <confirmed | refuted | chosen | deferred | needs_user_decision> - - evidence: <link / file:line / grep output snippet> - -## Anchored terms - -- **<term>**: <definition> ← from CLAUDE.md / .do-it/CONTEXT.md / clarified this turn - -## Failure modes considered - -- correctness: ... -- contract: ... -- migration: ... -- performance: ... -- security: ... -- UX: ... -``` - -Use `confirmed` / `refuted` only for facts. Use `chosen` / `deferred` / `needs_user_decision` only for user preferences or product decisions. A `needs_user_decision` item blocks only when it changes the next execution step. When every blocking item is resolved, change frontmatter `status: open` → `status: resolved`. - -## Style rules - -- One bullet per item. No nested bullets in the bullet body — each item is independent. -- Falsifier must be cheap and deterministic. "Read the spec" is not a falsifier; "grep -F 'createOrder' src/" is. -- Evidence is the literal artifact: a path, a line number, a snippet of output. Never paraphrase. -- "Anchored terms" entries get sedimented to `.do-it/CONTEXT.md` (see `do-it-context`) — this section is just a working pad. -- Failure modes section captures predicted modes by category; it is permission-to-stop-thinking, not a binding promise. -- Do not mark a user preference as `confirmed`; if the user chose it, use `chosen`. -- Do not block closeout on a `deferred` preference unless the current implementation still depends on it. - -## Append-only discipline - -- New items are appended; existing items are mutated in place (`needs_user_decision` → `chosen`/`deferred`, or fact status filled in). Never delete an item — refute or defer it instead. -- The frontmatter `status` flips to `resolved` once no execution-blocking item remains. Do not flip it back to `open` retroactively without a new entry explaining why. - -## Worked example - -```markdown ---- -task: dedupe grill across same session -session_id: s1a2 -created: 2026-05-02 -status: resolved ---- - -## Items tested - -- [x] **Same-session re-grill is wasted unless prompt diverges materially.** - - kind: fact - - falsifier: count tokens injected for back-to-back implement requests in one transcript. - - status: confirmed - - evidence: hooks/grill-prompt.sh:38 — emits ~300 tokens; second call adds zero signal. -- [x] **Question turns must not consume the real same-session grill marker.** - - kind: fact - - falsifier: simulate question prompt followed by work prompt and inspect session state. - - status: confirmed - - evidence: hooks/router.sh sets `last_prompt_kind`, while hooks/grill-prompt.sh treats `grilled=1` as the real de-dup marker. - -## Anchored terms - -- **grilled**: a session-state flag in `${session_dir}/state.json`; value `1` means a real grill reminder fired this session. Question turns use `last_prompt_kind=question`. - -## Failure modes considered - -- correctness: forgetting to flip `grilled=1` would cause repeated injection — covered. -- contract: external scripts reading `state.json` would see new key — acceptable, additive. -``` - -## Common Rationalizations - -- *"I'll record it later."* — Later means after compaction, which means never. -- *"It's obvious why I confirmed this."* — Obvious to you now, not to verification next turn. -- *"This is too small to log."* — Then this premise wasn't load-bearing; you should not have grilled it. -- *"I changed my mind, let me delete that line."* — Mutate decision in place; `refuted` with evidence is more honest. - -## Red Flags - -- Every fact is `confirmed`. (Are you grilling, or rubber-stamping?) -- All facts are `refuted` and the plan still proceeds unchanged. (Why grill?) -- `status: resolved` with execution-blocking `needs_user_decision` items remaining. (Do not flip status until each blocking item resolves.) -- File grows past ~150 lines for a single task. (Probably needs splitting into sub-tasks, or the task is too broad.) - -## Stop Conditions - -Stop and return to `do-it-grill` or the user when: - -- a decision item is `needs_user_decision` and changes the next action; -- a fact has no cheap falsifier but the implementation depends on it; -- the log would need multiple unrelated task slugs to stay coherent; -- the evidence is only paraphrase, memory, or old transcript context. - -## Verification - -Before using the log as closeout evidence: - -- every execution-blocking fact is `confirmed` or `refuted`; -- every execution-blocking decision is `chosen`, `deferred`, or escalated; -- every evidence field points to a file, command, grep result, or explicit user choice; -- frontmatter `status: resolved` appears only when no blocking item remains. - -## Related Skills - -- `do-it-grill` — primary writer. -- `do-it-context` — destination for sediment of "anchored terms". -- `do-it-planning` — must read this file before producing the plan card; references the slug in plan frontmatter. -- `do-it-verification-gate` — must check that no execution-blocking unresolved item remains before allowing closeout. diff --git a/skills/do-it/do-it-grill/SKILL.md b/skills/do-it/do-it-grill/SKILL.md index c047c48..11ca100 100644 --- a/skills/do-it/do-it-grill/SKILL.md +++ b/skills/do-it/do-it-grill/SKILL.md @@ -21,7 +21,7 @@ A common failure is to dump a 5-question template at the user and call it grilli 2. **Anchor terms before debating intent.** If the user uses a term that has a definition in `CLAUDE.md`, `.do-it/CONTEXT.md`, or visible in code with a different shape — surface the conflict before going further. 3. **Verify, don't ask, when verification is cheap.** If the question can be answered with `rg`, `cat`, or a quick local command, do that and report what you found. 4. **Ask only for decisions.** Ask the user one focused question only when local truth cannot decide a preference, priority, or scope tradeoff that changes execution. Before asking, explain the decision in plain language, list the viable options with benefits/costs/risks, and recommend a default. -5. **Sediment what you learned.** When a term gets clarified or a constraint surfaces, append it to `.do-it/CONTEXT.md` (one line, declarative). Use `do-it-grill-log` for the per-task `.do-it/grill/<task>.md` artifact (`kind: fact|decision`, falsifier, status, evidence). +5. **Sediment what you learned.** When a term gets clarified or a constraint surfaces, append it to `.do-it/CONTEXT.md` (one line, declarative). Record the per-task `.do-it/grill/<task>.md` artifact (`kind: fact|decision`, falsifier, status, evidence) per § Grill Log Artifact below. ## When To Use @@ -71,7 +71,7 @@ Run this loop until every execution-blocking item is resolved: facts become `con 1. **Pick the most load-bearing premise.** What single belief, if wrong, would change the most downstream decisions? 2. **Try to falsify cheaply.** Read the file, grep for the symbol, run the unit test, glance at the schema. If you find evidence, jump to step 4. 3. **Ask one focused question** only when the remaining unknown is a user decision. Start with the minimum context the user needs, then show 2-3 real options with tradeoffs and a recommended default so the user has something concrete to accept or correct. -4. **Record the outcome** in `.do-it/grill/<task>.md` (see `do-it-grill-log`). Use `kind: fact` with `confirmed/refuted` for evidence, or `kind: decision` with `chosen/deferred/needs_user_decision` for user preferences. +4. **Record the outcome** in `.do-it/grill/<task>.md` (see § Grill Log Artifact). Use `kind: fact` with `confirmed/refuted` for evidence, or `kind: decision` with `chosen/deferred/needs_user_decision` for user preferences. 5. **Repeat** with the next-most-load-bearing premise, until the remaining unknowns no longer change the route. ## Assumptions Mode @@ -103,7 +103,7 @@ Convergence flow: 1. **Read the artifact.** Parse `Requirement Shape`, `Product Boundary`, `Core Goal`, `Options`, `Architecture Foundation`, and `Grill Handoff`. Each `Must Resolve In Grill` entry is a candidate premise the brainstorm lenses thought a human, grill, or local verification had to settle. 2. **Rank by route-impact.** Sort candidates by "if this is wrong, how many downstream choices change?" — same rule as the Iterative Loop. Cross-lens tensions usually outrank single-lens one-offs. -3. **Resolve each candidate** via the existing loop (verify cheaply, ask one question if a user decision is needed, log the result in `.do-it/grill/<task>.md` per `do-it-grill-log`). +3. **Resolve each candidate** via the existing loop (verify cheaply, ask one question if a user decision is needed, log the result in `.do-it/grill/<task>.md` per § Grill Log Artifact). 4. **Reference the brainstorm slug** in the grill log frontmatter: add `brainstorm: <task-slug>` so `do-it-planning` and `do-it-verification-gate` can trace the lineage. 5. **Flip brainstorm status.** Once every execution-blocking `Must Resolve In Grill` item has a resolution (`chosen` / `deferred` / `needs_user_decision` for decisions; `confirmed` / `refuted` for facts), edit the brainstorm artifact's frontmatter from `status: open` to `status: converged`. Do not delete the artifact; future sessions read it. @@ -238,10 +238,53 @@ For a heavy grill: - Treating architecture taste as delivery truth. - Using a fuzzy term repeatedly without ever defining it back to the user or to `.do-it/CONTEXT.md`. +## Grill Log Artifact + +Grill records every pressure-tested fact or decision in `.do-it/grill/<task>.md` +so the signal outlives the chat turn and feeds `do-it-planning` and +`do-it-verification-gate`. Without it, grilling is just a vibe — once context +compacts, every signal is gone. + +`<task-slug>` is the user's task title (lowercased, dash-separated, ≤32 chars) +when one is obvious, else the first 8 chars of the SHA-1 of the first prompt; +prefix with the short session id when collisions are likely. Keep +`.do-it/grill/.gitkeep` so the directory tracks in git. + +Format: + +```markdown +--- +task: <one-line title> +session_id: <id> +created: <YYYY-MM-DD> +status: open # flips to `resolved` when no execution-blocking item remains +brainstorm: <slug> # only when converging a brainstorm artifact +--- + +## Items tested + +- [ ] **<the load-bearing fact or decision, stated as a claim>** + - kind: <fact | decision> + - falsifier: <the cheap deterministic check for a fact, or `user choice required` for a decision> + - status: <confirmed | refuted | chosen | deferred | needs_user_decision> + - evidence: <file:line / grep output / explicit user choice — the literal artifact, never paraphrase> + +## Anchored terms + +- **<term>**: <definition> ← from CLAUDE.md / .do-it/CONTEXT.md / clarified this turn +``` + +Rules: use `confirmed`/`refuted` only for facts, `chosen`/`deferred`/`needs_user_decision` +only for decisions. A `needs_user_decision` item blocks only when it changes the +next execution step. Append new items and mutate existing ones in place — never +delete an item; refute or defer it with evidence. Anchored-terms entries get +sedimented to `.do-it/CONTEXT.md` (see `do-it-context`); this section is a +working pad. Flip `status: resolved` once no execution-blocking item remains, and +do not flip it back without a new entry explaining why. + ## Related Skills -- `do-it-context` — set up and maintain `.do-it/CONTEXT.md` with project terms and invariants. -- `do-it-grill-log` — write per-task `.do-it/grill/<task>.md` artifacts (`kind`, falsifier, status, evidence). +- `do-it-context` — set up and maintain `.do-it/CONTEXT.md` with project terms and invariants (sediment destination for anchored terms). - `do-it-brainstorm` — divergent persona pass that runs before grill; produces the open decisions grill converges on. -- `do-it-planning` — consume the grill outcome into a plan card under `.do-it/plans/<task>.md`. +- `do-it-planning` — consume the grill outcome into a plan card under `.do-it/plans/<task>.md`; reads the grill slug. - `do-it-review-loop` — apply pressure to the delivered diff after grilling has set the bar. From f952d6b218db076df446bb5905f06edc61066d53 Mon Sep 17 00:00:00 2001 From: tdwhere123 <tdwhere123@gmail.com> Date: Fri, 5 Jun 2026 17:53:17 +0800 Subject: [PATCH 04/10] refactor(skills): fold domain-language into context, visual-planning into planning (22 -> 20) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two more low-utilization skills merged into their natural homes: - do-it-domain-language -> do-it-context (new § Domain Glossary Mode). Both are managed vocabulary; context now carries the Light sediment path plus the deeper canonical-glossary + contradiction pass. - do-it-visual-planning -> do-it-planning (new § Visual Aids). It was optional/ auxiliary ("must not promote tier") and rarely routed. The lightweight .do-it/visual sketch guidance folds into planning; the browser-companion server (scripts/, templates/, references/) is retired. Both deprecated via manifest deprecatedTargets with their 0.10.0 legacyHashes; build scripts, router route-map, planning/context/brainstorm refs, and docs (routing-matrix, upstream-map, maintenance) updated. The domain-language-reviewer AGENT is untouched (separate review lens, not the skill). Verified: 0.10.0 -> current upgrade removes the deprecated skills, doctor reports clean (drift: 0); npm test green; check-skill-links resolves; 20 skills. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --- docs/maintenance.md | 3 +- docs/routing-matrix.md | 22 +- docs/upstream-map.md | 4 +- index.json | 31 +- install/manage.mjs | 2 +- manifest.json | 29 +- plugins/do-it/skills/_index.md | 7 +- plugins/do-it/skills/do-it-context/SKILL.md | 43 +- .../skills/do-it-domain-language/SKILL.md | 76 --- plugins/do-it/skills/do-it-planning/SKILL.md | 12 +- plugins/do-it/skills/do-it-router/SKILL.md | 6 +- .../skills/do-it-visual-planning/SKILL.md | 87 --- .../references/visual-companion.md | 267 --------- .../scripts/frame-template.html | 534 ------------------ .../do-it-visual-planning/scripts/helper.js | 98 ---- .../do-it-visual-planning/scripts/server.cjs | 354 ------------ .../scripts/start-server.sh | 148 ----- .../scripts/stop-server.sh | 56 -- .../templates/plan-card.html | 56 -- .../templates/review-report.html | 47 -- scripts/build-index-json.mjs | 4 +- scripts/build-skills-index.mjs | 1 - skills/do-it/do-it-context/SKILL.md | 43 +- skills/do-it/do-it-domain-language/SKILL.md | 76 --- skills/do-it/do-it-planning/SKILL.md | 12 +- skills/do-it/do-it-router/SKILL.md | 6 +- skills/do-it/do-it-visual-planning/SKILL.md | 87 --- .../references/visual-companion.md | 267 --------- .../scripts/frame-template.html | 534 ------------------ .../do-it-visual-planning/scripts/helper.js | 98 ---- .../do-it-visual-planning/scripts/server.cjs | 354 ------------ .../scripts/start-server.sh | 148 ----- .../scripts/stop-server.sh | 56 -- .../templates/plan-card.html | 56 -- .../templates/review-report.html | 47 -- 35 files changed, 144 insertions(+), 3527 deletions(-) delete mode 100644 plugins/do-it/skills/do-it-domain-language/SKILL.md delete mode 100644 plugins/do-it/skills/do-it-visual-planning/SKILL.md delete mode 100644 plugins/do-it/skills/do-it-visual-planning/references/visual-companion.md delete mode 100644 plugins/do-it/skills/do-it-visual-planning/scripts/frame-template.html delete mode 100644 plugins/do-it/skills/do-it-visual-planning/scripts/helper.js delete mode 100644 plugins/do-it/skills/do-it-visual-planning/scripts/server.cjs delete mode 100755 plugins/do-it/skills/do-it-visual-planning/scripts/start-server.sh delete mode 100755 plugins/do-it/skills/do-it-visual-planning/scripts/stop-server.sh delete mode 100644 plugins/do-it/skills/do-it-visual-planning/templates/plan-card.html delete mode 100644 plugins/do-it/skills/do-it-visual-planning/templates/review-report.html delete mode 100644 skills/do-it/do-it-domain-language/SKILL.md delete mode 100644 skills/do-it/do-it-visual-planning/SKILL.md delete mode 100644 skills/do-it/do-it-visual-planning/references/visual-companion.md delete mode 100644 skills/do-it/do-it-visual-planning/scripts/frame-template.html delete mode 100644 skills/do-it/do-it-visual-planning/scripts/helper.js delete mode 100644 skills/do-it/do-it-visual-planning/scripts/server.cjs delete mode 100755 skills/do-it/do-it-visual-planning/scripts/start-server.sh delete mode 100755 skills/do-it/do-it-visual-planning/scripts/stop-server.sh delete mode 100644 skills/do-it/do-it-visual-planning/templates/plan-card.html delete mode 100644 skills/do-it/do-it-visual-planning/templates/review-report.html diff --git a/docs/maintenance.md b/docs/maintenance.md index f704f57..63f97f3 100644 --- a/docs/maintenance.md +++ b/docs/maintenance.md @@ -259,8 +259,7 @@ surface generated from the same maintained manifest: `do-it` at `./plugins/do-it`. - `plugins/do-it/.codex-plugin/plugin.json` — plugin metadata with version parity to `package.json`. -- `plugins/do-it/skills/` — generated from every `manifest.skills[]` entry, - including optional `do-it-visual-planning`. +- `plugins/do-it/skills/` — generated from every `manifest.skills[]` entry. - `plugins/do-it/agents/` — generated from every `manifest.agents[]` entry. - `scripts/build-codex-plugin.mjs` — the only supported way to refresh the generated plugin bundle. diff --git a/docs/routing-matrix.md b/docs/routing-matrix.md index 6645bb6..960a58c 100644 --- a/docs/routing-matrix.md +++ b/docs/routing-matrix.md @@ -130,6 +130,8 @@ rebuilds it from each `skills/do-it/<name>/SKILL.md` frontmatter and - `do-it-context`: maintains the project's canonical `.do-it/CONTEXT.md` — one-line definitions for terms, invariants, and relationships that downstream skills (grill, planning, review) read before debating semantics. + Its § Domain Glossary Mode stabilizes domain terms and catches contradictions + between user language, docs, and code. - `do-it-grill` § Grill Log Artifact: writes the per-task `.do-it/grill/<task>.md` artifact (`kind`, falsifier, status, evidence). Read by `do-it-planning` and `do-it-verification-gate` so unresolved facts or execution-blocking @@ -138,8 +140,6 @@ rebuilds it from each `skills/do-it/<name>/SKILL.md` frontmatter and migration path, rollout risk, and failure isolation. - `do-it-interface-drill`: checks API, type, schema, CLI, docs, protocol, and adapter contracts at the producer/consumer boundary. -- `do-it-domain-language`: stabilizes domain terms and catches contradictions - between user language, docs, and code. - `do-it-tdd`, `do-it-debugging`, `do-it-review-loop`, `do-it-fix-loop`, and `do-it-verification-gate`: focused quality loops used when behavior, root cause, review findings, or completion claims require @@ -148,8 +148,6 @@ rebuilds it from each `skills/do-it/<name>/SKILL.md` frontmatter and slices, ownership boundaries, and return schemas. - `do-it-worktree-isolation` and `do-it-branch-closeout`: optional support for isolated work and final integration. -- `do-it-visual-planning`: optional local visual companion for planning - artifacts; it is not part of the default delivery route. The do-it roles absorb the useful discipline from the previous workflow family: mandatory truth checks, failure-mode forecasting, explicit planning, isolated @@ -183,16 +181,16 @@ class: task` for a delegated slice, or `tier: Heavy, class: wave` for the parent coordinator. Do not use `wave` or `phase` as substitutes for `Standard` or `Heavy`. -`do-it-domain-language`, `do-it-worktree-isolation`, `do-it-skill-authoring`, -and `do-it-visual-planning` are routed by need rather than by tier: +`do-it-worktree-isolation` and `do-it-skill-authoring` are routed by need rather +than by tier: -- use `do-it-domain-language` when overloaded terms, product concepts, or - business rules affect the plan or review; - use `do-it-worktree-isolation` when current workspace state, parallel lanes, or rollback risk requires isolation; -- use `do-it-skill-authoring` when creating or updating skills; -- use `do-it-visual-planning` only when a local visual planning companion would - improve a planning discussion. +- use `do-it-skill-authoring` when creating or updating skills. + +Vocabulary work (overloaded terms, product concepts, business rules) routes to +`do-it-context` § Domain Glossary Mode; visual comparison routes to +`do-it-planning` § Visual Aids. ## Planning Rules @@ -276,7 +274,7 @@ Use for `Heavy` work: 2. Use `do-it-grill` to challenge the decision tree, failure-mode forecast, and path map before implementation. 3. Use `do-it-slicing` to define lanes and shared-file ownership. 4. Run `do-it-interface-drill`, `do-it-architecture-scan`, and - `do-it-domain-language` only where their evidence will change the plan. + `do-it-context` § Domain Glossary Mode only where their evidence will change the plan. 5. Delegate Standard slices unless a child is explicitly assigned Heavy work. 6. Run expanded review, fix-loop, re-review, and branch closeout. diff --git a/docs/upstream-map.md b/docs/upstream-map.md index 9a2ef24..1da0ace 100644 --- a/docs/upstream-map.md +++ b/docs/upstream-map.md @@ -18,7 +18,7 @@ runtime-specific assumptions do not leak into new Codex installs. | `do-it-brainstorm` | requirement-shape discovery before grill | Absorbs multi-perspective divergence into a product + architecture core flow: product boundary, core goal, option tradeoffs, architecture foundation, extension modules, and explicit grill handoff. | | `do-it-architecture-scan` | architecture risk and opportunity scan | Absorbs codebase-improvement heuristics while keeping opportunities non-blocking unless correctness or delivery risk is real. | | `do-it-interface-drill` | interface and boundary design | Absorbs interface-design drills for APIs, schemas, CLIs, events, UI contracts, and agent handoffs. | -| `do-it-domain-language` | canonical term and model alignment | Absorbs ubiquitous-language and domain-model discipline for overloaded terms, glossary updates, and contradictions between code/docs/user language. | +| `do-it-context` § Domain Glossary Mode | canonical term and model alignment | Absorbs ubiquitous-language and domain-model discipline for overloaded terms, glossary updates, and contradictions between code/docs/user language. (Folded in from the former `do-it-domain-language` skill.) | | `do-it-tdd` | behavior-first RED/GREEN loop | Absorbs behavior-via-public-interface testing and one-test-at-a-time tracer-bullet TDD. | | `do-it-debugging` | root-cause investigation | Absorbs systematic debugging and issue triage: reproduce, trace, find root cause, then plan durable RED/GREEN fixes. | | `do-it-subagent-orchestration` | delegated slice protocol | Absorbs parallel-agent dispatch and subagent-driven development, but defaults child agents to Standard slices instead of inheriting Heavy parent flows. | @@ -27,7 +27,7 @@ runtime-specific assumptions do not leak into new Codex installs. | `do-it-verification-gate` | evidence-before-claims closeout | Absorbs legacy verification discipline and makes success claims depend on fresh commands or explicit evidence. | | `do-it-worktree-isolation` | workspace isolation | Absorbs git-worktree setup and current-worktree safety into a do-it support skill. | | `do-it-branch-closeout` | branch/PR/merge finish | Absorbs development-branch finish checks, commit/PR evidence, and cleanup choices. | -| `do-it-visual-planning` | optional planning companion | Absorbs the older visual brainstorming helper as an optional `.do-it/visual` support path, not a core workflow gate. Marked `optional: true` in `manifest.json` from 0.4.0; install with `--with-optional`. | +| `do-it-planning` § Visual Aids | optional planning companion | Absorbs the older visual brainstorming helper as an optional `.do-it/visual` support path, not a core workflow gate. (Folded in from the former `do-it-visual-planning` skill; the browser companion was retired.) | | `do-it-skill-authoring` | skill creation and maintenance | Absorbs progressive-disclosure skill writing and repo-managed skill validation. | ## External Idea Map diff --git a/index.json b/index.json index 6474a75..cf49fc3 100644 --- a/index.json +++ b/index.json @@ -4,19 +4,16 @@ "package": "@tdwhere/do-it", "repository": "https://github.com/tdwhere123/do-it", "domain": "agentic-workflow", - "total_skills": 22, + "total_skills": 20, "total_agents": 23, "coverage": { "skill_groups": { "index": 1, "mainline": 7, "maintenance": 3, - "on-demand": 10, - "optional": 1 + "on-demand": 9 }, - "optional_skills": [ - "do-it-visual-planning" - ] + "optional_skills": [] }, "entries": [ { @@ -72,7 +69,7 @@ { "kind": "skill", "name": "do-it-context", - "description": "Use when repo terms or invariants are drifting and `.do-it/CONTEXT.md` should become the downstream source of truth for names, relationships, and facts.", + "description": "Use when repo terms or invariants are drifting, or when user/docs/code naming disagrees and a canonical glossary is needed — `.do-it/CONTEXT.md` is the downstream source of truth for names, relationships, and facts.", "origin": "do-it", "optional": false, "group": "maintenance", @@ -109,16 +106,6 @@ "source": "skills/do-it/do-it-interface-drill", "target": "skills/do-it-interface-drill" }, - { - "kind": "skill", - "name": "do-it-domain-language", - "description": "Use when user language, docs, and code naming disagree and a canonical domain glossary or handoff vocabulary is needed.", - "origin": "do-it", - "optional": false, - "group": "on-demand", - "source": "skills/do-it/do-it-domain-language", - "target": "skills/do-it-domain-language" - }, { "kind": "skill", "name": "do-it-tdd", @@ -199,16 +186,6 @@ "source": "skills/do-it/do-it-branch-closeout", "target": "skills/do-it-branch-closeout" }, - { - "kind": "skill", - "name": "do-it-visual-planning", - "description": "Use when a plan or design decision would benefit from a small diagram, sketch, mockup, or side-by-side visual artifact alongside text.", - "origin": "do-it", - "optional": true, - "group": "optional", - "source": "skills/do-it/do-it-visual-planning", - "target": "skills/do-it-visual-planning" - }, { "kind": "skill", "name": "do-it-skill-authoring", diff --git a/install/manage.mjs b/install/manage.mjs index a4fc4ad..5bfd4ff 100755 --- a/install/manage.mjs +++ b/install/manage.mjs @@ -30,7 +30,7 @@ function usage(stream = console.error) { stream(""); stream("Options:"); stream(" --target=<name> Pick install target (default: codex). Available: codex, claude."); - stream(" --with-optional Include skills marked optional (e.g. visual-planning)."); + stream(" --with-optional Include any skills marked optional in the manifest."); stream(" --session=<id> With doctor: pretty-print session state (hook invocations, tier history) for the given session id."); stream(" --no-migrate With install: refuse to silently migrate from an older install-state version (exit code 2)."); stream(""); diff --git a/manifest.json b/manifest.json index f12e8fc..f801f09 100644 --- a/manifest.json +++ b/manifest.json @@ -367,6 +367,22 @@ "3d78d21c9cf63494773970273e750a7893d8dafc78992ce8a02bb01a417dd276" ], "reason": "folded into do-it-grill as the Grill Log Artifact section" + }, + { + "name": "do-it-domain-language", + "target": "skills/do-it-domain-language", + "legacyHashes": [ + "794f2d0cce1e77276a3840d12d673e9cc2859f7a3bc57df5dba435ac0717965b" + ], + "reason": "folded into do-it-context as Domain Glossary Mode" + }, + { + "name": "do-it-visual-planning", + "target": "skills/do-it-visual-planning", + "legacyHashes": [ + "d9a5232ded1eb64340d1698cce5e55b6e6c0a93046ce0f77458df0f8faa0936a" + ], + "reason": "auxiliary skill folded into do-it-planning as the Visual Aids section; browser companion retired" } ], "skills": [ @@ -424,12 +440,6 @@ "target": "skills/do-it-interface-drill", "origin": "do-it" }, - { - "name": "do-it-domain-language", - "source": "skills/do-it/do-it-domain-language", - "target": "skills/do-it-domain-language", - "origin": "do-it" - }, { "name": "do-it-tdd", "source": "skills/do-it/do-it-tdd", @@ -478,13 +488,6 @@ "target": "skills/do-it-branch-closeout", "origin": "do-it" }, - { - "name": "do-it-visual-planning", - "source": "skills/do-it/do-it-visual-planning", - "target": "skills/do-it-visual-planning", - "origin": "do-it", - "optional": true - }, { "name": "do-it-skill-authoring", "source": "skills/do-it/do-it-skill-authoring", diff --git a/plugins/do-it/skills/_index.md b/plugins/do-it/skills/_index.md index 4e49e42..f4af020 100644 --- a/plugins/do-it/skills/_index.md +++ b/plugins/do-it/skills/_index.md @@ -26,7 +26,6 @@ router 推荐按需加载:用 Skill 工具 + skill 名加载详情;不要一 - **do-it-interface-drill** — API, schema, CLI, or protocol changes must be checked across producer and cons… - **do-it-debugging** — a bug's root cause is unclear or prior fixes failed and you need a hypothesis,… - **do-it-slicing** — a large plan needs independent vertical slices with explicit ownership, verifi… -- **do-it-domain-language** — user language, docs, and code naming disagree and a canonical domain glossary… - **do-it-comments-discipline** — code comments are authored or reviewed and must be checked as anchors, invaria… - **do-it-worktree-isolation** — risky, long, or parallel work needs an isolated git worktree to protect the ma… - **do-it-branch-closeout** — closing a branch, PR, merge, or cleanup and you must name scope, verification… @@ -35,9 +34,5 @@ router 推荐按需加载:用 Skill 工具 + skill 名加载详情;不要一 ## Handbook & 维护 - **do-it-handbook** — a project needs a durable `.do-it/handbook/` skeleton for architecture, invari… -- **do-it-context** — repo terms or invariants are drifting and `.do-it/CONTEXT.md` should become th… +- **do-it-context** — repo terms or invariants are drifting, or when user/docs/code naming disagrees… - **do-it-skill-authoring** — creating or updating do-it skills and you need clear triggers, return shape, w… - -## 其他 (manifest 已声明但未分组) - -- **do-it-visual-planning** — a plan or design decision would benefit from a small diagram, sketch, mockup,… diff --git a/plugins/do-it/skills/do-it-context/SKILL.md b/plugins/do-it/skills/do-it-context/SKILL.md index d1f6f06..c3010a4 100644 --- a/plugins/do-it/skills/do-it-context/SKILL.md +++ b/plugins/do-it/skills/do-it-context/SKILL.md @@ -1,13 +1,13 @@ --- name: do-it-context -description: "Use when repo terms or invariants are drifting and `.do-it/CONTEXT.md` should become the downstream source of truth for names, relationships, and facts." +description: "Use when repo terms or invariants are drifting, or when user/docs/code naming disagrees and a canonical glossary is needed — `.do-it/CONTEXT.md` is the downstream source of truth for names, relationships, and facts." --- # Do-It Context ## Purpose -`.do-it/CONTEXT.md` is the single canonical place where this project's terminology, invariants, and relationship-shapes live for AI workflows. Other skills (especially `do-it-grill`, `do-it-planning`, `do-it-review-loop`, `do-it-domain-language`) read it before debating definitions. +`.do-it/CONTEXT.md` is the single canonical place where this project's terminology, invariants, and relationship-shapes live for AI workflows. Other skills (especially `do-it-grill`, `do-it-planning`, `do-it-review-loop`) read it before debating definitions. This skill also owns the deeper domain-language pass (canonical glossary + contradiction checks) — see § Domain Glossary Mode. It is **not** a wiki, README replacement, or onboarding doc. It is a terse, declarative artifact intended to fit in the AI's working memory budget. Keep it under ~200 lines. @@ -87,6 +87,44 @@ Roughly quarterly, or when the file crosses ~200 lines: 2. Find lines that no longer match the code; rewrite or delete. 3. Find lines that have moved into the type system / schema and can now be deleted. +## Domain Glossary Mode (Standard+) + +The sediment workflow above is the Light path — one line per clarified term. For +non-trivial naming or modeling work (a new public API, schema, data model, phase +plan, or widespread terminology drift), do the deeper pass: build an explicit +canonical language map before names harden into code, docs, schemas, UI labels, +or handoffs. + +Sequence: + +1. Collect terms from the user request, docs, code, tests, schemas, logs, and UI copy. +2. Group synonyms, aliases, abbreviations, and deprecated terms. +3. Identify contradictions between code, docs, user language, and runtime behavior. +4. Define canonical terms from domain meaning, not implementation convenience. +5. Name domain entities, actions, states, invariants, and forbidden states. +6. Recommend what must change now and what can wait; feed interface/architecture + implications into the relevant do-it skill. + +Glossary shape: + +| Term | Definition | Source evidence | Aliases | Status | +| --- | --- | --- | --- | --- | +| canonical-term | ... | file/docs/user | old-term | canonical | + +Status values: `canonical` (use in new code/docs), `alias` (acceptable for +compatibility), `deprecated` (avoid in new work, migrate when touched), +`conflict` (sources disagree and need a decision). + +Contradiction checks — look for: a user term and a code term that mean different +things; docs describing a concept code models differently; a UI label hiding a +backend state distinction; schema names encoding transport detail instead of +domain meaning; tests using legacy terms; agents or task cards using different +names for the same ownership boundary. + +Stable canonical terms graduate into `glossary.md` via the three-session +promotion rule (see `do-it-handbook`). Do not rename code broadly when a glossary +is enough for the current task. + ## Stop Conditions Do not update CONTEXT.md when: @@ -130,4 +168,3 @@ Before relying on or updating CONTEXT.md: - `do-it-grill` — primary writer of new entries. - `do-it-planning` — reads CONTEXT.md before drafting plan cards. - `do-it-review-loop` — checks CONTEXT.md for contract terms before reviewing. -- `do-it-domain-language` — for the deeper "is this a coherent domain language" question. diff --git a/plugins/do-it/skills/do-it-domain-language/SKILL.md b/plugins/do-it/skills/do-it-domain-language/SKILL.md deleted file mode 100644 index 71b8160..0000000 --- a/plugins/do-it/skills/do-it-domain-language/SKILL.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -name: do-it-domain-language -description: "Use when user language, docs, and code naming disagree and a canonical domain glossary or handoff vocabulary is needed." ---- - -# Do-It Domain Language - -## Purpose - -Use this to make domain terms explicit before names become code, docs, schemas, UI labels, or agent handoffs. The output is a small canonical language map with contradictions and proposed resolutions. - -## Tier Rules - -### Light - -Use for a local naming decision. Inspect nearby code and docs, pick the least surprising term, and note aliases if needed. - -### Standard - -Default for subagents and non-trivial naming or model work. Build a glossary from user language, docs, code, tests, schemas, and UI text. - -### Heavy - -Parent-only unless explicitly assigned. Use for phase plans, data models, public APIs, workflow policy, migrations, or widespread terminology drift. - -## Sequence - -1. Collect terms from the user request, docs, code, tests, schemas, logs, and UI copy. -2. Group synonyms, aliases, abbreviations, and deprecated terms. -3. Identify contradictions between code, docs, user language, and runtime behavior. -4. Define canonical terms using domain meaning, not implementation convenience. -5. Name domain entities, actions, states, invariants, and forbidden states. -6. Recommend where terminology must change now and what can wait. -7. Feed interface or architecture implications into the relevant do-it skill. - -## Glossary Shape - -| Term | Definition | Source evidence | Aliases | Status | -| --- | --- | --- | --- | --- | -| canonical-term | ... | file/docs/user | old-term | canonical | - -Status values: - -- `canonical`: use in new code/docs. -- `alias`: acceptable when preserving compatibility. -- `deprecated`: avoid in new work, migrate when touched. -- `conflict`: current sources disagree and need a decision. - -## Contradiction Checks - -Look for: - -- user term means one thing, code term means another; -- docs describe a concept that code models differently; -- UI label hides a backend state distinction; -- schema names encode transport detail instead of domain meaning; -- tests use legacy terms that make new behavior ambiguous; -- agents or task cards use different names for the same ownership boundary. - -## Output Shape - -- Scope scanned. -- Canonical glossary. -- Contradictions and proposed resolution. -- Domain entities, actions, states, and invariants. -- Required naming changes for current work. -- Deferred terminology cleanup, if any. -- Interface or architecture follow-ups. - -## Common Mistakes - -- Renaming code broadly when a glossary is enough for the current task. -- Picking names from implementation detail instead of domain meaning. -- Treating aliases as harmless when they create conflicting behavior. -- Ignoring docs or UI copy while changing API names. -- Letting a subagent redefine canonical language outside its assigned slice. diff --git a/plugins/do-it/skills/do-it-planning/SKILL.md b/plugins/do-it/skills/do-it-planning/SKILL.md index 7cebf26..65773e3 100644 --- a/plugins/do-it/skills/do-it-planning/SKILL.md +++ b/plugins/do-it/skills/do-it-planning/SKILL.md @@ -37,7 +37,7 @@ Parent-only unless explicitly assigned: - use for wave, phase, release, multi-agent, durable workflow, or cross-boundary planning; - lock scope, write ownership, non-goals, and integration ownership; -- run grill, interface, architecture, domain-language, or slicing drills as needed; +- run grill, interface, architecture, vocabulary (do-it-context), or slicing drills as needed; - stop for approval if the user asked to confirm the plan. ## Planning Sequence @@ -222,6 +222,16 @@ Include: Keep file paths and code snippets out of durable PRD prose unless the user asks for a code-facing plan; they go stale faster than domain decisions. +## Visual Aids (optional) + +When seeing an option is materially clearer than reading it — UI layout +alternatives, architecture/data-flow diagrams, before/after states, side-by-side +interface shapes — sketch it under `.do-it/visual/<topic>/` (descriptive +filenames like `option-a-flow.md`, `api-boundary.svg`). Treat these as auxiliary +evidence, not durable plan output: the decision still lands in the plan card. +Skip visuals for text-only decisions, one-line questions, or where a table is +clearer. A visual aid never promotes a task's tier by itself. + ## Output Shape - Tier and task class. diff --git a/plugins/do-it/skills/do-it-router/SKILL.md b/plugins/do-it/skills/do-it-router/SKILL.md index 1a6a7e6..ccda0b4 100644 --- a/plugins/do-it/skills/do-it-router/SKILL.md +++ b/plugins/do-it/skills/do-it-router/SKILL.md @@ -227,9 +227,9 @@ review-clean. - Need to challenge a premise, plan, or closeout claim: `do-it-grill`. - Need to design an API, schema, event, CLI, UI contract, module seam, or handoff: `do-it-interface-drill`. - Need coupling, ownership, modularity, or testability analysis: `do-it-architecture-scan`. -- Need names, domain model, glossary, or code/docs/user terminology alignment: `do-it-domain-language`. +- Need names, domain model, glossary, or code/docs/user terminology alignment: `do-it-context` (§ Domain Glossary Mode). - Need a durable project handbook (invariants, architecture, code map, glossary, backlog): `do-it-handbook`. Suggest it when work spans many files or several sessions and `.do-it/handbook/` does not yet exist; downstream skills (`do-it-grill`, `do-it-planning`, `do-it-architecture-scan`) read those files when present. -- Need optional visual comparison or diagrams: `do-it-visual-planning`. This is auxiliary and does not participate in the core tier flow. +- Need optional visual comparison or diagrams: `do-it-planning` § Visual Aids. Auxiliary; does not participate in the core tier flow. - Need implementation: execute locally or delegate a bounded slice after the route is clear; add `do-it-tdd` or `do-it-debugging` when the behavior or root cause warrants it. - Need behavior-first implementation or regression coverage: `do-it-tdd`. - Need root-cause diagnosis before fixing: `do-it-debugging`. @@ -242,7 +242,7 @@ review-clean. - Need to create or rewrite skills: `do-it-skill-authoring`. - Authoring or reviewing comments on a code edit: `do-it-comments-discipline`. The parent agent should apply it before writing comments; the PostToolUse `comments-lint` hook is advisory backup, and a Standard or Heavy review pass that touches comments should load it for the comments lens. -Use the narrowest sequence that covers the risk. A small API rename may need only Standard interface drill plus delivery. A phase plan may need Heavy planning, slicing, grill, interface, architecture, and domain-language passes. +Use the narrowest sequence that covers the risk. A small API rename may need only Standard interface drill plus delivery. A phase plan may need Heavy planning, slicing, grill, interface, architecture, and vocabulary passes. ## Delegation Policy diff --git a/plugins/do-it/skills/do-it-visual-planning/SKILL.md b/plugins/do-it/skills/do-it-visual-planning/SKILL.md deleted file mode 100644 index 70b68f1..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/SKILL.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -name: do-it-visual-planning -description: "Use when a plan or design decision would benefit from a small diagram, sketch, mockup, or side-by-side visual artifact alongside text." ---- - -# Do-It Visual Planning - -## Purpose - -Use this as an auxiliary planning aid for visual comparison. It is not part of the core do-it tier flow and must not promote a task from Light to Standard or Heavy by itself. - -Use `.do-it/visual/` as the workspace for sketches, diagrams, screenshots, notes, or generated visual assets. Keep product code and non-visual docs out of this skill unless another do-it skill explicitly owns that edit. - -## Tier Rules - -### Light - -Use a quick sketch, ASCII diagram, or one comparison image to resolve a narrow ambiguity. - -### Standard - -Default for subagents and ordinary visual planning. Produce 2-3 options and compare tradeoffs. - -### Heavy - -Parent-only unless explicitly assigned. Use for cross-screen UI flows, architecture diagrams for wave/phase planning, or visual decisions that affect multiple workers. - -## When To Use - -Use when seeing the option is materially better than reading it: - -- UI layout or interaction alternatives; -- architecture or data-flow diagrams; -- before/after visual states; -- side-by-side interface shapes; -- visual task sequencing for multi-agent work. - -Skip it for text-only decisions, one-line questions, or plans where a table is clearer. - -## Workspace Rules - -- Store artifacts under `.do-it/visual/<topic>/`. -- Use descriptive filenames like `option-a-flow.md`, `api-boundary.svg`, or `screen-compare.png`. -- Treat the workspace as auxiliary evidence, not final product output. -- Do not edit manifest, install scripts, package files, or unrelated docs from this skill. -- If generated artifacts are temporary, say so in closeout. -- For browser-based comparisons, use `scripts/start-server.sh` and - `references/visual-companion.md`. Load that reference only when you actually - need the local browser companion. -- Browser session HTML must be written to the `screen_dir` returned by the - companion server. Use `.do-it/visual/<topic>/` for static artifacts, notes, - screenshots, or generated assets outside the live browser session. - -## Scenario Templates - -`templates/` ships ready-made content fragments for two recurring artifacts: - -- `templates/plan-card.html` — a plan / task card (goal, scope, acceptance criteria, verification, risks); section order matches the task-card layout in `do-it-planning` so a visual card and a written card stay consistent. -- `templates/review-report.html` — review findings grouped by Blocking / Important / Opportunity with evidence. - -To use one: copy the fragment into the companion `screen_dir`, fill its `slot:` placeholders, and drop unused sections. The server wraps the fragment in `frame-template.html`, which already carries all CSS — the fragment stays small because only the content varies, and a consistent skeleton means the layout is not re-derived each time. - -These templates render the *same* content a text plan or review carries. Reach for them only when a user benefits from seeing the artifact in the browser companion; they do not replace the durable `.do-it/plans/` or `.do-it/review/` markdown that other skills own. - -## Sequence - -1. Inspect the current design context or code surface. -2. Decide whether visual treatment will reduce ambiguity. -3. Create or update the smallest useful artifact in `.do-it/visual/`, or in the - returned `screen_dir` when using the browser companion. -4. Compare options with explicit tradeoffs and a recommendation. -5. Feed the decision back into `do-it-planning`, `do-it-interface-drill`, or `do-it-architecture-scan`. - -## Output Shape - -- Visual workspace path. -- Options or diagram created. -- Decision clarified. -- Recommendation. -- Follow-up do-it skill or delivery step. - -## Common Mistakes - -- Making visuals because they look nice, not because they clarify a decision. -- Letting visual planning replace acceptance criteria or verification. -- Mixing temporary sketches into product docs. -- Treating this auxiliary skill as a required gate in the core do-it flow. diff --git a/plugins/do-it/skills/do-it-visual-planning/references/visual-companion.md b/plugins/do-it/skills/do-it-visual-planning/references/visual-companion.md deleted file mode 100644 index 393118e..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/references/visual-companion.md +++ /dev/null @@ -1,267 +0,0 @@ -# Visual Companion Guide - -Browser-based do-it visual planning companion for showing mockups, diagrams, and options. - -## When to Use - -Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?** - -**Use the browser** when the content itself is visual: - -- **UI mockups** — wireframes, layouts, navigation structures, component designs -- **Architecture diagrams** — system components, data flow, relationship maps -- **Side-by-side visual comparisons** — comparing two layouts, two color schemes, two design directions -- **Design polish** — when the question is about look and feel, spacing, visual hierarchy -- **Spatial relationships** — state machines, flowcharts, entity relationships rendered as diagrams - -**Use the terminal** when the content is text or tabular: - -- **Requirements and scope questions** — "what does X mean?", "which features are in scope?" -- **Conceptual A/B/C choices** — picking between approaches described in words -- **Tradeoff lists** — pros/cons, comparison tables -- **Technical decisions** — API design, data modeling, architectural approach selection -- **Clarifying questions** — anything where the answer is words, not a visual preference - -A question *about* a UI topic is not automatically a visual question. "What kind of wizard do you want?" is conceptual — use the terminal. "Which of these wizard layouts feels right?" is visual — use the browser. - -## How It Works - -The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to `screen_dir`, the user sees it in their browser and can click to select options. Selections are recorded to `state_dir/events` that you read on your next turn. - -**Content fragments vs full documents:** If your HTML file starts with `<!DOCTYPE` or `<html`, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, selection indicator, and all interactive infrastructure. **Write content fragments by default.** Only write full documents when you need complete control over the page. - -## Starting a Session - -```bash -# Start server with persistence (mockups saved to project) -scripts/start-server.sh --project-dir /path/to/project - -# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341", -# "screen_dir":"/path/to/project/.do-it/visual/12345-1706000000/content", -# "state_dir":"/path/to/project/.do-it/visual/12345-1706000000/state"} -``` - -Save `screen_dir` and `state_dir` from the response. Tell user to open the URL. - -**Finding connection info:** The server writes its startup JSON to `$STATE_DIR/server-info`. If you launched the server in the background and didn't capture stdout, read that file to get the URL and port. When using `--project-dir`, check `<project>/.do-it/visual/` for the session directory. - -**Note:** Pass the project root as `--project-dir` so mockups persist in `.do-it/visual/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. The do-it repository ignores `.do-it/`; downstream projects should do the same before using persistent visual sessions. - -**Launching the server:** - -```bash -# Codex-first default. The script auto-detects CODEX_CI and switches to -# foreground mode when the environment would reap detached processes. -scripts/start-server.sh --project-dir /path/to/project -``` - -Other runtimes must keep the server alive across turns. If the environment -reaps detached processes, use `--foreground` and launch the command with that -runtime's background execution mechanism. - -If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host: - -```bash -scripts/start-server.sh \ - --project-dir /path/to/project \ - --host 0.0.0.0 \ - --url-host localhost -``` - -Use `--url-host` to control what hostname is printed in the returned URL JSON. - -## The Loop - -1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`: - - Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity. - - Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html` - - **Never reuse filenames** — each screen gets a fresh file - - Use the normal file-editing tool; avoid cat/heredoc writes that dump noisy - HTML into terminal output. - - Server automatically serves the newest file - -2. **Tell user what to expect and end your turn:** - - Remind them of the URL (every step, not just first) - - Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage") - - Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like." - -3. **On your next turn** — after the user responds in the terminal: - - Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines - - Merge with the user's terminal text to get the full picture - - The terminal message is the primary feedback; `state_dir/events` provides structured interaction data - -4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated. - -5. **Unload when returning to terminal** — when the next step doesn't need the browser (e.g., a clarifying question, a tradeoff discussion), push a waiting screen to clear the stale content: - - ```html - <!-- filename: waiting.html (or waiting-2.html, etc.) --> - <div style="display:flex;align-items:center;justify-content:center;min-height:60vh"> - <p class="subtitle">Continuing in terminal...</p> - </div> - ``` - - This prevents the user from staring at a resolved choice while the conversation has moved on. When the next visual question comes up, push a new content file as usual. - -6. Repeat until done. - -## Writing Content Fragments - -Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure). - -**Minimal example:** - -```html -<h2>Which layout works better?</h2> -<p class="subtitle">Consider readability and visual hierarchy</p> - -<div class="options"> - <div class="option" data-choice="a" onclick="toggleSelect(this)"> - <div class="letter">A</div> - <div class="content"> - <h3>Single Column</h3> - <p>Clean, focused reading experience</p> - </div> - </div> - <div class="option" data-choice="b" onclick="toggleSelect(this)"> - <div class="letter">B</div> - <div class="content"> - <h3>Two Column</h3> - <p>Sidebar navigation with main content</p> - </div> - </div> -</div> -``` - -That's it. No `<html>`, no CSS, no `<script>` tags needed. The server provides all of that. - -## CSS Classes Available - -The frame template provides these CSS classes for your content: - -### Options (A/B/C choices) - -```html -<div class="options"> - <div class="option" data-choice="a" onclick="toggleSelect(this)"> - <div class="letter">A</div> - <div class="content"> - <h3>Title</h3> - <p>Description</p> - </div> - </div> -</div> -``` - -**Multi-select:** Add `data-multiselect` to the container to let users select multiple options. Each click toggles the item. The indicator bar shows the count. - -```html -<div class="options" data-multiselect> - <!-- same option markup — users can select/deselect multiple --> -</div> -``` - -### Cards (visual designs) - -```html -<div class="cards"> - <div class="card" data-choice="design1" onclick="toggleSelect(this)"> - <div class="card-image"><!-- mockup content --></div> - <div class="card-body"> - <h3>Name</h3> - <p>Description</p> - </div> - </div> -</div> -``` - -### Mockup container - -```html -<div class="mockup"> - <div class="mockup-header">Preview: Dashboard Layout</div> - <div class="mockup-body"><!-- your mockup HTML --></div> -</div> -``` - -### Split view (side-by-side) - -```html -<div class="split"> - <div class="mockup"><!-- left --></div> - <div class="mockup"><!-- right --></div> -</div> -``` - -### Pros/Cons - -```html -<div class="pros-cons"> - <div class="pros"><h4>Pros</h4><ul><li>Benefit</li></ul></div> - <div class="cons"><h4>Cons</h4><ul><li>Drawback</li></ul></div> -</div> -``` - -### Mock elements (wireframe building blocks) - -```html -<div class="mock-nav">Logo | Home | About | Contact</div> -<div style="display: flex;"> - <div class="mock-sidebar">Navigation</div> - <div class="mock-content">Main content area</div> -</div> -<button class="mock-button">Action Button</button> -<input class="mock-input" placeholder="Input field"> -<div class="placeholder">Placeholder area</div> -``` - -### Typography and sections - -- `h2` — page title -- `h3` — section heading -- `.subtitle` — secondary text below title -- `.section` — content block with bottom margin -- `.label` — small uppercase label text - -## Browser Events Format - -When the user clicks options in the browser, their interactions are recorded to `$STATE_DIR/events` (one JSON object per line). The file is cleared automatically when you push a new screen. - -```jsonl -{"type":"click","choice":"a","text":"Option A - Simple Layout","timestamp":1706000101} -{"type":"click","choice":"c","text":"Option C - Complex Grid","timestamp":1706000108} -{"type":"click","choice":"b","text":"Option B - Hybrid","timestamp":1706000115} -``` - -The full event stream shows the user's exploration path — they may click multiple options before settling. The last `choice` event is typically the final selection, but the pattern of clicks can reveal hesitation or preferences worth asking about. - -If `$STATE_DIR/events` doesn't exist, the user didn't interact with the browser — use only their terminal text. - -## Design Tips - -- **Scale fidelity to the question** — wireframes for layout, polish for polish questions -- **Explain the question on each page** — "Which layout feels more professional?" not just "Pick one" -- **Iterate before advancing** — if feedback changes current screen, write a new version -- **2-4 options max** per screen -- **Use real content when it matters** — for a photography portfolio, use actual images (Unsplash). Placeholder content obscures design issues. -- **Keep mockups simple** — focus on layout and structure, not pixel-perfect design - -## File Naming - -- Use semantic names: `platform.html`, `visual-style.html`, `layout.html` -- Never reuse filenames — each screen must be a new file -- For iterations: append version suffix like `layout-v2.html`, `layout-v3.html` -- Server serves newest file by modification time - -## Cleaning Up - -```bash -scripts/stop-server.sh $SESSION_DIR -``` - -If the session used `--project-dir`, mockup files persist in `.do-it/visual/` for later reference. Only `/tmp` sessions get deleted on stop. - -## Reference - -- Frame template (CSS reference): `scripts/frame-template.html` -- Helper script (client-side): `scripts/helper.js` diff --git a/plugins/do-it/skills/do-it-visual-planning/scripts/frame-template.html b/plugins/do-it/skills/do-it-visual-planning/scripts/frame-template.html deleted file mode 100644 index 0860f70..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/scripts/frame-template.html +++ /dev/null @@ -1,534 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>do-it Visual Planning - - - - - - -
-

- - - do-it - Visual Planning - -

-
Connected
-
- -
-
- -
-
- -
- Click an option above, then return to the terminal -
- - - diff --git a/plugins/do-it/skills/do-it-visual-planning/scripts/helper.js b/plugins/do-it/skills/do-it-visual-planning/scripts/helper.js deleted file mode 100644 index 23ba0c7..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/scripts/helper.js +++ /dev/null @@ -1,98 +0,0 @@ -(function() { - const WS_URL = 'ws://' + window.location.host; - let ws = null; - let eventQueue = []; - - function connect() { - ws = new WebSocket(WS_URL); - - ws.onopen = () => { - eventQueue.forEach(e => ws.send(JSON.stringify(e))); - eventQueue = []; - }; - - ws.onmessage = (msg) => { - const data = JSON.parse(msg.data); - if (data.type === 'reload') { - window.location.reload(); - } - }; - - ws.onclose = () => { - setTimeout(connect, 1000); - }; - } - - function sendEvent(event) { - event.timestamp = Date.now(); - if (ws && ws.readyState === WebSocket.OPEN) { - ws.send(JSON.stringify(event)); - } else { - eventQueue.push(event); - } - } - - function setSelectedIndicator(indicator, value) { - const selectedText = document.createElement('span'); - selectedText.className = 'selected-text'; - selectedText.textContent = value + ' selected'; - - indicator.textContent = ''; - indicator.appendChild(selectedText); - indicator.appendChild(document.createTextNode(' - return to terminal to continue')); - } - - // Capture clicks on choice elements - document.addEventListener('click', (e) => { - const target = e.target.closest('[data-choice]'); - if (!target) return; - - sendEvent({ - type: 'click', - text: target.textContent.trim(), - choice: target.dataset.choice, - id: target.id || null - }); - - // Update indicator bar (defer so toggleSelect runs first) - setTimeout(() => { - const indicator = document.getElementById('indicator-text'); - if (!indicator) return; - const container = target.closest('.options') || target.closest('.cards'); - const selected = container ? container.querySelectorAll('.selected') : []; - if (selected.length === 0) { - indicator.textContent = 'Click an option above, then return to the terminal'; - } else if (selected.length === 1) { - const label = selected[0].querySelector('h3, .content h3, .card-body h3')?.textContent?.trim() || selected[0].dataset.choice || ''; - setSelectedIndicator(indicator, label); - } else { - setSelectedIndicator(indicator, selected.length); - } - }, 0); - }); - - // Frame UI: selection tracking - window.selectedChoice = null; - - window.toggleSelect = function(el) { - const container = el.closest('.options') || el.closest('.cards'); - const multi = container && container.dataset.multiselect !== undefined; - if (container && !multi) { - container.querySelectorAll('.option, .card').forEach(o => o.classList.remove('selected')); - } - if (multi) { - el.classList.toggle('selected'); - } else { - el.classList.add('selected'); - } - window.selectedChoice = el.dataset.choice; - }; - - // Expose API for explicit use - window.doItVisual = { - send: sendEvent, - choice: (value, metadata = {}) => sendEvent({ type: 'choice', value, ...metadata }) - }; - - connect(); -})(); diff --git a/plugins/do-it/skills/do-it-visual-planning/scripts/server.cjs b/plugins/do-it/skills/do-it-visual-planning/scripts/server.cjs deleted file mode 100644 index 2f91d1d..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/scripts/server.cjs +++ /dev/null @@ -1,354 +0,0 @@ -const crypto = require('crypto'); -const http = require('http'); -const fs = require('fs'); -const path = require('path'); - -// ========== WebSocket Protocol (RFC 6455) ========== - -const OPCODES = { TEXT: 0x01, CLOSE: 0x08, PING: 0x09, PONG: 0x0A }; -const WS_MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'; - -function computeAcceptKey(clientKey) { - return crypto.createHash('sha1').update(clientKey + WS_MAGIC).digest('base64'); -} - -function encodeFrame(opcode, payload) { - const fin = 0x80; - const len = payload.length; - let header; - - if (len < 126) { - header = Buffer.alloc(2); - header[0] = fin | opcode; - header[1] = len; - } else if (len < 65536) { - header = Buffer.alloc(4); - header[0] = fin | opcode; - header[1] = 126; - header.writeUInt16BE(len, 2); - } else { - header = Buffer.alloc(10); - header[0] = fin | opcode; - header[1] = 127; - header.writeBigUInt64BE(BigInt(len), 2); - } - - return Buffer.concat([header, payload]); -} - -function decodeFrame(buffer) { - if (buffer.length < 2) return null; - - const secondByte = buffer[1]; - const opcode = buffer[0] & 0x0F; - const masked = (secondByte & 0x80) !== 0; - let payloadLen = secondByte & 0x7F; - let offset = 2; - - if (!masked) throw new Error('Client frames must be masked'); - - if (payloadLen === 126) { - if (buffer.length < 4) return null; - payloadLen = buffer.readUInt16BE(2); - offset = 4; - } else if (payloadLen === 127) { - if (buffer.length < 10) return null; - payloadLen = Number(buffer.readBigUInt64BE(2)); - offset = 10; - } - - const maskOffset = offset; - const dataOffset = offset + 4; - const totalLen = dataOffset + payloadLen; - if (buffer.length < totalLen) return null; - - const mask = buffer.slice(maskOffset, dataOffset); - const data = Buffer.alloc(payloadLen); - for (let i = 0; i < payloadLen; i++) { - data[i] = buffer[dataOffset + i] ^ mask[i % 4]; - } - - return { opcode, payload: data, bytesConsumed: totalLen }; -} - -// ========== Configuration ========== - -const PORT = process.env.DO_IT_VISUAL_PORT || (49152 + Math.floor(Math.random() * 16383)); -const HOST = process.env.DO_IT_VISUAL_HOST || '127.0.0.1'; -const URL_HOST = process.env.DO_IT_VISUAL_URL_HOST || (HOST === '127.0.0.1' ? 'localhost' : HOST); -const SESSION_DIR = process.env.DO_IT_VISUAL_DIR || '/tmp/do-it-visual'; -const CONTENT_DIR = path.join(SESSION_DIR, 'content'); -const STATE_DIR = path.join(SESSION_DIR, 'state'); -let ownerPid = process.env.DO_IT_VISUAL_OWNER_PID ? Number(process.env.DO_IT_VISUAL_OWNER_PID) : null; - -const MIME_TYPES = { - '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript', - '.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg', - '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml' -}; - -// ========== Templates and Constants ========== - -const WAITING_PAGE = ` - -do-it Visual Planning - - -

do-it Visual Planning

-

Waiting for the agent to push a screen...

`; - -const frameTemplate = fs.readFileSync(path.join(__dirname, 'frame-template.html'), 'utf-8'); -const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8'); -const helperInjection = ''; - -// ========== Helper Functions ========== - -function isFullDocument(html) { - const trimmed = html.trimStart().toLowerCase(); - return trimmed.startsWith('', content); -} - -function getNewestScreen() { - const files = fs.readdirSync(CONTENT_DIR) - .filter(f => f.endsWith('.html')) - .map(f => { - const fp = path.join(CONTENT_DIR, f); - return { path: fp, mtime: fs.statSync(fp).mtime.getTime() }; - }) - .sort((a, b) => b.mtime - a.mtime); - return files.length > 0 ? files[0].path : null; -} - -// ========== HTTP Request Handler ========== - -function handleRequest(req, res) { - touchActivity(); - if (req.method === 'GET' && req.url === '/') { - const screenFile = getNewestScreen(); - let html = screenFile - ? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8')) - : WAITING_PAGE; - - if (html.includes('')) { - html = html.replace('', helperInjection + '\n'); - } else { - html += helperInjection; - } - - res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); - res.end(html); - } else if (req.method === 'GET' && req.url.startsWith('/files/')) { - const fileName = req.url.slice(7); - const filePath = path.join(CONTENT_DIR, path.basename(fileName)); - if (!fs.existsSync(filePath)) { - res.writeHead(404); - res.end('Not found'); - return; - } - const ext = path.extname(filePath).toLowerCase(); - const contentType = MIME_TYPES[ext] || 'application/octet-stream'; - res.writeHead(200, { 'Content-Type': contentType }); - res.end(fs.readFileSync(filePath)); - } else { - res.writeHead(404); - res.end('Not found'); - } -} - -// ========== WebSocket Connection Handling ========== - -const clients = new Set(); - -function handleUpgrade(req, socket) { - const key = req.headers['sec-websocket-key']; - if (!key) { socket.destroy(); return; } - - const accept = computeAcceptKey(key); - socket.write( - 'HTTP/1.1 101 Switching Protocols\r\n' + - 'Upgrade: websocket\r\n' + - 'Connection: Upgrade\r\n' + - 'Sec-WebSocket-Accept: ' + accept + '\r\n\r\n' - ); - - let buffer = Buffer.alloc(0); - clients.add(socket); - - socket.on('data', (chunk) => { - buffer = Buffer.concat([buffer, chunk]); - while (buffer.length > 0) { - let result; - try { - result = decodeFrame(buffer); - } catch (e) { - socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); - clients.delete(socket); - return; - } - if (!result) break; - buffer = buffer.slice(result.bytesConsumed); - - switch (result.opcode) { - case OPCODES.TEXT: - handleMessage(result.payload.toString()); - break; - case OPCODES.CLOSE: - socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); - clients.delete(socket); - return; - case OPCODES.PING: - socket.write(encodeFrame(OPCODES.PONG, result.payload)); - break; - case OPCODES.PONG: - break; - default: { - const closeBuf = Buffer.alloc(2); - closeBuf.writeUInt16BE(1003); - socket.end(encodeFrame(OPCODES.CLOSE, closeBuf)); - clients.delete(socket); - return; - } - } - } - }); - - socket.on('close', () => clients.delete(socket)); - socket.on('error', () => clients.delete(socket)); -} - -function handleMessage(text) { - let event; - try { - event = JSON.parse(text); - } catch (e) { - console.error('Failed to parse WebSocket message:', e.message); - return; - } - touchActivity(); - console.log(JSON.stringify({ source: 'user-event', ...event })); - if (event.choice) { - const eventsFile = path.join(STATE_DIR, 'events'); - fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n'); - } -} - -function broadcast(msg) { - const frame = encodeFrame(OPCODES.TEXT, Buffer.from(JSON.stringify(msg))); - for (const socket of clients) { - try { socket.write(frame); } catch (e) { clients.delete(socket); } - } -} - -// ========== Activity Tracking ========== - -const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes -let lastActivity = Date.now(); - -function touchActivity() { - lastActivity = Date.now(); -} - -// ========== File Watching ========== - -const debounceTimers = new Map(); - -// ========== Server Startup ========== - -function startServer() { - if (!fs.existsSync(CONTENT_DIR)) fs.mkdirSync(CONTENT_DIR, { recursive: true }); - if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true }); - - // Track known files to distinguish new screens from updates. - // macOS fs.watch reports 'rename' for both new files and overwrites, - // so we can't rely on eventType alone. - const knownFiles = new Set( - fs.readdirSync(CONTENT_DIR).filter(f => f.endsWith('.html')) - ); - - const server = http.createServer(handleRequest); - server.on('upgrade', handleUpgrade); - - const watcher = fs.watch(CONTENT_DIR, (eventType, filename) => { - if (!filename || !filename.endsWith('.html')) return; - - if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename)); - debounceTimers.set(filename, setTimeout(() => { - debounceTimers.delete(filename); - const filePath = path.join(CONTENT_DIR, filename); - - if (!fs.existsSync(filePath)) return; // file was deleted - touchActivity(); - - if (!knownFiles.has(filename)) { - knownFiles.add(filename); - const eventsFile = path.join(STATE_DIR, 'events'); - if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); - console.log(JSON.stringify({ type: 'screen-added', file: filePath })); - } else { - console.log(JSON.stringify({ type: 'screen-updated', file: filePath })); - } - - broadcast({ type: 'reload' }); - }, 100)); - }); - watcher.on('error', (err) => console.error('fs.watch error:', err.message)); - - function shutdown(reason) { - console.log(JSON.stringify({ type: 'server-stopped', reason })); - const infoFile = path.join(STATE_DIR, 'server-info'); - if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile); - fs.writeFileSync( - path.join(STATE_DIR, 'server-stopped'), - JSON.stringify({ reason, timestamp: Date.now() }) + '\n' - ); - watcher.close(); - clearInterval(lifecycleCheck); - server.close(() => process.exit(0)); - } - - function ownerAlive() { - if (!ownerPid) return true; - try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; } - } - - // Check every 60s: exit if owner process died or idle for 30 minutes - const lifecycleCheck = setInterval(() => { - if (!ownerAlive()) shutdown('owner process exited'); - else if (Date.now() - lastActivity > IDLE_TIMEOUT_MS) shutdown('idle timeout'); - }, 60 * 1000); - lifecycleCheck.unref(); - - // Validate owner PID at startup. If it's already dead, the PID resolution - // was wrong (common on WSL, Tailscale SSH, and cross-user scenarios). - // Disable monitoring and rely on the idle timeout instead. - if (ownerPid) { - try { process.kill(ownerPid, 0); } - catch (e) { - if (e.code !== 'EPERM') { - console.log(JSON.stringify({ type: 'owner-pid-invalid', pid: ownerPid, reason: 'dead at startup' })); - ownerPid = null; - } - } - } - - server.listen(PORT, HOST, () => { - const info = JSON.stringify({ - type: 'server-started', port: Number(PORT), host: HOST, - url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT, - screen_dir: CONTENT_DIR, state_dir: STATE_DIR - }); - console.log(info); - fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n'); - }); -} - -if (require.main === module) { - startServer(); -} - -module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES }; diff --git a/plugins/do-it/skills/do-it-visual-planning/scripts/start-server.sh b/plugins/do-it/skills/do-it-visual-planning/scripts/start-server.sh deleted file mode 100755 index 55b89ae..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/scripts/start-server.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env bash -# Start the do-it visual server and output connection info -# Usage: start-server.sh [--project-dir ] [--host ] [--url-host ] [--foreground] [--background] -# -# Starts server on a random high port, outputs JSON with URL. -# Each session gets its own directory to avoid conflicts. -# -# Options: -# --project-dir Store session files under /.do-it/visual/ -# instead of /tmp. Files persist after server stops. -# --host Host/interface to bind (default: 127.0.0.1). -# Use 0.0.0.0 in remote/containerized environments. -# --url-host Hostname shown in returned URL JSON. -# --foreground Run server in the current terminal (no backgrounding). -# --background Force background mode (overrides Codex auto-foreground). - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -# Parse arguments -PROJECT_DIR="" -FOREGROUND="false" -FORCE_BACKGROUND="false" -BIND_HOST="127.0.0.1" -URL_HOST="" -while [[ $# -gt 0 ]]; do - case "$1" in - --project-dir) - PROJECT_DIR="$2" - shift 2 - ;; - --host) - BIND_HOST="$2" - shift 2 - ;; - --url-host) - URL_HOST="$2" - shift 2 - ;; - --foreground|--no-daemon) - FOREGROUND="true" - shift - ;; - --background|--daemon) - FORCE_BACKGROUND="true" - shift - ;; - *) - echo "{\"error\": \"Unknown argument: $1\"}" - exit 1 - ;; - esac -done - -if [[ -z "$URL_HOST" ]]; then - if [[ "$BIND_HOST" == "127.0.0.1" || "$BIND_HOST" == "localhost" ]]; then - URL_HOST="localhost" - else - URL_HOST="$BIND_HOST" - fi -fi - -# Some environments reap detached/background processes. Auto-foreground when detected. -if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then - FOREGROUND="true" -fi - -# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected. -if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then - case "${OSTYPE:-}" in - msys*|cygwin*|mingw*) FOREGROUND="true" ;; - esac - if [[ -n "${MSYSTEM:-}" ]]; then - FOREGROUND="true" - fi -fi - -# Generate unique session directory -SESSION_ID="$$-$(date +%s)" - -if [[ -n "$PROJECT_DIR" ]]; then - SESSION_DIR="${PROJECT_DIR}/.do-it/visual/${SESSION_ID}" -else - SESSION_DIR="/tmp/do-it-visual-${SESSION_ID}" -fi - -STATE_DIR="${SESSION_DIR}/state" -PID_FILE="${STATE_DIR}/server.pid" -LOG_FILE="${STATE_DIR}/server.log" - -# Create fresh session directory with content and state peers -mkdir -p "${SESSION_DIR}/content" "$STATE_DIR" - -# Kill any existing server -if [[ -f "$PID_FILE" ]]; then - old_pid=$(cat "$PID_FILE") - kill "$old_pid" 2>/dev/null - rm -f "$PID_FILE" -fi - -cd "$SCRIPT_DIR" - -# Resolve the harness PID (grandparent of this script). -# $PPID is the ephemeral shell the harness spawned to run us — it dies -# when this script exits. The harness itself is $PPID's parent. -OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ')" -if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then - OWNER_PID="$PPID" -fi - -# Foreground mode for environments that reap detached/background processes. -if [[ "$FOREGROUND" == "true" ]]; then - echo "$$" > "$PID_FILE" - env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs - exit $? -fi - -# Start server, capturing output to log file -# Use nohup to survive shell exit; disown to remove from job table -nohup env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 & -SERVER_PID=$! -disown "$SERVER_PID" 2>/dev/null -echo "$SERVER_PID" > "$PID_FILE" - -# Wait for server-started message (check log file) -for i in {1..50}; do - if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then - # Verify server is still alive after a short window (catches process reapers) - alive="true" - for _ in {1..20}; do - if ! kill -0 "$SERVER_PID" 2>/dev/null; then - alive="false" - break - fi - sleep 0.1 - done - if [[ "$alive" != "true" ]]; then - echo "{\"error\": \"Server started but was killed. Retry in a persistent terminal with: $SCRIPT_DIR/start-server.sh${PROJECT_DIR:+ --project-dir $PROJECT_DIR} --host $BIND_HOST --url-host $URL_HOST --foreground\"}" - exit 1 - fi - grep "server-started" "$LOG_FILE" | head -1 - exit 0 - fi - sleep 0.1 -done - -# Timeout - server didn't start -echo '{"error": "Server failed to start within 5 seconds"}' -exit 1 diff --git a/plugins/do-it/skills/do-it-visual-planning/scripts/stop-server.sh b/plugins/do-it/skills/do-it-visual-planning/scripts/stop-server.sh deleted file mode 100755 index 8966a93..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/scripts/stop-server.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -# Stop the do-it visual server and clean up -# Usage: stop-server.sh -# -# Kills the server process. Only deletes session directory if it's -# under /tmp (ephemeral). Persistent directories (.do-it/visual/) are -# kept so mockups can be reviewed later. - -SESSION_DIR="$1" - -if [[ -z "$SESSION_DIR" ]]; then - echo '{"error": "Usage: stop-server.sh "}' - exit 1 -fi - -STATE_DIR="${SESSION_DIR}/state" -PID_FILE="${STATE_DIR}/server.pid" - -if [[ -f "$PID_FILE" ]]; then - pid=$(cat "$PID_FILE") - - # Try to stop gracefully, fallback to force if still alive - kill "$pid" 2>/dev/null || true - - # Wait for graceful shutdown (up to ~2s) - for i in {1..20}; do - if ! kill -0 "$pid" 2>/dev/null; then - break - fi - sleep 0.1 - done - - # If still running, escalate to SIGKILL - if kill -0 "$pid" 2>/dev/null; then - kill -9 "$pid" 2>/dev/null || true - - # Give SIGKILL a moment to take effect - sleep 0.1 - fi - - if kill -0 "$pid" 2>/dev/null; then - echo '{"status": "failed", "error": "process still running"}' - exit 1 - fi - - rm -f "$PID_FILE" "${STATE_DIR}/server.log" - - # Only delete ephemeral /tmp directories - if [[ "$SESSION_DIR" == /tmp/* ]]; then - rm -rf "$SESSION_DIR" - fi - - echo '{"status": "stopped"}' -else - echo '{"status": "not_running"}' -fi diff --git a/plugins/do-it/skills/do-it-visual-planning/templates/plan-card.html b/plugins/do-it/skills/do-it-visual-planning/templates/plan-card.html deleted file mode 100644 index facf904..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/templates/plan-card.html +++ /dev/null @@ -1,56 +0,0 @@ - -
-

-

-
- Tier: - Size: - Owner: -
-
- -
-
Background & Goal
-

-
- -
-
Allowed Scope
-
    -
  • -
-
- -
-
Acceptance Criteria
- - - - - -
ACCriteriaEvidence
AC1
-
- -
-
Verification
-

-
- -
-
Risks & Shared-File Hazards
-
    -
  • -
-
diff --git a/plugins/do-it/skills/do-it-visual-planning/templates/review-report.html b/plugins/do-it/skills/do-it-visual-planning/templates/review-report.html deleted file mode 100644 index 367fb1c..0000000 --- a/plugins/do-it/skills/do-it-visual-planning/templates/review-report.html +++ /dev/null @@ -1,47 +0,0 @@ - -
-

-

-
- Blocking: - Important: - Opportunity: -
-
- -
-
Findings
- -
-
Blocking
-

-
-
- -
-
Important
-

-
-
- -
-
Opportunity
-

-
-
-
- -
-
Residual Risk
-

-
diff --git a/scripts/build-index-json.mjs b/scripts/build-index-json.mjs index 402092f..b446f08 100644 --- a/scripts/build-index-json.mjs +++ b/scripts/build-index-json.mjs @@ -26,15 +26,13 @@ const SKILL_GROUPS = new Map([ ["do-it-interface-drill", "on-demand"], ["do-it-debugging", "on-demand"], ["do-it-slicing", "on-demand"], - ["do-it-domain-language", "on-demand"], ["do-it-comments-discipline", "on-demand"], ["do-it-worktree-isolation", "on-demand"], ["do-it-branch-closeout", "on-demand"], ["do-it-subagent-orchestration", "on-demand"], ["do-it-handbook", "maintenance"], ["do-it-context", "maintenance"], - ["do-it-skill-authoring", "maintenance"], - ["do-it-visual-planning", "optional"] + ["do-it-skill-authoring", "maintenance"] ]); function repoPath(relativePath) { diff --git a/scripts/build-skills-index.mjs b/scripts/build-skills-index.mjs index c6be17a..a506130 100644 --- a/scripts/build-skills-index.mjs +++ b/scripts/build-skills-index.mjs @@ -32,7 +32,6 @@ const ON_DEMAND = [ "do-it-interface-drill", "do-it-debugging", "do-it-slicing", - "do-it-domain-language", "do-it-comments-discipline", "do-it-worktree-isolation", "do-it-branch-closeout", diff --git a/skills/do-it/do-it-context/SKILL.md b/skills/do-it/do-it-context/SKILL.md index d1f6f06..c3010a4 100644 --- a/skills/do-it/do-it-context/SKILL.md +++ b/skills/do-it/do-it-context/SKILL.md @@ -1,13 +1,13 @@ --- name: do-it-context -description: "Use when repo terms or invariants are drifting and `.do-it/CONTEXT.md` should become the downstream source of truth for names, relationships, and facts." +description: "Use when repo terms or invariants are drifting, or when user/docs/code naming disagrees and a canonical glossary is needed — `.do-it/CONTEXT.md` is the downstream source of truth for names, relationships, and facts." --- # Do-It Context ## Purpose -`.do-it/CONTEXT.md` is the single canonical place where this project's terminology, invariants, and relationship-shapes live for AI workflows. Other skills (especially `do-it-grill`, `do-it-planning`, `do-it-review-loop`, `do-it-domain-language`) read it before debating definitions. +`.do-it/CONTEXT.md` is the single canonical place where this project's terminology, invariants, and relationship-shapes live for AI workflows. Other skills (especially `do-it-grill`, `do-it-planning`, `do-it-review-loop`) read it before debating definitions. This skill also owns the deeper domain-language pass (canonical glossary + contradiction checks) — see § Domain Glossary Mode. It is **not** a wiki, README replacement, or onboarding doc. It is a terse, declarative artifact intended to fit in the AI's working memory budget. Keep it under ~200 lines. @@ -87,6 +87,44 @@ Roughly quarterly, or when the file crosses ~200 lines: 2. Find lines that no longer match the code; rewrite or delete. 3. Find lines that have moved into the type system / schema and can now be deleted. +## Domain Glossary Mode (Standard+) + +The sediment workflow above is the Light path — one line per clarified term. For +non-trivial naming or modeling work (a new public API, schema, data model, phase +plan, or widespread terminology drift), do the deeper pass: build an explicit +canonical language map before names harden into code, docs, schemas, UI labels, +or handoffs. + +Sequence: + +1. Collect terms from the user request, docs, code, tests, schemas, logs, and UI copy. +2. Group synonyms, aliases, abbreviations, and deprecated terms. +3. Identify contradictions between code, docs, user language, and runtime behavior. +4. Define canonical terms from domain meaning, not implementation convenience. +5. Name domain entities, actions, states, invariants, and forbidden states. +6. Recommend what must change now and what can wait; feed interface/architecture + implications into the relevant do-it skill. + +Glossary shape: + +| Term | Definition | Source evidence | Aliases | Status | +| --- | --- | --- | --- | --- | +| canonical-term | ... | file/docs/user | old-term | canonical | + +Status values: `canonical` (use in new code/docs), `alias` (acceptable for +compatibility), `deprecated` (avoid in new work, migrate when touched), +`conflict` (sources disagree and need a decision). + +Contradiction checks — look for: a user term and a code term that mean different +things; docs describing a concept code models differently; a UI label hiding a +backend state distinction; schema names encoding transport detail instead of +domain meaning; tests using legacy terms; agents or task cards using different +names for the same ownership boundary. + +Stable canonical terms graduate into `glossary.md` via the three-session +promotion rule (see `do-it-handbook`). Do not rename code broadly when a glossary +is enough for the current task. + ## Stop Conditions Do not update CONTEXT.md when: @@ -130,4 +168,3 @@ Before relying on or updating CONTEXT.md: - `do-it-grill` — primary writer of new entries. - `do-it-planning` — reads CONTEXT.md before drafting plan cards. - `do-it-review-loop` — checks CONTEXT.md for contract terms before reviewing. -- `do-it-domain-language` — for the deeper "is this a coherent domain language" question. diff --git a/skills/do-it/do-it-domain-language/SKILL.md b/skills/do-it/do-it-domain-language/SKILL.md deleted file mode 100644 index 71b8160..0000000 --- a/skills/do-it/do-it-domain-language/SKILL.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -name: do-it-domain-language -description: "Use when user language, docs, and code naming disagree and a canonical domain glossary or handoff vocabulary is needed." ---- - -# Do-It Domain Language - -## Purpose - -Use this to make domain terms explicit before names become code, docs, schemas, UI labels, or agent handoffs. The output is a small canonical language map with contradictions and proposed resolutions. - -## Tier Rules - -### Light - -Use for a local naming decision. Inspect nearby code and docs, pick the least surprising term, and note aliases if needed. - -### Standard - -Default for subagents and non-trivial naming or model work. Build a glossary from user language, docs, code, tests, schemas, and UI text. - -### Heavy - -Parent-only unless explicitly assigned. Use for phase plans, data models, public APIs, workflow policy, migrations, or widespread terminology drift. - -## Sequence - -1. Collect terms from the user request, docs, code, tests, schemas, logs, and UI copy. -2. Group synonyms, aliases, abbreviations, and deprecated terms. -3. Identify contradictions between code, docs, user language, and runtime behavior. -4. Define canonical terms using domain meaning, not implementation convenience. -5. Name domain entities, actions, states, invariants, and forbidden states. -6. Recommend where terminology must change now and what can wait. -7. Feed interface or architecture implications into the relevant do-it skill. - -## Glossary Shape - -| Term | Definition | Source evidence | Aliases | Status | -| --- | --- | --- | --- | --- | -| canonical-term | ... | file/docs/user | old-term | canonical | - -Status values: - -- `canonical`: use in new code/docs. -- `alias`: acceptable when preserving compatibility. -- `deprecated`: avoid in new work, migrate when touched. -- `conflict`: current sources disagree and need a decision. - -## Contradiction Checks - -Look for: - -- user term means one thing, code term means another; -- docs describe a concept that code models differently; -- UI label hides a backend state distinction; -- schema names encode transport detail instead of domain meaning; -- tests use legacy terms that make new behavior ambiguous; -- agents or task cards use different names for the same ownership boundary. - -## Output Shape - -- Scope scanned. -- Canonical glossary. -- Contradictions and proposed resolution. -- Domain entities, actions, states, and invariants. -- Required naming changes for current work. -- Deferred terminology cleanup, if any. -- Interface or architecture follow-ups. - -## Common Mistakes - -- Renaming code broadly when a glossary is enough for the current task. -- Picking names from implementation detail instead of domain meaning. -- Treating aliases as harmless when they create conflicting behavior. -- Ignoring docs or UI copy while changing API names. -- Letting a subagent redefine canonical language outside its assigned slice. diff --git a/skills/do-it/do-it-planning/SKILL.md b/skills/do-it/do-it-planning/SKILL.md index 7cebf26..65773e3 100644 --- a/skills/do-it/do-it-planning/SKILL.md +++ b/skills/do-it/do-it-planning/SKILL.md @@ -37,7 +37,7 @@ Parent-only unless explicitly assigned: - use for wave, phase, release, multi-agent, durable workflow, or cross-boundary planning; - lock scope, write ownership, non-goals, and integration ownership; -- run grill, interface, architecture, domain-language, or slicing drills as needed; +- run grill, interface, architecture, vocabulary (do-it-context), or slicing drills as needed; - stop for approval if the user asked to confirm the plan. ## Planning Sequence @@ -222,6 +222,16 @@ Include: Keep file paths and code snippets out of durable PRD prose unless the user asks for a code-facing plan; they go stale faster than domain decisions. +## Visual Aids (optional) + +When seeing an option is materially clearer than reading it — UI layout +alternatives, architecture/data-flow diagrams, before/after states, side-by-side +interface shapes — sketch it under `.do-it/visual//` (descriptive +filenames like `option-a-flow.md`, `api-boundary.svg`). Treat these as auxiliary +evidence, not durable plan output: the decision still lands in the plan card. +Skip visuals for text-only decisions, one-line questions, or where a table is +clearer. A visual aid never promotes a task's tier by itself. + ## Output Shape - Tier and task class. diff --git a/skills/do-it/do-it-router/SKILL.md b/skills/do-it/do-it-router/SKILL.md index 1a6a7e6..ccda0b4 100644 --- a/skills/do-it/do-it-router/SKILL.md +++ b/skills/do-it/do-it-router/SKILL.md @@ -227,9 +227,9 @@ review-clean. - Need to challenge a premise, plan, or closeout claim: `do-it-grill`. - Need to design an API, schema, event, CLI, UI contract, module seam, or handoff: `do-it-interface-drill`. - Need coupling, ownership, modularity, or testability analysis: `do-it-architecture-scan`. -- Need names, domain model, glossary, or code/docs/user terminology alignment: `do-it-domain-language`. +- Need names, domain model, glossary, or code/docs/user terminology alignment: `do-it-context` (§ Domain Glossary Mode). - Need a durable project handbook (invariants, architecture, code map, glossary, backlog): `do-it-handbook`. Suggest it when work spans many files or several sessions and `.do-it/handbook/` does not yet exist; downstream skills (`do-it-grill`, `do-it-planning`, `do-it-architecture-scan`) read those files when present. -- Need optional visual comparison or diagrams: `do-it-visual-planning`. This is auxiliary and does not participate in the core tier flow. +- Need optional visual comparison or diagrams: `do-it-planning` § Visual Aids. Auxiliary; does not participate in the core tier flow. - Need implementation: execute locally or delegate a bounded slice after the route is clear; add `do-it-tdd` or `do-it-debugging` when the behavior or root cause warrants it. - Need behavior-first implementation or regression coverage: `do-it-tdd`. - Need root-cause diagnosis before fixing: `do-it-debugging`. @@ -242,7 +242,7 @@ review-clean. - Need to create or rewrite skills: `do-it-skill-authoring`. - Authoring or reviewing comments on a code edit: `do-it-comments-discipline`. The parent agent should apply it before writing comments; the PostToolUse `comments-lint` hook is advisory backup, and a Standard or Heavy review pass that touches comments should load it for the comments lens. -Use the narrowest sequence that covers the risk. A small API rename may need only Standard interface drill plus delivery. A phase plan may need Heavy planning, slicing, grill, interface, architecture, and domain-language passes. +Use the narrowest sequence that covers the risk. A small API rename may need only Standard interface drill plus delivery. A phase plan may need Heavy planning, slicing, grill, interface, architecture, and vocabulary passes. ## Delegation Policy diff --git a/skills/do-it/do-it-visual-planning/SKILL.md b/skills/do-it/do-it-visual-planning/SKILL.md deleted file mode 100644 index 70b68f1..0000000 --- a/skills/do-it/do-it-visual-planning/SKILL.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -name: do-it-visual-planning -description: "Use when a plan or design decision would benefit from a small diagram, sketch, mockup, or side-by-side visual artifact alongside text." ---- - -# Do-It Visual Planning - -## Purpose - -Use this as an auxiliary planning aid for visual comparison. It is not part of the core do-it tier flow and must not promote a task from Light to Standard or Heavy by itself. - -Use `.do-it/visual/` as the workspace for sketches, diagrams, screenshots, notes, or generated visual assets. Keep product code and non-visual docs out of this skill unless another do-it skill explicitly owns that edit. - -## Tier Rules - -### Light - -Use a quick sketch, ASCII diagram, or one comparison image to resolve a narrow ambiguity. - -### Standard - -Default for subagents and ordinary visual planning. Produce 2-3 options and compare tradeoffs. - -### Heavy - -Parent-only unless explicitly assigned. Use for cross-screen UI flows, architecture diagrams for wave/phase planning, or visual decisions that affect multiple workers. - -## When To Use - -Use when seeing the option is materially better than reading it: - -- UI layout or interaction alternatives; -- architecture or data-flow diagrams; -- before/after visual states; -- side-by-side interface shapes; -- visual task sequencing for multi-agent work. - -Skip it for text-only decisions, one-line questions, or plans where a table is clearer. - -## Workspace Rules - -- Store artifacts under `.do-it/visual//`. -- Use descriptive filenames like `option-a-flow.md`, `api-boundary.svg`, or `screen-compare.png`. -- Treat the workspace as auxiliary evidence, not final product output. -- Do not edit manifest, install scripts, package files, or unrelated docs from this skill. -- If generated artifacts are temporary, say so in closeout. -- For browser-based comparisons, use `scripts/start-server.sh` and - `references/visual-companion.md`. Load that reference only when you actually - need the local browser companion. -- Browser session HTML must be written to the `screen_dir` returned by the - companion server. Use `.do-it/visual//` for static artifacts, notes, - screenshots, or generated assets outside the live browser session. - -## Scenario Templates - -`templates/` ships ready-made content fragments for two recurring artifacts: - -- `templates/plan-card.html` — a plan / task card (goal, scope, acceptance criteria, verification, risks); section order matches the task-card layout in `do-it-planning` so a visual card and a written card stay consistent. -- `templates/review-report.html` — review findings grouped by Blocking / Important / Opportunity with evidence. - -To use one: copy the fragment into the companion `screen_dir`, fill its `slot:` placeholders, and drop unused sections. The server wraps the fragment in `frame-template.html`, which already carries all CSS — the fragment stays small because only the content varies, and a consistent skeleton means the layout is not re-derived each time. - -These templates render the *same* content a text plan or review carries. Reach for them only when a user benefits from seeing the artifact in the browser companion; they do not replace the durable `.do-it/plans/` or `.do-it/review/` markdown that other skills own. - -## Sequence - -1. Inspect the current design context or code surface. -2. Decide whether visual treatment will reduce ambiguity. -3. Create or update the smallest useful artifact in `.do-it/visual/`, or in the - returned `screen_dir` when using the browser companion. -4. Compare options with explicit tradeoffs and a recommendation. -5. Feed the decision back into `do-it-planning`, `do-it-interface-drill`, or `do-it-architecture-scan`. - -## Output Shape - -- Visual workspace path. -- Options or diagram created. -- Decision clarified. -- Recommendation. -- Follow-up do-it skill or delivery step. - -## Common Mistakes - -- Making visuals because they look nice, not because they clarify a decision. -- Letting visual planning replace acceptance criteria or verification. -- Mixing temporary sketches into product docs. -- Treating this auxiliary skill as a required gate in the core do-it flow. diff --git a/skills/do-it/do-it-visual-planning/references/visual-companion.md b/skills/do-it/do-it-visual-planning/references/visual-companion.md deleted file mode 100644 index 393118e..0000000 --- a/skills/do-it/do-it-visual-planning/references/visual-companion.md +++ /dev/null @@ -1,267 +0,0 @@ -# Visual Companion Guide - -Browser-based do-it visual planning companion for showing mockups, diagrams, and options. - -## When to Use - -Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?** - -**Use the browser** when the content itself is visual: - -- **UI mockups** — wireframes, layouts, navigation structures, component designs -- **Architecture diagrams** — system components, data flow, relationship maps -- **Side-by-side visual comparisons** — comparing two layouts, two color schemes, two design directions -- **Design polish** — when the question is about look and feel, spacing, visual hierarchy -- **Spatial relationships** — state machines, flowcharts, entity relationships rendered as diagrams - -**Use the terminal** when the content is text or tabular: - -- **Requirements and scope questions** — "what does X mean?", "which features are in scope?" -- **Conceptual A/B/C choices** — picking between approaches described in words -- **Tradeoff lists** — pros/cons, comparison tables -- **Technical decisions** — API design, data modeling, architectural approach selection -- **Clarifying questions** — anything where the answer is words, not a visual preference - -A question *about* a UI topic is not automatically a visual question. "What kind of wizard do you want?" is conceptual — use the terminal. "Which of these wizard layouts feels right?" is visual — use the browser. - -## How It Works - -The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to `screen_dir`, the user sees it in their browser and can click to select options. Selections are recorded to `state_dir/events` that you read on your next turn. - -**Content fragments vs full documents:** If your HTML file starts with `/.do-it/visual/` for the session directory. - -**Note:** Pass the project root as `--project-dir` so mockups persist in `.do-it/visual/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. The do-it repository ignores `.do-it/`; downstream projects should do the same before using persistent visual sessions. - -**Launching the server:** - -```bash -# Codex-first default. The script auto-detects CODEX_CI and switches to -# foreground mode when the environment would reap detached processes. -scripts/start-server.sh --project-dir /path/to/project -``` - -Other runtimes must keep the server alive across turns. If the environment -reaps detached processes, use `--foreground` and launch the command with that -runtime's background execution mechanism. - -If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host: - -```bash -scripts/start-server.sh \ - --project-dir /path/to/project \ - --host 0.0.0.0 \ - --url-host localhost -``` - -Use `--url-host` to control what hostname is printed in the returned URL JSON. - -## The Loop - -1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`: - - Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity. - - Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html` - - **Never reuse filenames** — each screen gets a fresh file - - Use the normal file-editing tool; avoid cat/heredoc writes that dump noisy - HTML into terminal output. - - Server automatically serves the newest file - -2. **Tell user what to expect and end your turn:** - - Remind them of the URL (every step, not just first) - - Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage") - - Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like." - -3. **On your next turn** — after the user responds in the terminal: - - Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines - - Merge with the user's terminal text to get the full picture - - The terminal message is the primary feedback; `state_dir/events` provides structured interaction data - -4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated. - -5. **Unload when returning to terminal** — when the next step doesn't need the browser (e.g., a clarifying question, a tradeoff discussion), push a waiting screen to clear the stale content: - - ```html - -
-

Continuing in terminal...

-
- ``` - - This prevents the user from staring at a resolved choice while the conversation has moved on. When the next visual question comes up, push a new content file as usual. - -6. Repeat until done. - -## Writing Content Fragments - -Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure). - -**Minimal example:** - -```html -

Which layout works better?

-

Consider readability and visual hierarchy

- -
-
-
A
-
-

Single Column

-

Clean, focused reading experience

-
-
-
-
B
-
-

Two Column

-

Sidebar navigation with main content

-
-
-
-``` - -That's it. No ``, no CSS, no `'; - -// ========== Helper Functions ========== - -function isFullDocument(html) { - const trimmed = html.trimStart().toLowerCase(); - return trimmed.startsWith('', content); -} - -function getNewestScreen() { - const files = fs.readdirSync(CONTENT_DIR) - .filter(f => f.endsWith('.html')) - .map(f => { - const fp = path.join(CONTENT_DIR, f); - return { path: fp, mtime: fs.statSync(fp).mtime.getTime() }; - }) - .sort((a, b) => b.mtime - a.mtime); - return files.length > 0 ? files[0].path : null; -} - -// ========== HTTP Request Handler ========== - -function handleRequest(req, res) { - touchActivity(); - if (req.method === 'GET' && req.url === '/') { - const screenFile = getNewestScreen(); - let html = screenFile - ? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8')) - : WAITING_PAGE; - - if (html.includes('')) { - html = html.replace('', helperInjection + '\n'); - } else { - html += helperInjection; - } - - res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); - res.end(html); - } else if (req.method === 'GET' && req.url.startsWith('/files/')) { - const fileName = req.url.slice(7); - const filePath = path.join(CONTENT_DIR, path.basename(fileName)); - if (!fs.existsSync(filePath)) { - res.writeHead(404); - res.end('Not found'); - return; - } - const ext = path.extname(filePath).toLowerCase(); - const contentType = MIME_TYPES[ext] || 'application/octet-stream'; - res.writeHead(200, { 'Content-Type': contentType }); - res.end(fs.readFileSync(filePath)); - } else { - res.writeHead(404); - res.end('Not found'); - } -} - -// ========== WebSocket Connection Handling ========== - -const clients = new Set(); - -function handleUpgrade(req, socket) { - const key = req.headers['sec-websocket-key']; - if (!key) { socket.destroy(); return; } - - const accept = computeAcceptKey(key); - socket.write( - 'HTTP/1.1 101 Switching Protocols\r\n' + - 'Upgrade: websocket\r\n' + - 'Connection: Upgrade\r\n' + - 'Sec-WebSocket-Accept: ' + accept + '\r\n\r\n' - ); - - let buffer = Buffer.alloc(0); - clients.add(socket); - - socket.on('data', (chunk) => { - buffer = Buffer.concat([buffer, chunk]); - while (buffer.length > 0) { - let result; - try { - result = decodeFrame(buffer); - } catch (e) { - socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); - clients.delete(socket); - return; - } - if (!result) break; - buffer = buffer.slice(result.bytesConsumed); - - switch (result.opcode) { - case OPCODES.TEXT: - handleMessage(result.payload.toString()); - break; - case OPCODES.CLOSE: - socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); - clients.delete(socket); - return; - case OPCODES.PING: - socket.write(encodeFrame(OPCODES.PONG, result.payload)); - break; - case OPCODES.PONG: - break; - default: { - const closeBuf = Buffer.alloc(2); - closeBuf.writeUInt16BE(1003); - socket.end(encodeFrame(OPCODES.CLOSE, closeBuf)); - clients.delete(socket); - return; - } - } - } - }); - - socket.on('close', () => clients.delete(socket)); - socket.on('error', () => clients.delete(socket)); -} - -function handleMessage(text) { - let event; - try { - event = JSON.parse(text); - } catch (e) { - console.error('Failed to parse WebSocket message:', e.message); - return; - } - touchActivity(); - console.log(JSON.stringify({ source: 'user-event', ...event })); - if (event.choice) { - const eventsFile = path.join(STATE_DIR, 'events'); - fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n'); - } -} - -function broadcast(msg) { - const frame = encodeFrame(OPCODES.TEXT, Buffer.from(JSON.stringify(msg))); - for (const socket of clients) { - try { socket.write(frame); } catch (e) { clients.delete(socket); } - } -} - -// ========== Activity Tracking ========== - -const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes -let lastActivity = Date.now(); - -function touchActivity() { - lastActivity = Date.now(); -} - -// ========== File Watching ========== - -const debounceTimers = new Map(); - -// ========== Server Startup ========== - -function startServer() { - if (!fs.existsSync(CONTENT_DIR)) fs.mkdirSync(CONTENT_DIR, { recursive: true }); - if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true }); - - // Track known files to distinguish new screens from updates. - // macOS fs.watch reports 'rename' for both new files and overwrites, - // so we can't rely on eventType alone. - const knownFiles = new Set( - fs.readdirSync(CONTENT_DIR).filter(f => f.endsWith('.html')) - ); - - const server = http.createServer(handleRequest); - server.on('upgrade', handleUpgrade); - - const watcher = fs.watch(CONTENT_DIR, (eventType, filename) => { - if (!filename || !filename.endsWith('.html')) return; - - if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename)); - debounceTimers.set(filename, setTimeout(() => { - debounceTimers.delete(filename); - const filePath = path.join(CONTENT_DIR, filename); - - if (!fs.existsSync(filePath)) return; // file was deleted - touchActivity(); - - if (!knownFiles.has(filename)) { - knownFiles.add(filename); - const eventsFile = path.join(STATE_DIR, 'events'); - if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); - console.log(JSON.stringify({ type: 'screen-added', file: filePath })); - } else { - console.log(JSON.stringify({ type: 'screen-updated', file: filePath })); - } - - broadcast({ type: 'reload' }); - }, 100)); - }); - watcher.on('error', (err) => console.error('fs.watch error:', err.message)); - - function shutdown(reason) { - console.log(JSON.stringify({ type: 'server-stopped', reason })); - const infoFile = path.join(STATE_DIR, 'server-info'); - if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile); - fs.writeFileSync( - path.join(STATE_DIR, 'server-stopped'), - JSON.stringify({ reason, timestamp: Date.now() }) + '\n' - ); - watcher.close(); - clearInterval(lifecycleCheck); - server.close(() => process.exit(0)); - } - - function ownerAlive() { - if (!ownerPid) return true; - try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; } - } - - // Check every 60s: exit if owner process died or idle for 30 minutes - const lifecycleCheck = setInterval(() => { - if (!ownerAlive()) shutdown('owner process exited'); - else if (Date.now() - lastActivity > IDLE_TIMEOUT_MS) shutdown('idle timeout'); - }, 60 * 1000); - lifecycleCheck.unref(); - - // Validate owner PID at startup. If it's already dead, the PID resolution - // was wrong (common on WSL, Tailscale SSH, and cross-user scenarios). - // Disable monitoring and rely on the idle timeout instead. - if (ownerPid) { - try { process.kill(ownerPid, 0); } - catch (e) { - if (e.code !== 'EPERM') { - console.log(JSON.stringify({ type: 'owner-pid-invalid', pid: ownerPid, reason: 'dead at startup' })); - ownerPid = null; - } - } - } - - server.listen(PORT, HOST, () => { - const info = JSON.stringify({ - type: 'server-started', port: Number(PORT), host: HOST, - url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT, - screen_dir: CONTENT_DIR, state_dir: STATE_DIR - }); - console.log(info); - fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n'); - }); -} - -if (require.main === module) { - startServer(); -} - -module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES }; diff --git a/skills/do-it/do-it-visual-planning/scripts/start-server.sh b/skills/do-it/do-it-visual-planning/scripts/start-server.sh deleted file mode 100755 index 55b89ae..0000000 --- a/skills/do-it/do-it-visual-planning/scripts/start-server.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env bash -# Start the do-it visual server and output connection info -# Usage: start-server.sh [--project-dir ] [--host ] [--url-host ] [--foreground] [--background] -# -# Starts server on a random high port, outputs JSON with URL. -# Each session gets its own directory to avoid conflicts. -# -# Options: -# --project-dir Store session files under /.do-it/visual/ -# instead of /tmp. Files persist after server stops. -# --host Host/interface to bind (default: 127.0.0.1). -# Use 0.0.0.0 in remote/containerized environments. -# --url-host Hostname shown in returned URL JSON. -# --foreground Run server in the current terminal (no backgrounding). -# --background Force background mode (overrides Codex auto-foreground). - -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -# Parse arguments -PROJECT_DIR="" -FOREGROUND="false" -FORCE_BACKGROUND="false" -BIND_HOST="127.0.0.1" -URL_HOST="" -while [[ $# -gt 0 ]]; do - case "$1" in - --project-dir) - PROJECT_DIR="$2" - shift 2 - ;; - --host) - BIND_HOST="$2" - shift 2 - ;; - --url-host) - URL_HOST="$2" - shift 2 - ;; - --foreground|--no-daemon) - FOREGROUND="true" - shift - ;; - --background|--daemon) - FORCE_BACKGROUND="true" - shift - ;; - *) - echo "{\"error\": \"Unknown argument: $1\"}" - exit 1 - ;; - esac -done - -if [[ -z "$URL_HOST" ]]; then - if [[ "$BIND_HOST" == "127.0.0.1" || "$BIND_HOST" == "localhost" ]]; then - URL_HOST="localhost" - else - URL_HOST="$BIND_HOST" - fi -fi - -# Some environments reap detached/background processes. Auto-foreground when detected. -if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then - FOREGROUND="true" -fi - -# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected. -if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then - case "${OSTYPE:-}" in - msys*|cygwin*|mingw*) FOREGROUND="true" ;; - esac - if [[ -n "${MSYSTEM:-}" ]]; then - FOREGROUND="true" - fi -fi - -# Generate unique session directory -SESSION_ID="$$-$(date +%s)" - -if [[ -n "$PROJECT_DIR" ]]; then - SESSION_DIR="${PROJECT_DIR}/.do-it/visual/${SESSION_ID}" -else - SESSION_DIR="/tmp/do-it-visual-${SESSION_ID}" -fi - -STATE_DIR="${SESSION_DIR}/state" -PID_FILE="${STATE_DIR}/server.pid" -LOG_FILE="${STATE_DIR}/server.log" - -# Create fresh session directory with content and state peers -mkdir -p "${SESSION_DIR}/content" "$STATE_DIR" - -# Kill any existing server -if [[ -f "$PID_FILE" ]]; then - old_pid=$(cat "$PID_FILE") - kill "$old_pid" 2>/dev/null - rm -f "$PID_FILE" -fi - -cd "$SCRIPT_DIR" - -# Resolve the harness PID (grandparent of this script). -# $PPID is the ephemeral shell the harness spawned to run us — it dies -# when this script exits. The harness itself is $PPID's parent. -OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ')" -if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then - OWNER_PID="$PPID" -fi - -# Foreground mode for environments that reap detached/background processes. -if [[ "$FOREGROUND" == "true" ]]; then - echo "$$" > "$PID_FILE" - env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs - exit $? -fi - -# Start server, capturing output to log file -# Use nohup to survive shell exit; disown to remove from job table -nohup env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 & -SERVER_PID=$! -disown "$SERVER_PID" 2>/dev/null -echo "$SERVER_PID" > "$PID_FILE" - -# Wait for server-started message (check log file) -for i in {1..50}; do - if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then - # Verify server is still alive after a short window (catches process reapers) - alive="true" - for _ in {1..20}; do - if ! kill -0 "$SERVER_PID" 2>/dev/null; then - alive="false" - break - fi - sleep 0.1 - done - if [[ "$alive" != "true" ]]; then - echo "{\"error\": \"Server started but was killed. Retry in a persistent terminal with: $SCRIPT_DIR/start-server.sh${PROJECT_DIR:+ --project-dir $PROJECT_DIR} --host $BIND_HOST --url-host $URL_HOST --foreground\"}" - exit 1 - fi - grep "server-started" "$LOG_FILE" | head -1 - exit 0 - fi - sleep 0.1 -done - -# Timeout - server didn't start -echo '{"error": "Server failed to start within 5 seconds"}' -exit 1 diff --git a/skills/do-it/do-it-visual-planning/scripts/stop-server.sh b/skills/do-it/do-it-visual-planning/scripts/stop-server.sh deleted file mode 100755 index 8966a93..0000000 --- a/skills/do-it/do-it-visual-planning/scripts/stop-server.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -# Stop the do-it visual server and clean up -# Usage: stop-server.sh -# -# Kills the server process. Only deletes session directory if it's -# under /tmp (ephemeral). Persistent directories (.do-it/visual/) are -# kept so mockups can be reviewed later. - -SESSION_DIR="$1" - -if [[ -z "$SESSION_DIR" ]]; then - echo '{"error": "Usage: stop-server.sh "}' - exit 1 -fi - -STATE_DIR="${SESSION_DIR}/state" -PID_FILE="${STATE_DIR}/server.pid" - -if [[ -f "$PID_FILE" ]]; then - pid=$(cat "$PID_FILE") - - # Try to stop gracefully, fallback to force if still alive - kill "$pid" 2>/dev/null || true - - # Wait for graceful shutdown (up to ~2s) - for i in {1..20}; do - if ! kill -0 "$pid" 2>/dev/null; then - break - fi - sleep 0.1 - done - - # If still running, escalate to SIGKILL - if kill -0 "$pid" 2>/dev/null; then - kill -9 "$pid" 2>/dev/null || true - - # Give SIGKILL a moment to take effect - sleep 0.1 - fi - - if kill -0 "$pid" 2>/dev/null; then - echo '{"status": "failed", "error": "process still running"}' - exit 1 - fi - - rm -f "$PID_FILE" "${STATE_DIR}/server.log" - - # Only delete ephemeral /tmp directories - if [[ "$SESSION_DIR" == /tmp/* ]]; then - rm -rf "$SESSION_DIR" - fi - - echo '{"status": "stopped"}' -else - echo '{"status": "not_running"}' -fi diff --git a/skills/do-it/do-it-visual-planning/templates/plan-card.html b/skills/do-it/do-it-visual-planning/templates/plan-card.html deleted file mode 100644 index facf904..0000000 --- a/skills/do-it/do-it-visual-planning/templates/plan-card.html +++ /dev/null @@ -1,56 +0,0 @@ - -
-

-

-
- Tier: - Size: - Owner: -
-
- -
-
Background & Goal
-

-
- -
-
Allowed Scope
-
    -
  • -
-
- -
-
Acceptance Criteria
- - - - - -
ACCriteriaEvidence
AC1
-
- -
-
Verification
-

-
- -
-
Risks & Shared-File Hazards
-
    -
  • -
-
diff --git a/skills/do-it/do-it-visual-planning/templates/review-report.html b/skills/do-it/do-it-visual-planning/templates/review-report.html deleted file mode 100644 index 367fb1c..0000000 --- a/skills/do-it/do-it-visual-planning/templates/review-report.html +++ /dev/null @@ -1,47 +0,0 @@ - -
-

-

-
- Blocking: - Important: - Opportunity: -
-
- -
-
Findings
- -
-
Blocking
-

-
-
- -
-
Important
-

-
-
- -
-
Opportunity
-

-
-
-
- -
-
Residual Risk
-

-
From e37cc63f4ce15d7d7d5bd75f6c8e44b3ac686b67 Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 18:07:44 +0800 Subject: [PATCH 05/10] feat(hooks): advisory nudges for plan-card reliability and existing-code discipline Two low-noise, one-shot advisories (never block) for real workflow gaps the user hit: plan cards not reliably created after discussion, and agents "going rogue" on established codebases. - Plan-card reliability: after grill has run on durable-plan work (Heavy or an explicit plan-first request) and no .do-it/plans/.md exists, grill-prompt emits a one-shot reminder to land the plan card before implementation drifts ahead. Router records a sticky durable_plan_seen so the nudge survives the per-turn durable_plan_required recompute. - Existing-code discipline: router writes dim_brownfield (project has .do-it/CONTEXT.md or a handbook) and port_intent (prompt asks to port / restore / reintroduce). grill-prompt emits a one-shot "read existing structure / grep current code first" nudge so the agent stops assuming greenfield. Both follow the existing router(state-only) -> grill-prompt(emit) split and attach to whichever exit path the grill hook takes, so they fire even when the grill reminder itself does not. Brownfield is intentionally narrow (do-it context artifacts, not any git repo) to stay coherent and quiet. Adds 6 regression cases to scripts/test-hooks.sh. npm test green; lint-hooks clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- hooks/grill-prompt.sh | 54 ++++++++++++++++++++++++++++++++---- hooks/router.sh | 25 +++++++++++++++++ scripts/test-hooks.sh | 64 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 5 deletions(-) diff --git a/hooks/grill-prompt.sh b/hooks/grill-prompt.sh index 314c9a1..b3c2020 100755 --- a/hooks/grill-prompt.sh +++ b/hooks/grill-prompt.sh @@ -21,6 +21,16 @@ source "${SCRIPT_DIR}/lib/keywords.sh" # shellcheck source=lib/debug.sh source "${SCRIPT_DIR}/lib/debug.sh" +# Advisory nudges (plan-card reliability, existing-codebase discipline) are +# computed once on a work turn and attached to whichever exit path this hook +# takes, so they fire even when the grill reminder itself does not. Advisory +# only — never blocks. +_doit_advisory="" +_emit_advisory_exit() { + [[ -n "$_doit_advisory" ]] && do_it_emit_context UserPromptSubmit "$_doit_advisory" + exit 0 +} + # Read stdin first so the subagent check can use the JSON-supplied # transcript_path (the host delivers it on stdin, not as an env var). RAW_INPUT="$(do_it_read_stdin)" @@ -79,6 +89,40 @@ if [[ "$EXPLICIT_GRILL" -eq 0 ]] && { [[ "$LAST_PROMPT_KIND" == "question" ]] || exit 0 fi +# ---- One-shot advisory nudges (work turns only; never block) ---- +ADVISORY_TIER="$(do_it_session_state_get "$SESSION_ID" tier)" + +# C1: grill ran in a prior turn and durable planning is required, but no plan +# card exists yet — nudge to land it before implementation drifts ahead. +_grilled_prev="$(do_it_session_state_get "$SESSION_ID" grilled)" +if [[ "$(do_it_session_state_get "$SESSION_ID" plan_nudged)" != "1" \ + && "$(do_it_session_state_get "$SESSION_ID" durable_plan_seen)" == "1" \ + && -n "$_grilled_prev" && "$_grilled_prev" != "0" && "$_grilled_prev" != "skip-question" ]] \ + && ! ls "${CWD}/.do-it/plans/"*.md >/dev/null 2>&1; then + do_it_session_state_set "$SESSION_ID" plan_nudged 1 + _doit_advisory="${_doit_advisory} +do-it planning: grill has converged and this is durable-plan work, but no .do-it/plans/.md exists yet. Load do-it-planning to land the plan card (acceptance criteria, failure-mode forecast, path map) before implementing. Advisory — skip only if an inline modification map fully covers the work. +" +fi + +# C2: existing-codebase / port-restore "understand before you change" nudge. +if [[ "$(do_it_session_state_get "$SESSION_ID" brownfield_nudged)" != "1" ]]; then + _port="$(do_it_session_state_get "$SESSION_ID" port_intent)" + _brown="$(do_it_session_state_get "$SESSION_ID" dim_brownfield)" + _touch="$(do_it_session_state_get "$SESSION_ID" dim_touches_code)" + if [[ "$_port" == "1" ]]; then + do_it_session_state_set "$SESSION_ID" brownfield_nudged 1 + _doit_advisory="${_doit_advisory} +do-it (existing code): this looks like port / restore / reintroduce work. Before writing a 'port' plan, grep/Glob the current packages/apps/migrations for the target name — it may already exist; if so, extend it instead of rebuilding. Advisory. +" + elif [[ "$_brown" == "1" && "$_touch" == "1" ]] && { [[ "$ADVISORY_TIER" == "Standard" || "$ADVISORY_TIER" == "Heavy" ]]; }; then + do_it_session_state_set "$SESSION_ID" brownfield_nudged 1 + _doit_advisory="${_doit_advisory} +do-it (existing code): this is an established codebase. Before editing, read the file/area you are changing and reuse its existing patterns, names, and invariants (.do-it/CONTEXT.md and handbook if present) rather than assuming greenfield. Advisory. +" + fi +fi + # Same-session de-dup: if we already grilled and the user did not re-request, # stay quiet. if [[ "$RE_GRILL" -eq 0 ]]; then @@ -89,7 +133,7 @@ if [[ "$RE_GRILL" -eq 0 ]]; then fi if [[ -n "$GRILLED" && "$GRILLED" != "0" && "$GRILLED" != "skip-question" ]]; then do_it_debug grill-prompt "decision=already-grilled state=$GRILLED" - exit 0 + _emit_advisory_exit fi fi @@ -108,7 +152,7 @@ if [[ -z "$TRIGGER" && "$EXPLICIT_GRILL" -eq 1 ]]; then fi if [[ -z "$TRIGGER" && "$TIER" == "Light" ]]; then do_it_debug grill-prompt "decision=no-trigger tier=$TIER reason=light" - exit 0 + _emit_advisory_exit fi if [[ -z "$TRIGGER" && "$TIER" == "Standard" ]] && do_it_prompt_has_any "$PROMPT" DO_IT_UNCERTAINTY_WORDS; then TRIGGER="uncertainty" @@ -129,13 +173,13 @@ if [[ -n "$TRIGGER" && "$TIER" == "Standard" && "$EXPLICIT_GRILL" -eq 0 ]]; then TOUCHES_CODE="$(do_it_session_state_get "$SESSION_ID" dim_touches_code)" if [[ "$TOUCHES_CODE" != "1" ]]; then do_it_debug grill-prompt "decision=no-trigger tier=Standard reason=dim-touches-code-zero original-trigger=${TRIGGER}" - exit 0 + _emit_advisory_exit fi fi if [[ -z "$TRIGGER" ]]; then do_it_debug grill-prompt "decision=no-trigger tier=$TIER" - exit 0 + _emit_advisory_exit fi # Heavy-tier turns get a fuller fact-first reminder; everyone else gets the @@ -182,5 +226,5 @@ case "${DO_IT_DEBUG:-0}" in ;; esac -do_it_emit_context UserPromptSubmit "$MSG" +do_it_emit_context UserPromptSubmit "${MSG}${_doit_advisory}" exit 0 diff --git a/hooks/router.sh b/hooks/router.sh index bf0bb42..c78b6dc 100755 --- a/hooks/router.sh +++ b/hooks/router.sh @@ -119,6 +119,31 @@ if [[ "$TIER" == "Heavy" ]] || do_it_prompt_requires_durable_plan "$PROMPT"; the durable_plan_required=1 fi do_it_session_state_set "$SESSION_ID" durable_plan_required "$durable_plan_required" +# Sticky: once durable planning is required in a session, remember it so the +# post-grill plan-card nudge can fire on a later turn even after the per-turn +# durable_plan_required is recomputed to 0 by a follow-up prompt. +if [[ "$durable_plan_required" == "1" ]]; then + do_it_session_state_set "$SESSION_ID" durable_plan_seen 1 +fi + +# Existing-codebase + port/restore signals for the advisory nudges that +# grill-prompt.sh emits (router stays state-only). brownfield = the project has +# accumulated do-it context (CONTEXT.md or a handbook), so the agent should read +# that existing structure before editing rather than assume greenfield. Kept +# precise on purpose: the advisory points at those exact files, and a bare git +# repo is not "established" in the sense that matters. port_intent = the prompt +# asks to port / restore / reintroduce something that often already exists. +brownfield=0 +if [[ -f "${CWD}/.do-it/CONTEXT.md" || -d "${CWD}/.do-it/handbook" ]]; then + brownfield=1 +fi +do_it_session_state_set "$SESSION_ID" dim_brownfield "$brownfield" +port_intent=0 +case "$(do_it_lc "$PROMPT")" in + *"移植"*|*"迁移回"*|*"重新引入"*|*"恢复"*|*"reintroduce"*|*"re-introduce"*|*"port from"*|*"port over"*|*"port the"*|*"restore the"*|*"bring back"*) + port_intent=1 ;; +esac +do_it_session_state_set "$SESSION_ID" port_intent "$port_intent" # Dimensions are orthogonal to tier. Tier stays as the single derived label # existing skills key off; downstream skills may read these additive booleans diff --git a/scripts/test-hooks.sh b/scripts/test-hooks.sh index b15a0c2..da8bedc 100644 --- a/scripts/test-hooks.sh +++ b/scripts/test-hooks.sh @@ -265,4 +265,68 @@ run_router "$withcode_session" "release 我想确认 src/release.ts" withcode_grill="$(run_grill "$withcode_session" "release 我想确认 src/release.ts")" assert_contains "$withcode_grill" "trigger: uncertainty" "Standard + uncertainty + dim_touches_code=1 should still grill" +# ---- Phase 3 advisory nudges (plan-card reliability + existing-codebase) ---- + +# C1: after grill on durable-plan work with no plan card, a later grilled turn +# emits a one-shot plan-card nudge. +nudge_project="$TMP_ROOT/plan-nudge-project" +mkdir -p "$nudge_project" +plan_nudge_session="plan-card-nudge" +run_router "$plan_nudge_session" "Prepare the release schema migration" "$nudge_project" +run_grill "$plan_nudge_session" "Prepare the release schema migration" "$nudge_project" >/dev/null +[[ "$(state_value "$plan_nudge_session" durable_plan_seen)" == "1" ]] \ + || fail "Heavy turn should set durable_plan_seen" +run_router "$plan_nudge_session" "ok implement it" "$nudge_project" +plan_nudge_out="$(run_grill "$plan_nudge_session" "ok implement it" "$nudge_project")" +assert_contains "$plan_nudge_out" "no .do-it/plans/.md exists yet" \ + "post-grill durable work with no plan card should nudge planning" + +# one-shot: a third turn does not repeat the plan nudge +run_router "$plan_nudge_session" "continue implementing" "$nudge_project" +plan_nudge_repeat="$(run_grill "$plan_nudge_session" "continue implementing" "$nudge_project")" +[[ "$plan_nudge_repeat" != *"no .do-it/plans/.md exists yet"* ]] \ + || fail "plan-card nudge should be one-shot per session" + +# with a plan card present, no plan nudge +nudge_has_plan="$TMP_ROOT/plan-present-project" +mkdir -p "$nudge_has_plan/.do-it/plans" +printf '# plan\n' > "$nudge_has_plan/.do-it/plans/task.md" +has_plan_session="plan-present" +run_router "$has_plan_session" "Prepare the release schema migration" "$nudge_has_plan" +run_grill "$has_plan_session" "Prepare the release schema migration" "$nudge_has_plan" >/dev/null +run_router "$has_plan_session" "ok implement it" "$nudge_has_plan" +has_plan_out="$(run_grill "$has_plan_session" "ok implement it" "$nudge_has_plan")" +[[ "$has_plan_out" != *"no .do-it/plans/.md exists yet"* ]] \ + || fail "existing plan card should suppress the planning nudge" + +# C2: port/restore intent emits a one-shot "grep current code first" nudge. +port_session="port-intent-nudge" +run_router "$port_session" "port the BudgetService from v0.1" "$REPO_ROOT" +[[ "$(state_value "$port_session" port_intent)" == "1" ]] \ + || fail "port prompt should set port_intent" +port_out="$(run_grill "$port_session" "port the BudgetService from v0.1" "$REPO_ROOT")" +assert_contains "$port_out" "port / restore / reintroduce work" \ + "port intent should nudge to grep current code first" + +# C2: established project (has .do-it/CONTEXT.md) + Standard code edit emits the +# read-existing nudge; a greenfield repo does not. +brown_project="$TMP_ROOT/brownfield-project" +mkdir -p "$brown_project/.do-it" +printf '# context\n' > "$brown_project/.do-it/CONTEXT.md" +brown_session="brownfield-nudge" +run_router "$brown_session" "Implement the cleanup in src/util.ts" "$brown_project" +[[ "$(state_value "$brown_session" dim_brownfield)" == "1" ]] \ + || fail "project with .do-it/CONTEXT.md should set dim_brownfield" +brown_out="$(run_grill "$brown_session" "Implement the cleanup in src/util.ts" "$brown_project")" +assert_contains "$brown_out" "established codebase" \ + "brownfield Standard code edit should nudge read-existing" + +greenfield_project="$TMP_ROOT/greenfield-project" +mkdir -p "$greenfield_project" +greenfield_session="greenfield-no-nudge" +run_router "$greenfield_session" "Implement the cleanup in src/util.ts" "$greenfield_project" +green_out="$(run_grill "$greenfield_session" "Implement the cleanup in src/util.ts" "$greenfield_project")" +[[ "$green_out" != *"established codebase"* ]] \ + || fail "greenfield repo should not emit the read-existing nudge" + echo "[test-hooks] ok" From 0c1588a3f5f21814ed26563a4d49c55822fc0262 Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 18:13:50 +0800 Subject: [PATCH 06/10] fix(comments): drop stage-history comments and teach comments-lint to catch them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed the "Phase N" / "Cn" task-card labels I had left in the advisory-nudge hook and its tests — exactly the stage-history comments do-it-comments-discipline forbids, since they rot a release or two later. Then closed the gap that let them through: comments-lint's task-ref family now also flags `phase N`, `wave N`, and `BL-NNN` stage markers, not just external tracker refs (issue/pr/ticket/jira). Adds a regression case. Co-Authored-By: Claude Opus 4.8 (1M context) --- hooks/comments-lint.sh | 5 +++-- hooks/grill-prompt.sh | 6 +++--- scripts/test-hooks.sh | 10 +++++----- tests/hooks/comments-lint.test.sh | 17 +++++++++++++++++ 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/hooks/comments-lint.sh b/hooks/comments-lint.sh index 0d23c62..5d53a7a 100755 --- a/hooks/comments-lint.sh +++ b/hooks/comments-lint.sh @@ -253,9 +253,10 @@ if [[ "${FIX_HITS:-0}" -gt 0 ]]; then _record_family "fix-narrative" fi -# 3. Task references +# 3. Task references — external trackers plus do-it stage markers (phase / +# wave / backlog IDs) that rot a release or two after they are written. TASKREF_HITS=$(printf '%s\n' "$FILTERED" \ - | grep -ciE 'issue #|pr #|ticket #|jira-' \ + | grep -ciE 'issue #|pr #|ticket #|jira-|\bBL-[0-9]|\bphase[ -][0-9]|\bwave[ -][0-9]' \ || true) if [[ "${TASKREF_HITS:-0}" -gt 0 ]]; then HITS=$((HITS + TASKREF_HITS)) diff --git a/hooks/grill-prompt.sh b/hooks/grill-prompt.sh index b3c2020..b819b2e 100755 --- a/hooks/grill-prompt.sh +++ b/hooks/grill-prompt.sh @@ -92,8 +92,8 @@ fi # ---- One-shot advisory nudges (work turns only; never block) ---- ADVISORY_TIER="$(do_it_session_state_get "$SESSION_ID" tier)" -# C1: grill ran in a prior turn and durable planning is required, but no plan -# card exists yet — nudge to land it before implementation drifts ahead. +# Plan-card nudge: grill ran in a prior turn and durable planning is required, +# but no plan card exists yet — nudge to land it before implementation drifts ahead. _grilled_prev="$(do_it_session_state_get "$SESSION_ID" grilled)" if [[ "$(do_it_session_state_get "$SESSION_ID" plan_nudged)" != "1" \ && "$(do_it_session_state_get "$SESSION_ID" durable_plan_seen)" == "1" \ @@ -105,7 +105,7 @@ do-it planning: grill has converged and this is durable-plan work, but no .do-it " fi -# C2: existing-codebase / port-restore "understand before you change" nudge. +# Existing-codebase / port-restore "understand before you change" nudge. if [[ "$(do_it_session_state_get "$SESSION_ID" brownfield_nudged)" != "1" ]]; then _port="$(do_it_session_state_get "$SESSION_ID" port_intent)" _brown="$(do_it_session_state_get "$SESSION_ID" dim_brownfield)" diff --git a/scripts/test-hooks.sh b/scripts/test-hooks.sh index da8bedc..d73c32a 100644 --- a/scripts/test-hooks.sh +++ b/scripts/test-hooks.sh @@ -265,10 +265,10 @@ run_router "$withcode_session" "release 我想确认 src/release.ts" withcode_grill="$(run_grill "$withcode_session" "release 我想确认 src/release.ts")" assert_contains "$withcode_grill" "trigger: uncertainty" "Standard + uncertainty + dim_touches_code=1 should still grill" -# ---- Phase 3 advisory nudges (plan-card reliability + existing-codebase) ---- +# ---- advisory nudges (plan-card reliability + existing-codebase) ---- -# C1: after grill on durable-plan work with no plan card, a later grilled turn -# emits a one-shot plan-card nudge. +# Plan-card nudge: after grill on durable-plan work with no plan card, a later +# grilled turn emits a one-shot plan-card nudge. nudge_project="$TMP_ROOT/plan-nudge-project" mkdir -p "$nudge_project" plan_nudge_session="plan-card-nudge" @@ -299,7 +299,7 @@ has_plan_out="$(run_grill "$has_plan_session" "ok implement it" "$nudge_has_plan [[ "$has_plan_out" != *"no .do-it/plans/.md exists yet"* ]] \ || fail "existing plan card should suppress the planning nudge" -# C2: port/restore intent emits a one-shot "grep current code first" nudge. +# Port/restore intent emits a one-shot "grep current code first" nudge. port_session="port-intent-nudge" run_router "$port_session" "port the BudgetService from v0.1" "$REPO_ROOT" [[ "$(state_value "$port_session" port_intent)" == "1" ]] \ @@ -308,7 +308,7 @@ port_out="$(run_grill "$port_session" "port the BudgetService from v0.1" "$REPO_ assert_contains "$port_out" "port / restore / reintroduce work" \ "port intent should nudge to grep current code first" -# C2: established project (has .do-it/CONTEXT.md) + Standard code edit emits the +# Established project (has .do-it/CONTEXT.md) + Standard code edit emits the # read-existing nudge; a greenfield repo does not. brown_project="$TMP_ROOT/brownfield-project" mkdir -p "$brown_project/.do-it" diff --git a/tests/hooks/comments-lint.test.sh b/tests/hooks/comments-lint.test.sh index d060c24..b0afbbb 100755 --- a/tests/hooks/comments-lint.test.sh +++ b/tests/hooks/comments-lint.test.sh @@ -210,6 +210,23 @@ OUT=$(_run_hook "$FILE") _assert_not_contains "owner-tagged TODO ok" "$OUT" "orphan-todo" rm -rf "$DIR" +# ------------------------------------------------------------------------- +echo "Case 10: stage markers (phase / wave / backlog id) → flagged as task-ref" +DIR=$(_setup_repo) +FILE="$DIR/stage.ts" +printf 'function s() { return 1; }\n' > "$FILE" +( cd "$DIR" && git add stage.ts && git commit -q -m base ) >/dev/null 2>&1 +cat > "$FILE" <<'EOF' +function s() { + // Phase 3 advisory wiring; tracked at BL-038, lands in wave 2 + return 1; +} +EOF +OUT=$(_run_hook "$FILE") +_assert_contains "flags stage markers" "$OUT" "system-reminder" +_assert_contains "names task-ref family for stage markers" "$OUT" "task-ref" +rm -rf "$DIR" + # ------------------------------------------------------------------------- echo echo "Summary: $PASS passed, $FAIL failed" From c14f519a3f4148e27241cbeb7ba3988d689ab030 Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 18:15:44 +0800 Subject: [PATCH 07/10] feat: add Restraint principle to router + give CLAUDE.md a managed role MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Encodes the standing "又快又好 / 少做慎做" design principle into do-it so the agent self-applies it instead of it living only in external memory: - do-it-router gains a § Restraint: prefer advisory over blocking, thin/reuse before adding, never build things that grow unbounded, check git intent before deleting, let capabilities auto-fire instead of requiring a /command, match process to risk. - do-it-context now gives CLAUDE.md a formal place: named in the source-of-truth hierarchy (authoritative for how-to-work; current code still wins on what the code is), with a § CLAUDE.md that draws the CLAUDE.md / CONTEXT.md / handbook boundary, makes CLAUDE.md the top of the convention-promotion ladder, and offers an on-demand lean skeleton (additive, never auto-write) that carries the Restraint principle into adopting projects. Regenerated plugin bundle; check-skill-links + validate pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- plugins/do-it/skills/do-it-context/SKILL.md | 53 +++++++++++++++++++-- plugins/do-it/skills/do-it-router/SKILL.md | 21 ++++++++ skills/do-it/do-it-context/SKILL.md | 53 +++++++++++++++++++-- skills/do-it/do-it-router/SKILL.md | 21 ++++++++ 4 files changed, 140 insertions(+), 8 deletions(-) diff --git a/plugins/do-it/skills/do-it-context/SKILL.md b/plugins/do-it/skills/do-it-context/SKILL.md index c3010a4..c8034c0 100644 --- a/plugins/do-it/skills/do-it-context/SKILL.md +++ b/plugins/do-it/skills/do-it-context/SKILL.md @@ -31,11 +31,15 @@ When context sources disagree, use this order: 1. Current code, tests, schemas, manifests, generated source-of-truth scripts, and live command output. -2. `.do-it/CONTEXT.md` for terse repo terms, invariants, and relationships that +2. `CLAUDE.md` (or the host's equivalent root agent-instruction file) for + durable, human-authored conventions and behavioral rules the team chose — + authoritative for *how to work here*, though current code still wins on + *what the code is*. +3. `.do-it/CONTEXT.md` for terse repo terms, invariants, and relationships that code does not express accessibly. -3. Current plan, grill log, task card, or issue for the active work. -4. README, docs, ADRs, and maintenance guides. -5. Memory, old reports, previous worker summaries, and external sources. +4. Current plan, grill log, task card, or issue for the active work. +5. README, docs, ADRs, and maintenance guides. +6. Memory, old reports, previous worker summaries, and external sources. Lower layers can point to what to inspect, but they do not override current repo truth. @@ -87,6 +91,47 @@ Roughly quarterly, or when the file crosses ~200 lines: 2. Find lines that no longer match the code; rewrite or delete. 3. Find lines that have moved into the type system / schema and can now be deleted. +## CLAUDE.md (durable conventions) + +`CLAUDE.md` (or the host's equivalent root instruction file) holds the durable, +human-owned conventions for how agents work in this project — coding standards, +review bar, do/don't rules, restraint principles. do-it reads it before grill +and planning. It differs from the other do-it homes: + +- **CLAUDE.md** — durable *behavioral* conventions and team rules (human-owned, + rarely changes). +- **`.do-it/CONTEXT.md`** — per-session *factual* sediment (terms, invariants, + relationships) that `do-it-grill` writes. +- **`.do-it/handbook/`** — structural project docs (architecture, code map, + glossary, backlog). + +CLAUDE.md is the top of the convention ladder: a rule that has held across +sessions and is about *how to work* (not a project fact) graduates here from +`.do-it/CONTEXT.md`. + +When the user asks to set up or tidy CLAUDE.md, scaffold a lean skeleton on +demand — never auto-write, and never overwrite an existing CLAUDE.md (additive, +like the handbook bootstrap). A useful skeleton: + +```markdown +# — agent conventions + +## Restraint +- Prefer advisory nudges over write-blocking gates. +- Reuse or thin an existing module before adding a new one; do not build things + that grow unbounded. +- Read existing structure and git intent before deleting or rewriting. + +## Conventions +- + +## Review bar +- +``` + +Keep it short — CLAUDE.md is read every turn, so it competes for context budget. +Detail belongs in `.do-it/handbook/` or `docs/`. + ## Domain Glossary Mode (Standard+) The sediment workflow above is the Light path — one line per clarified term. For diff --git a/plugins/do-it/skills/do-it-router/SKILL.md b/plugins/do-it/skills/do-it-router/SKILL.md index ccda0b4..702798c 100644 --- a/plugins/do-it/skills/do-it-router/SKILL.md +++ b/plugins/do-it/skills/do-it-router/SKILL.md @@ -56,6 +56,27 @@ A failure, error, surprising result, or red flag is a clue to investigate — no This principle binds the parent agent and every subagent. `do-it-debugging`, `do-it-fix-loop`, and `do-it-verification-gate` enforce it at their stages; reviewers treat a cover-up as a Blocking finding. +## Restraint + +do-it favors the smallest change that earns its keep — fast *and* good, not more +ceremony. When extending the system or planning a change inside a project, apply +these by default: + +- Prefer advisory nudges and side-channels over write-blocking gates: remind in + the moment, do not stall the work before it starts. +- Thin or reuse an existing skill before adding a new one. Do not build anything + that grows unbounded with use (anti-pattern lists, auto-collected findings, + ever-longer checklists); ask "will this keep growing?" before adding a rule. +- Before deleting code, a field, or a doc that looks unused, read its git history + and original intent. "No current consumer" is a reason to investigate why it + was built, not a licence to delete. +- Let capabilities surface automatically at the right moment instead of requiring + the user to remember a `/command`. +- Match process to risk, not habit: small work stays Light; only real risk earns + planning, review, and proof. + +This binds how do-it itself evolves and how it shapes changes inside a project. + ## Orthogonal Dimensions In addition to the single tier label, the router writes 5 boolean dimensions into per-session state. They narrow *intensity*, not tier itself: a Standard task can still be `breaks_interface=1` and a downstream skill MAY upgrade its review or drill posture accordingly. diff --git a/skills/do-it/do-it-context/SKILL.md b/skills/do-it/do-it-context/SKILL.md index c3010a4..c8034c0 100644 --- a/skills/do-it/do-it-context/SKILL.md +++ b/skills/do-it/do-it-context/SKILL.md @@ -31,11 +31,15 @@ When context sources disagree, use this order: 1. Current code, tests, schemas, manifests, generated source-of-truth scripts, and live command output. -2. `.do-it/CONTEXT.md` for terse repo terms, invariants, and relationships that +2. `CLAUDE.md` (or the host's equivalent root agent-instruction file) for + durable, human-authored conventions and behavioral rules the team chose — + authoritative for *how to work here*, though current code still wins on + *what the code is*. +3. `.do-it/CONTEXT.md` for terse repo terms, invariants, and relationships that code does not express accessibly. -3. Current plan, grill log, task card, or issue for the active work. -4. README, docs, ADRs, and maintenance guides. -5. Memory, old reports, previous worker summaries, and external sources. +4. Current plan, grill log, task card, or issue for the active work. +5. README, docs, ADRs, and maintenance guides. +6. Memory, old reports, previous worker summaries, and external sources. Lower layers can point to what to inspect, but they do not override current repo truth. @@ -87,6 +91,47 @@ Roughly quarterly, or when the file crosses ~200 lines: 2. Find lines that no longer match the code; rewrite or delete. 3. Find lines that have moved into the type system / schema and can now be deleted. +## CLAUDE.md (durable conventions) + +`CLAUDE.md` (or the host's equivalent root instruction file) holds the durable, +human-owned conventions for how agents work in this project — coding standards, +review bar, do/don't rules, restraint principles. do-it reads it before grill +and planning. It differs from the other do-it homes: + +- **CLAUDE.md** — durable *behavioral* conventions and team rules (human-owned, + rarely changes). +- **`.do-it/CONTEXT.md`** — per-session *factual* sediment (terms, invariants, + relationships) that `do-it-grill` writes. +- **`.do-it/handbook/`** — structural project docs (architecture, code map, + glossary, backlog). + +CLAUDE.md is the top of the convention ladder: a rule that has held across +sessions and is about *how to work* (not a project fact) graduates here from +`.do-it/CONTEXT.md`. + +When the user asks to set up or tidy CLAUDE.md, scaffold a lean skeleton on +demand — never auto-write, and never overwrite an existing CLAUDE.md (additive, +like the handbook bootstrap). A useful skeleton: + +```markdown +# — agent conventions + +## Restraint +- Prefer advisory nudges over write-blocking gates. +- Reuse or thin an existing module before adding a new one; do not build things + that grow unbounded. +- Read existing structure and git intent before deleting or rewriting. + +## Conventions +- + +## Review bar +- +``` + +Keep it short — CLAUDE.md is read every turn, so it competes for context budget. +Detail belongs in `.do-it/handbook/` or `docs/`. + ## Domain Glossary Mode (Standard+) The sediment workflow above is the Light path — one line per clarified term. For diff --git a/skills/do-it/do-it-router/SKILL.md b/skills/do-it/do-it-router/SKILL.md index ccda0b4..702798c 100644 --- a/skills/do-it/do-it-router/SKILL.md +++ b/skills/do-it/do-it-router/SKILL.md @@ -56,6 +56,27 @@ A failure, error, surprising result, or red flag is a clue to investigate — no This principle binds the parent agent and every subagent. `do-it-debugging`, `do-it-fix-loop`, and `do-it-verification-gate` enforce it at their stages; reviewers treat a cover-up as a Blocking finding. +## Restraint + +do-it favors the smallest change that earns its keep — fast *and* good, not more +ceremony. When extending the system or planning a change inside a project, apply +these by default: + +- Prefer advisory nudges and side-channels over write-blocking gates: remind in + the moment, do not stall the work before it starts. +- Thin or reuse an existing skill before adding a new one. Do not build anything + that grows unbounded with use (anti-pattern lists, auto-collected findings, + ever-longer checklists); ask "will this keep growing?" before adding a rule. +- Before deleting code, a field, or a doc that looks unused, read its git history + and original intent. "No current consumer" is a reason to investigate why it + was built, not a licence to delete. +- Let capabilities surface automatically at the right moment instead of requiring + the user to remember a `/command`. +- Match process to risk, not habit: small work stays Light; only real risk earns + planning, review, and proof. + +This binds how do-it itself evolves and how it shapes changes inside a project. + ## Orthogonal Dimensions In addition to the single tier label, the router writes 5 boolean dimensions into per-session state. They narrow *intensity*, not tier itself: a Standard task can still be `breaks_interface=1` and a downstream skill MAY upgrade its review or drill posture accordingly. From 45de02b9c9ba4247c46c73739e2ae8402d944155 Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 18:19:29 +0800 Subject: [PATCH 08/10] chore(release): do-it 0.11.0 Bumps version across package.json, manifest.json, both plugin.json files, and the marketplace manifest; adds the 0.10.x migration entry; writes the 0.11.0 CHANGELOG covering the macOS CI fix, the handbook slim-down, the three skill consolidations, the Restraint principle, CLAUDE.md's managed role, and the plan-card / existing-code advisory nudges. Regenerated index.json + plugin bundle. Verified: simulated 0.10.0 -> 0.11.0 upgrade migrates state, removes the three deprecated skills, updates the changed hooks, and reports doctor drift: 0; fresh install clean on both codex and claude targets; npm test green; npm pack lists the expected files. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- CHANGELOG.md | 40 +++++++++++++++++++++++++ index.json | 2 +- manifest.json | 6 +++- package.json | 2 +- plugins/do-it/.codex-plugin/plugin.json | 2 +- 7 files changed, 50 insertions(+), 6 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 6e4b3e2..df854c3 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -8,7 +8,7 @@ { "name": "do-it", "description": "Workflow discipline plugin: skills auto-trigger via hooks; no slash commands required.", - "version": "0.10.0", + "version": "0.11.0", "source": "./", "author": { "name": "tdwhere123" diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index b144884..9de267c 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "do-it", "description": "Workflow discipline plugin for Claude Code: tier routing, premise grilling, verification gates. Skills auto-trigger via hooks—no slash commands required.", - "version": "0.10.0", + "version": "0.11.0", "author": { "name": "tdwhere123" }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 5594c7e..6e2bc8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,46 @@ - No unreleased changes. +## 0.11.0 + +### Fixed + +- macOS CI: the `anti-patterns-lint` hook is now BSD-portable. The no-consumer + check uses git grep's own `-w` word match instead of a GNU `\b` regex, and + file paths are canonicalized with `pwd -P` before repo-relative stripping so + the `/var`→`/private/var` symlink no longer breaks self-exclusion. The macOS + hook-test job was failing on these for three releases. + +### Changed + +- Handbook slimmed from 12 templates to 7 project-truth files. The five process + docs that duplicated skills were removed: the task-card layout now lives in + `do-it-planning`, the review protocol in `do-it-review-loop`, the dispatch + contract in `do-it-subagent-orchestration`, the execution pipeline in + `do-it-router`, and the handbook maintenance rules in the `do-it-handbook` + skill. +- Three low-utilization skills consolidated (23 → 20): `do-it-grill-log` folded + into `do-it-grill` (Grill Log Artifact), `do-it-domain-language` into + `do-it-context` (Domain Glossary Mode), and the optional `do-it-visual-planning` + into `do-it-planning` (Visual Aids); the visual-planning browser companion is + retired. Existing installs remove the deprecated skills on upgrade. +- `do-it-router` gains a § Restraint principle: advisory over blocking, reuse + over add, no unbounded libraries, check git intent before deleting, and + capabilities that auto-fire instead of requiring a `/command`. +- `do-it-context` gives `CLAUDE.md` a formal role in the source-of-truth + hierarchy, draws the `CLAUDE.md` / `CONTEXT.md` / handbook boundary, and can + scaffold a lean `CLAUDE.md` on demand (additive, never auto-write). + +### Added + +- Advisory nudges (one-shot, never block): after grill on durable-plan work with + no plan card, a reminder to land the plan card before implementation drifts + ahead; on established projects (`.do-it/CONTEXT.md` or handbook present) or + port/restore prompts, a reminder to read existing structure / grep current + code first. +- `comments-lint` now flags `phase N`, `wave N`, and `BL-NNN` stage markers as + `task-ref` comments. + ## 0.10.0 ### Added diff --git a/index.json b/index.json index cf49fc3..4483459 100644 --- a/index.json +++ b/index.json @@ -1,5 +1,5 @@ { - "version": "0.10.0", + "version": "0.11.0", "generated_at": "2026-05-24T15:12:54.935Z", "package": "@tdwhere/do-it", "repository": "https://github.com/tdwhere123/do-it", diff --git a/manifest.json b/manifest.json index f801f09..7e07b60 100644 --- a/manifest.json +++ b/manifest.json @@ -1,5 +1,5 @@ { - "version": "0.10.0", + "version": "0.11.0", "migrations": [ { "from": "0.4.x", @@ -24,6 +24,10 @@ { "from": "0.9.x", "actions": [] + }, + { + "from": "0.10.x", + "actions": [] } ], "targets": { diff --git a/package.json b/package.json index 5e34777..a68fa8a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tdwhere/do-it", - "version": "0.10.0", + "version": "0.11.0", "description": "Installable AI coding workflow for Codex and Claude Code with risk-based routing, scoped sub-agents, and evidence-backed completion.", "type": "module", "license": "MIT", diff --git a/plugins/do-it/.codex-plugin/plugin.json b/plugins/do-it/.codex-plugin/plugin.json index a098c03..4b77907 100644 --- a/plugins/do-it/.codex-plugin/plugin.json +++ b/plugins/do-it/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "do-it", - "version": "0.10.0", + "version": "0.11.0", "description": "Installable AI coding workflow for Codex and Claude Code with risk-based routing, scoped sub-agents, and evidence-backed completion.", "author": { "name": "tdwhere123" From 9776899c889807c5e589da21cc1ba5de416bd3f8 Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 18:39:50 +0800 Subject: [PATCH 09/10] =?UTF-8?q?fix(review):=20resolve=20review=20finding?= =?UTF-8?q?s=20=E2=80=94=20stale=20docs,=20port=20over-trigger,=20test=20g?= =?UTF-8?q?aps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review-loop batch fixes (no Blocking found; these are the Important/Opportunity findings): - Stale skill inventory swept across human docs after the skill merges: README.md and README.zh-CN.md (the latter ships in the npm tarball) now say 20 skills and drop every do-it-visual-planning reference and the dead --with-optional example; docs/upstream-map.md external-idea rows repoint do-it-domain-language -> do-it-context; docs/maintenance.md drops the visual-planning example. - anti-patterns-lint: added a no-consumer regression case proving the git grep `-w` word match rejects a substring-only neighbour (Widget vs WidgetFactory) — the exact invariant the BSD fix relies on; and canonicalized PROJECT_ROOT with pwd -P so the advisory's display path stays repo-relative on symlinked CWDs. - router port_intent tightened: dropped the bare 恢复 / restore the / bring back forms that over-fired on runtime phrases ("恢复正常", "restore the DB"); kept the precise port / reintroduce / restore-legacy forms. npm test green (anti-patterns 16, comments 17, hooks ok, install 19); lint-hooks clean; no build drift. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 11 ++++------- README.zh-CN.md | 7 +++---- docs/maintenance.md | 4 ++-- docs/upstream-map.md | 4 ++-- hooks/anti-patterns-lint.sh | 3 +++ hooks/router.sh | 2 +- tests/hooks/anti-patterns-lint.test.sh | 23 +++++++++++++++++++++++ 7 files changed, 38 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 32d971e..2d10d9d 100644 --- a/README.md +++ b/README.md @@ -112,8 +112,7 @@ CODEX_HOME=/tmp/do-it-plugin-test codex plugin marketplace add /path/to/do-it ``` The Codex plugin bundle lives at `plugins/do-it/` and is generated from -`manifest.json`. It includes 23 skills and 23 agents, including optional -`do-it-visual-planning`. +`manifest.json`. It includes 20 skills and 23 agents. For v1, pair plugin installation with `do-it setup` when you need enforced automatic hooks. Local `codex features list` currently reports @@ -137,9 +136,8 @@ do-it doctor --target=claude ``` The Claude target installs to `~/.claude/` by default; override with -`CLAUDE_PLUGIN_ROOT_OVERRIDE`. Optional skills such as -`do-it-visual-planning` are excluded by default; opt in with -`--with-optional`. +`CLAUDE_PLUGIN_ROOT_OVERRIDE`. The `--with-optional` flag installs any manifest +skills marked optional (none are marked optional in 0.11.0). ## What It Installs @@ -322,8 +320,7 @@ emitting valid JSON without `jq`. Stale session directories are pruned after 7 days. `do-it-router` gains an `Integrity` section — a failure is a clue to trace, not a symptom to hide — referenced by `do-it-debugging`, `do-it-fix-loop`, `do-it-verification-gate`, and the subagent dispatch -contract. `do-it-visual-planning` ships `plan-card` / `review-report` scenario -templates, and the CI test job now also runs on macOS. If a machine has a +contract. The CI test job now also runs on macOS. If a machine has a cached `0.8.0` plugin, reinstall or refresh so the host loads the new hook and skill files. diff --git a/README.zh-CN.md b/README.zh-CN.md index 2842b5a..d8e345a 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -102,7 +102,7 @@ CODEX_HOME=/tmp/do-it-plugin-test codex plugin marketplace add /path/to/do-it ``` Codex plugin bundle 位于 `plugins/do-it/`,由 `manifest.json` 生成。 -它包含 23 个 skill 和 23 个 agent,包括可选的 `do-it-visual-planning`。 +它包含 20 个 skill 和 23 个 agent。 v1 阶段,如果你需要强制自动 hooks,请把 plugin 安装和 `do-it setup` 配套使用。 当前本机 `codex features list` 显示 `codex_hooks=true`、`plugins=true`、 @@ -125,7 +125,7 @@ do-it doctor --target=claude ``` Claude target 默认装到 `~/.claude/`;用 `CLAUDE_PLUGIN_ROOT_OVERRIDE` 改根目录。 -可选 skill(如 `do-it-visual-planning`)默认不装,加 `--with-optional` 才装。 +`--with-optional` 会安装 manifest 中标记为 optional 的 skill(0.11.0 没有 optional skill)。 ## 它会安装什么 @@ -287,8 +287,7 @@ reasoning-effort 字段,Claude 生成的 agent 默认继承当前宿主模型 `do_it_emit_context` 在没有 `jq` 时仍能输出合法 JSON。陈旧 session 目录会在 7 天后清理。`do-it-router` 新增 `Integrity` 段 —— 失败是要追根因的线索, 不是要掩盖的症状 —— 被 `do-it-debugging`、`do-it-fix-loop`、 -`do-it-verification-gate` 和子智能体派发合约引用。`do-it-visual-planning` -新增 `plan-card` / `review-report` 场景模板,CI 测试任务现在也跑 macOS。 +`do-it-verification-gate` 和子智能体派发合约引用。CI 测试任务现在也跑 macOS。 若某台机器缓存了 `0.8.0` 插件,请重装或刷新,让宿主加载新的 hook 和 skill。 ## 升级到 0.8.0 diff --git a/docs/maintenance.md b/docs/maintenance.md index 63f97f3..0bef671 100644 --- a/docs/maintenance.md +++ b/docs/maintenance.md @@ -110,8 +110,8 @@ When a skill changes, decide which kind of update it is: - do-it rewrite - do-it compatibility adapter that preserves a workflow idea while changing the installed name and wording -- optional auxiliary support, such as visual planning, that is installed but not - part of the default tier flow +- optional auxiliary support that is installed but not part of the default tier + flow (no skills are marked optional in 0.11.0) For either kind: diff --git a/docs/upstream-map.md b/docs/upstream-map.md index 1da0ace..69558a0 100644 --- a/docs/upstream-map.md +++ b/docs/upstream-map.md @@ -45,8 +45,8 @@ The do-it skills are rewrites, not vendored copies. Useful ideas from | `improve-codebase-architecture` | `do-it-architecture-scan` | Friction-led exploration, shallow-module detection, deep-module candidates, coupling and testability impact. | | `tdd` | `do-it-tdd` | Public-interface behavior tests and one RED/GREEN vertical slice at a time. | | `triage-issue` | `do-it-debugging` | Manifestation, code path, root cause, minimal fix, and TDD fix plan. | -| `qa` | `do-it-review-loop`, `do-it-domain-language` | User-facing durable issues, concise reproduction, and project domain language. | -| `ubiquitous-language`, `domain-model` | `do-it-domain-language` | Canonical glossary, ambiguity flags, code/docs contradiction checks, and lightweight ADR triggers. | +| `qa` | `do-it-review-loop`, `do-it-context` | User-facing durable issues, concise reproduction, and project domain language. | +| `ubiquitous-language`, `domain-model` | `do-it-context` § Domain Glossary Mode | Canonical glossary, ambiguity flags, code/docs contradiction checks, and lightweight ADR triggers. | | `write-a-skill` | `do-it-skill-authoring` | Concise SKILL.md, progressive disclosure, optional resources, and validation. | Excluded or adapter-only ideas remain outside the core install flow unless a diff --git a/hooks/anti-patterns-lint.sh b/hooks/anti-patterns-lint.sh index a30e729..8eaf7e9 100755 --- a/hooks/anti-patterns-lint.sh +++ b/hooks/anti-patterns-lint.sh @@ -315,6 +315,9 @@ fi PROJECT_ROOT="$(do_it_project_root "$CWD")" PROJECT_ROOT="${PROJECT_ROOT%/}" +# FILE_PATH was symlink-resolved with pwd -P above; resolve PROJECT_ROOT the same +# way so the display strip still works when CWD is a symlinked path (macOS). +PROJECT_ROOT="$(cd "$PROJECT_ROOT" 2>/dev/null && pwd -P || printf '%s' "$PROJECT_ROOT")" case "$FILE_PATH" in "$PROJECT_ROOT"/*) DISPLAY_PATH="${FILE_PATH#"$PROJECT_ROOT"/}" ;; *) DISPLAY_PATH="$FILE_PATH" ;; diff --git a/hooks/router.sh b/hooks/router.sh index c78b6dc..f1d9049 100755 --- a/hooks/router.sh +++ b/hooks/router.sh @@ -140,7 +140,7 @@ fi do_it_session_state_set "$SESSION_ID" dim_brownfield "$brownfield" port_intent=0 case "$(do_it_lc "$PROMPT")" in - *"移植"*|*"迁移回"*|*"重新引入"*|*"恢复"*|*"reintroduce"*|*"re-introduce"*|*"port from"*|*"port over"*|*"port the"*|*"restore the"*|*"bring back"*) + *"移植"*|*"迁移回"*|*"重新引入"*|*"恢复历史"*|*"恢复旧"*|*"恢复以前"*|*"reintroduce"*|*"re-introduce"*|*"port from"*|*"port over"*|*"port the"*|*"restore legacy"*|*"restore the old"*|*"bring back the"*) port_intent=1 ;; esac do_it_session_state_set "$SESSION_ID" port_intent "$port_intent" diff --git a/tests/hooks/anti-patterns-lint.test.sh b/tests/hooks/anti-patterns-lint.test.sh index a604d6f..a011078 100644 --- a/tests/hooks/anti-patterns-lint.test.sh +++ b/tests/hooks/anti-patterns-lint.test.sh @@ -162,6 +162,29 @@ OUT=$(_run_hook "$FILE") _assert_not_contains "no-consumer silent for referenced symbol" "$OUT" "- no-consumer:" rm -rf "$DIR" +# ------------------------------------------------------------------------- +echo "Case 4b: no-consumer with only a substring neighbour — word match required" +DIR=$(_setup_repo) +FILE="$DIR/util.ts" +cat > "$FILE" <<'EOF' +// initial +EOF +# Another file references WidgetFactory (Widget is a substring); a whole-word +# match must NOT count it as a consumer of the exported `Widget`. +cat > "$DIR/consumer.ts" <<'EOF' +import { WidgetFactory } from './factory'; +console.log(WidgetFactory()); +EOF +( cd "$DIR" && git add . && git commit -q -m base ) >/dev/null 2>&1 +cat > "$FILE" <<'EOF' +// initial +export function Widget() { return 1; } +EOF +OUT=$(_run_hook "$FILE") +_assert_contains "no-consumer flags symbol with only a substring neighbour" "$OUT" "- no-consumer:" +_assert_contains "names the orphan symbol Widget" "$OUT" "Widget" +rm -rf "$DIR" + # ------------------------------------------------------------------------- echo "Case 5: copy-paste hit — ≥5-line block duplicated in same directory" DIR=$(_setup_repo) From 1f28bfa3dc897e976e4ff0677a70bfee847d47b7 Mon Sep 17 00:00:00 2001 From: tdwhere123 Date: Fri, 5 Jun 2026 19:15:41 +0800 Subject: [PATCH 10/10] feat(planning): keep + redesign the visual companion under do-it-planning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The visual-planning merge kept the SKILL folded into do-it-planning but had retired the browser companion. Per the owner, the render capability stays (only relocated) and the plain templates get a visual upgrade: - Relocated the visual companion (static server + helper + plan-card / review-report render templates) from the removed do-it-visual-planning skill to skills/do-it/do-it-planning/{scripts,templates,references}. The server uses __dirname + a /tmp session dir, so the move needs no path changes. - Redesigned frame-template.html: an editorial "dossier" aesthetic (Newsreader + IBM Plex Mono + Inter Tight, aged-ivory light / slate-navy dark themes, dot grid, ruled section margins, refined option/card/finding/table states). The full class/id contract consumed by helper.js + server.cjs is preserved, and it was rendered and verified in both color schemes. - do-it-planning § Visual Aids now fully preserves the capability (compare options + recommendation, feed into interface-drill / architecture-scan, multi-agent sequencing) and points at the optional companion. - manifest deprecation reason + CHANGELOG updated (companion relocated, not retired). npm test green; check-skill-links + validate pass; plugin bundle regenerated. Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 5 +- manifest.json | 2 +- plugins/do-it/skills/do-it-planning/SKILL.md | 21 +- .../references/visual-companion.md | 267 ++++++ .../scripts/frame-template.html | 855 ++++++++++++++++++ .../skills/do-it-planning/scripts/helper.js | 98 ++ .../skills/do-it-planning/scripts/server.cjs | 354 ++++++++ .../do-it-planning/scripts/start-server.sh | 148 +++ .../do-it-planning/scripts/stop-server.sh | 56 ++ .../do-it-planning/templates/plan-card.html | 56 ++ .../templates/review-report.html | 47 + skills/do-it/do-it-planning/SKILL.md | 21 +- .../references/visual-companion.md | 267 ++++++ .../scripts/frame-template.html | 855 ++++++++++++++++++ skills/do-it/do-it-planning/scripts/helper.js | 98 ++ .../do-it/do-it-planning/scripts/server.cjs | 354 ++++++++ .../do-it-planning/scripts/start-server.sh | 148 +++ .../do-it-planning/scripts/stop-server.sh | 56 ++ .../do-it-planning/templates/plan-card.html | 56 ++ .../templates/review-report.html | 47 + 20 files changed, 3798 insertions(+), 13 deletions(-) create mode 100644 plugins/do-it/skills/do-it-planning/references/visual-companion.md create mode 100644 plugins/do-it/skills/do-it-planning/scripts/frame-template.html create mode 100644 plugins/do-it/skills/do-it-planning/scripts/helper.js create mode 100644 plugins/do-it/skills/do-it-planning/scripts/server.cjs create mode 100755 plugins/do-it/skills/do-it-planning/scripts/start-server.sh create mode 100755 plugins/do-it/skills/do-it-planning/scripts/stop-server.sh create mode 100644 plugins/do-it/skills/do-it-planning/templates/plan-card.html create mode 100644 plugins/do-it/skills/do-it-planning/templates/review-report.html create mode 100644 skills/do-it/do-it-planning/references/visual-companion.md create mode 100644 skills/do-it/do-it-planning/scripts/frame-template.html create mode 100644 skills/do-it/do-it-planning/scripts/helper.js create mode 100644 skills/do-it/do-it-planning/scripts/server.cjs create mode 100755 skills/do-it/do-it-planning/scripts/start-server.sh create mode 100755 skills/do-it/do-it-planning/scripts/stop-server.sh create mode 100644 skills/do-it/do-it-planning/templates/plan-card.html create mode 100644 skills/do-it/do-it-planning/templates/review-report.html diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e2bc8a..247f256 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,8 +25,9 @@ - Three low-utilization skills consolidated (23 → 20): `do-it-grill-log` folded into `do-it-grill` (Grill Log Artifact), `do-it-domain-language` into `do-it-context` (Domain Glossary Mode), and the optional `do-it-visual-planning` - into `do-it-planning` (Visual Aids); the visual-planning browser companion is - retired. Existing installs remove the deprecated skills on upgrade. + into `do-it-planning` (Visual Aids); the visual companion (local browser + server + render templates) moves under `do-it-planning` and its templates were + visually redesigned. Existing installs remove the deprecated skills on upgrade. - `do-it-router` gains a § Restraint principle: advisory over blocking, reuse over add, no unbounded libraries, check git intent before deleting, and capabilities that auto-fire instead of requiring a `/command`. diff --git a/manifest.json b/manifest.json index 7e07b60..0b0d4b1 100644 --- a/manifest.json +++ b/manifest.json @@ -386,7 +386,7 @@ "legacyHashes": [ "d9a5232ded1eb64340d1698cce5e55b6e6c0a93046ce0f77458df0f8faa0936a" ], - "reason": "auxiliary skill folded into do-it-planning as the Visual Aids section; browser companion retired" + "reason": "auxiliary skill folded into do-it-planning as the Visual Aids section; visual companion relocated under do-it-planning" } ], "skills": [ diff --git a/plugins/do-it/skills/do-it-planning/SKILL.md b/plugins/do-it/skills/do-it-planning/SKILL.md index 65773e3..ca04004 100644 --- a/plugins/do-it/skills/do-it-planning/SKILL.md +++ b/plugins/do-it/skills/do-it-planning/SKILL.md @@ -226,11 +226,22 @@ for a code-facing plan; they go stale faster than domain decisions. When seeing an option is materially clearer than reading it — UI layout alternatives, architecture/data-flow diagrams, before/after states, side-by-side -interface shapes — sketch it under `.do-it/visual//` (descriptive -filenames like `option-a-flow.md`, `api-boundary.svg`). Treat these as auxiliary -evidence, not durable plan output: the decision still lands in the plan card. -Skip visuals for text-only decisions, one-line questions, or where a table is -clearer. A visual aid never promotes a task's tier by itself. +interface shapes, or visual task sequencing for multi-agent work — produce the +smallest useful artifact under `.do-it/visual//` (descriptive filenames +like `option-a-flow.md`, `api-boundary.svg`), compare 2-3 options with explicit +tradeoffs, and name a recommendation. Feed that decision back into this plan card +(or `do-it-interface-drill` / `do-it-architecture-scan` when it shapes a contract +or boundary). + +Treat visuals as auxiliary evidence, not durable plan output: the decision still +lands in the plan card. Skip them for text-only decisions, one-line questions, or +where a table is clearer. A visual aid never promotes a task's tier by itself. + +For browser-based side-by-side comparison, this skill ships an optional local +visual companion under `scripts/` (a small static server plus `plan-card` / +`review-report` render templates). Load `references/visual-companion.md` only +when you actually need the browser render; for everything else, file-based +sketches in `.do-it/visual/` are enough. ## Output Shape diff --git a/plugins/do-it/skills/do-it-planning/references/visual-companion.md b/plugins/do-it/skills/do-it-planning/references/visual-companion.md new file mode 100644 index 0000000..393118e --- /dev/null +++ b/plugins/do-it/skills/do-it-planning/references/visual-companion.md @@ -0,0 +1,267 @@ +# Visual Companion Guide + +Browser-based do-it visual planning companion for showing mockups, diagrams, and options. + +## When to Use + +Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?** + +**Use the browser** when the content itself is visual: + +- **UI mockups** — wireframes, layouts, navigation structures, component designs +- **Architecture diagrams** — system components, data flow, relationship maps +- **Side-by-side visual comparisons** — comparing two layouts, two color schemes, two design directions +- **Design polish** — when the question is about look and feel, spacing, visual hierarchy +- **Spatial relationships** — state machines, flowcharts, entity relationships rendered as diagrams + +**Use the terminal** when the content is text or tabular: + +- **Requirements and scope questions** — "what does X mean?", "which features are in scope?" +- **Conceptual A/B/C choices** — picking between approaches described in words +- **Tradeoff lists** — pros/cons, comparison tables +- **Technical decisions** — API design, data modeling, architectural approach selection +- **Clarifying questions** — anything where the answer is words, not a visual preference + +A question *about* a UI topic is not automatically a visual question. "What kind of wizard do you want?" is conceptual — use the terminal. "Which of these wizard layouts feels right?" is visual — use the browser. + +## How It Works + +The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to `screen_dir`, the user sees it in their browser and can click to select options. Selections are recorded to `state_dir/events` that you read on your next turn. + +**Content fragments vs full documents:** If your HTML file starts with `/.do-it/visual/` for the session directory. + +**Note:** Pass the project root as `--project-dir` so mockups persist in `.do-it/visual/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. The do-it repository ignores `.do-it/`; downstream projects should do the same before using persistent visual sessions. + +**Launching the server:** + +```bash +# Codex-first default. The script auto-detects CODEX_CI and switches to +# foreground mode when the environment would reap detached processes. +scripts/start-server.sh --project-dir /path/to/project +``` + +Other runtimes must keep the server alive across turns. If the environment +reaps detached processes, use `--foreground` and launch the command with that +runtime's background execution mechanism. + +If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host: + +```bash +scripts/start-server.sh \ + --project-dir /path/to/project \ + --host 0.0.0.0 \ + --url-host localhost +``` + +Use `--url-host` to control what hostname is printed in the returned URL JSON. + +## The Loop + +1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`: + - Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity. + - Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html` + - **Never reuse filenames** — each screen gets a fresh file + - Use the normal file-editing tool; avoid cat/heredoc writes that dump noisy + HTML into terminal output. + - Server automatically serves the newest file + +2. **Tell user what to expect and end your turn:** + - Remind them of the URL (every step, not just first) + - Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage") + - Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like." + +3. **On your next turn** — after the user responds in the terminal: + - Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines + - Merge with the user's terminal text to get the full picture + - The terminal message is the primary feedback; `state_dir/events` provides structured interaction data + +4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated. + +5. **Unload when returning to terminal** — when the next step doesn't need the browser (e.g., a clarifying question, a tradeoff discussion), push a waiting screen to clear the stale content: + + ```html + +
+

Continuing in terminal...

+
+ ``` + + This prevents the user from staring at a resolved choice while the conversation has moved on. When the next visual question comes up, push a new content file as usual. + +6. Repeat until done. + +## Writing Content Fragments + +Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure). + +**Minimal example:** + +```html +

Which layout works better?

+

Consider readability and visual hierarchy

+ +
+
+
A
+
+

Single Column

+

Clean, focused reading experience

+
+
+
+
B
+
+

Two Column

+

Sidebar navigation with main content

+
+
+
+``` + +That's it. No ``, no CSS, no `'; + +// ========== Helper Functions ========== + +function isFullDocument(html) { + const trimmed = html.trimStart().toLowerCase(); + return trimmed.startsWith('', content); +} + +function getNewestScreen() { + const files = fs.readdirSync(CONTENT_DIR) + .filter(f => f.endsWith('.html')) + .map(f => { + const fp = path.join(CONTENT_DIR, f); + return { path: fp, mtime: fs.statSync(fp).mtime.getTime() }; + }) + .sort((a, b) => b.mtime - a.mtime); + return files.length > 0 ? files[0].path : null; +} + +// ========== HTTP Request Handler ========== + +function handleRequest(req, res) { + touchActivity(); + if (req.method === 'GET' && req.url === '/') { + const screenFile = getNewestScreen(); + let html = screenFile + ? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8')) + : WAITING_PAGE; + + if (html.includes('')) { + html = html.replace('', helperInjection + '\n'); + } else { + html += helperInjection; + } + + res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); + res.end(html); + } else if (req.method === 'GET' && req.url.startsWith('/files/')) { + const fileName = req.url.slice(7); + const filePath = path.join(CONTENT_DIR, path.basename(fileName)); + if (!fs.existsSync(filePath)) { + res.writeHead(404); + res.end('Not found'); + return; + } + const ext = path.extname(filePath).toLowerCase(); + const contentType = MIME_TYPES[ext] || 'application/octet-stream'; + res.writeHead(200, { 'Content-Type': contentType }); + res.end(fs.readFileSync(filePath)); + } else { + res.writeHead(404); + res.end('Not found'); + } +} + +// ========== WebSocket Connection Handling ========== + +const clients = new Set(); + +function handleUpgrade(req, socket) { + const key = req.headers['sec-websocket-key']; + if (!key) { socket.destroy(); return; } + + const accept = computeAcceptKey(key); + socket.write( + 'HTTP/1.1 101 Switching Protocols\r\n' + + 'Upgrade: websocket\r\n' + + 'Connection: Upgrade\r\n' + + 'Sec-WebSocket-Accept: ' + accept + '\r\n\r\n' + ); + + let buffer = Buffer.alloc(0); + clients.add(socket); + + socket.on('data', (chunk) => { + buffer = Buffer.concat([buffer, chunk]); + while (buffer.length > 0) { + let result; + try { + result = decodeFrame(buffer); + } catch (e) { + socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); + clients.delete(socket); + return; + } + if (!result) break; + buffer = buffer.slice(result.bytesConsumed); + + switch (result.opcode) { + case OPCODES.TEXT: + handleMessage(result.payload.toString()); + break; + case OPCODES.CLOSE: + socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); + clients.delete(socket); + return; + case OPCODES.PING: + socket.write(encodeFrame(OPCODES.PONG, result.payload)); + break; + case OPCODES.PONG: + break; + default: { + const closeBuf = Buffer.alloc(2); + closeBuf.writeUInt16BE(1003); + socket.end(encodeFrame(OPCODES.CLOSE, closeBuf)); + clients.delete(socket); + return; + } + } + } + }); + + socket.on('close', () => clients.delete(socket)); + socket.on('error', () => clients.delete(socket)); +} + +function handleMessage(text) { + let event; + try { + event = JSON.parse(text); + } catch (e) { + console.error('Failed to parse WebSocket message:', e.message); + return; + } + touchActivity(); + console.log(JSON.stringify({ source: 'user-event', ...event })); + if (event.choice) { + const eventsFile = path.join(STATE_DIR, 'events'); + fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n'); + } +} + +function broadcast(msg) { + const frame = encodeFrame(OPCODES.TEXT, Buffer.from(JSON.stringify(msg))); + for (const socket of clients) { + try { socket.write(frame); } catch (e) { clients.delete(socket); } + } +} + +// ========== Activity Tracking ========== + +const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes +let lastActivity = Date.now(); + +function touchActivity() { + lastActivity = Date.now(); +} + +// ========== File Watching ========== + +const debounceTimers = new Map(); + +// ========== Server Startup ========== + +function startServer() { + if (!fs.existsSync(CONTENT_DIR)) fs.mkdirSync(CONTENT_DIR, { recursive: true }); + if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true }); + + // Track known files to distinguish new screens from updates. + // macOS fs.watch reports 'rename' for both new files and overwrites, + // so we can't rely on eventType alone. + const knownFiles = new Set( + fs.readdirSync(CONTENT_DIR).filter(f => f.endsWith('.html')) + ); + + const server = http.createServer(handleRequest); + server.on('upgrade', handleUpgrade); + + const watcher = fs.watch(CONTENT_DIR, (eventType, filename) => { + if (!filename || !filename.endsWith('.html')) return; + + if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename)); + debounceTimers.set(filename, setTimeout(() => { + debounceTimers.delete(filename); + const filePath = path.join(CONTENT_DIR, filename); + + if (!fs.existsSync(filePath)) return; // file was deleted + touchActivity(); + + if (!knownFiles.has(filename)) { + knownFiles.add(filename); + const eventsFile = path.join(STATE_DIR, 'events'); + if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); + console.log(JSON.stringify({ type: 'screen-added', file: filePath })); + } else { + console.log(JSON.stringify({ type: 'screen-updated', file: filePath })); + } + + broadcast({ type: 'reload' }); + }, 100)); + }); + watcher.on('error', (err) => console.error('fs.watch error:', err.message)); + + function shutdown(reason) { + console.log(JSON.stringify({ type: 'server-stopped', reason })); + const infoFile = path.join(STATE_DIR, 'server-info'); + if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile); + fs.writeFileSync( + path.join(STATE_DIR, 'server-stopped'), + JSON.stringify({ reason, timestamp: Date.now() }) + '\n' + ); + watcher.close(); + clearInterval(lifecycleCheck); + server.close(() => process.exit(0)); + } + + function ownerAlive() { + if (!ownerPid) return true; + try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; } + } + + // Check every 60s: exit if owner process died or idle for 30 minutes + const lifecycleCheck = setInterval(() => { + if (!ownerAlive()) shutdown('owner process exited'); + else if (Date.now() - lastActivity > IDLE_TIMEOUT_MS) shutdown('idle timeout'); + }, 60 * 1000); + lifecycleCheck.unref(); + + // Validate owner PID at startup. If it's already dead, the PID resolution + // was wrong (common on WSL, Tailscale SSH, and cross-user scenarios). + // Disable monitoring and rely on the idle timeout instead. + if (ownerPid) { + try { process.kill(ownerPid, 0); } + catch (e) { + if (e.code !== 'EPERM') { + console.log(JSON.stringify({ type: 'owner-pid-invalid', pid: ownerPid, reason: 'dead at startup' })); + ownerPid = null; + } + } + } + + server.listen(PORT, HOST, () => { + const info = JSON.stringify({ + type: 'server-started', port: Number(PORT), host: HOST, + url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT, + screen_dir: CONTENT_DIR, state_dir: STATE_DIR + }); + console.log(info); + fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n'); + }); +} + +if (require.main === module) { + startServer(); +} + +module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES }; diff --git a/plugins/do-it/skills/do-it-planning/scripts/start-server.sh b/plugins/do-it/skills/do-it-planning/scripts/start-server.sh new file mode 100755 index 0000000..55b89ae --- /dev/null +++ b/plugins/do-it/skills/do-it-planning/scripts/start-server.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# Start the do-it visual server and output connection info +# Usage: start-server.sh [--project-dir ] [--host ] [--url-host ] [--foreground] [--background] +# +# Starts server on a random high port, outputs JSON with URL. +# Each session gets its own directory to avoid conflicts. +# +# Options: +# --project-dir Store session files under /.do-it/visual/ +# instead of /tmp. Files persist after server stops. +# --host Host/interface to bind (default: 127.0.0.1). +# Use 0.0.0.0 in remote/containerized environments. +# --url-host Hostname shown in returned URL JSON. +# --foreground Run server in the current terminal (no backgrounding). +# --background Force background mode (overrides Codex auto-foreground). + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Parse arguments +PROJECT_DIR="" +FOREGROUND="false" +FORCE_BACKGROUND="false" +BIND_HOST="127.0.0.1" +URL_HOST="" +while [[ $# -gt 0 ]]; do + case "$1" in + --project-dir) + PROJECT_DIR="$2" + shift 2 + ;; + --host) + BIND_HOST="$2" + shift 2 + ;; + --url-host) + URL_HOST="$2" + shift 2 + ;; + --foreground|--no-daemon) + FOREGROUND="true" + shift + ;; + --background|--daemon) + FORCE_BACKGROUND="true" + shift + ;; + *) + echo "{\"error\": \"Unknown argument: $1\"}" + exit 1 + ;; + esac +done + +if [[ -z "$URL_HOST" ]]; then + if [[ "$BIND_HOST" == "127.0.0.1" || "$BIND_HOST" == "localhost" ]]; then + URL_HOST="localhost" + else + URL_HOST="$BIND_HOST" + fi +fi + +# Some environments reap detached/background processes. Auto-foreground when detected. +if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then + FOREGROUND="true" +fi + +# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected. +if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then + case "${OSTYPE:-}" in + msys*|cygwin*|mingw*) FOREGROUND="true" ;; + esac + if [[ -n "${MSYSTEM:-}" ]]; then + FOREGROUND="true" + fi +fi + +# Generate unique session directory +SESSION_ID="$$-$(date +%s)" + +if [[ -n "$PROJECT_DIR" ]]; then + SESSION_DIR="${PROJECT_DIR}/.do-it/visual/${SESSION_ID}" +else + SESSION_DIR="/tmp/do-it-visual-${SESSION_ID}" +fi + +STATE_DIR="${SESSION_DIR}/state" +PID_FILE="${STATE_DIR}/server.pid" +LOG_FILE="${STATE_DIR}/server.log" + +# Create fresh session directory with content and state peers +mkdir -p "${SESSION_DIR}/content" "$STATE_DIR" + +# Kill any existing server +if [[ -f "$PID_FILE" ]]; then + old_pid=$(cat "$PID_FILE") + kill "$old_pid" 2>/dev/null + rm -f "$PID_FILE" +fi + +cd "$SCRIPT_DIR" + +# Resolve the harness PID (grandparent of this script). +# $PPID is the ephemeral shell the harness spawned to run us — it dies +# when this script exits. The harness itself is $PPID's parent. +OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ')" +if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then + OWNER_PID="$PPID" +fi + +# Foreground mode for environments that reap detached/background processes. +if [[ "$FOREGROUND" == "true" ]]; then + echo "$$" > "$PID_FILE" + env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs + exit $? +fi + +# Start server, capturing output to log file +# Use nohup to survive shell exit; disown to remove from job table +nohup env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 & +SERVER_PID=$! +disown "$SERVER_PID" 2>/dev/null +echo "$SERVER_PID" > "$PID_FILE" + +# Wait for server-started message (check log file) +for i in {1..50}; do + if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then + # Verify server is still alive after a short window (catches process reapers) + alive="true" + for _ in {1..20}; do + if ! kill -0 "$SERVER_PID" 2>/dev/null; then + alive="false" + break + fi + sleep 0.1 + done + if [[ "$alive" != "true" ]]; then + echo "{\"error\": \"Server started but was killed. Retry in a persistent terminal with: $SCRIPT_DIR/start-server.sh${PROJECT_DIR:+ --project-dir $PROJECT_DIR} --host $BIND_HOST --url-host $URL_HOST --foreground\"}" + exit 1 + fi + grep "server-started" "$LOG_FILE" | head -1 + exit 0 + fi + sleep 0.1 +done + +# Timeout - server didn't start +echo '{"error": "Server failed to start within 5 seconds"}' +exit 1 diff --git a/plugins/do-it/skills/do-it-planning/scripts/stop-server.sh b/plugins/do-it/skills/do-it-planning/scripts/stop-server.sh new file mode 100755 index 0000000..8966a93 --- /dev/null +++ b/plugins/do-it/skills/do-it-planning/scripts/stop-server.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# Stop the do-it visual server and clean up +# Usage: stop-server.sh +# +# Kills the server process. Only deletes session directory if it's +# under /tmp (ephemeral). Persistent directories (.do-it/visual/) are +# kept so mockups can be reviewed later. + +SESSION_DIR="$1" + +if [[ -z "$SESSION_DIR" ]]; then + echo '{"error": "Usage: stop-server.sh "}' + exit 1 +fi + +STATE_DIR="${SESSION_DIR}/state" +PID_FILE="${STATE_DIR}/server.pid" + +if [[ -f "$PID_FILE" ]]; then + pid=$(cat "$PID_FILE") + + # Try to stop gracefully, fallback to force if still alive + kill "$pid" 2>/dev/null || true + + # Wait for graceful shutdown (up to ~2s) + for i in {1..20}; do + if ! kill -0 "$pid" 2>/dev/null; then + break + fi + sleep 0.1 + done + + # If still running, escalate to SIGKILL + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + + # Give SIGKILL a moment to take effect + sleep 0.1 + fi + + if kill -0 "$pid" 2>/dev/null; then + echo '{"status": "failed", "error": "process still running"}' + exit 1 + fi + + rm -f "$PID_FILE" "${STATE_DIR}/server.log" + + # Only delete ephemeral /tmp directories + if [[ "$SESSION_DIR" == /tmp/* ]]; then + rm -rf "$SESSION_DIR" + fi + + echo '{"status": "stopped"}' +else + echo '{"status": "not_running"}' +fi diff --git a/plugins/do-it/skills/do-it-planning/templates/plan-card.html b/plugins/do-it/skills/do-it-planning/templates/plan-card.html new file mode 100644 index 0000000..3d3ef2d --- /dev/null +++ b/plugins/do-it/skills/do-it-planning/templates/plan-card.html @@ -0,0 +1,56 @@ + +
+

+

+
+ Tier: + Size: + Owner: +
+
+ +
+
Background & Goal
+

+
+ +
+
Allowed Scope
+
    +
  • +
+
+ +
+
Acceptance Criteria
+ + + + + +
ACCriteriaEvidence
AC1
+
+ +
+
Verification
+

+
+ +
+
Risks & Shared-File Hazards
+
    +
  • +
+
diff --git a/plugins/do-it/skills/do-it-planning/templates/review-report.html b/plugins/do-it/skills/do-it-planning/templates/review-report.html new file mode 100644 index 0000000..e7c6eb6 --- /dev/null +++ b/plugins/do-it/skills/do-it-planning/templates/review-report.html @@ -0,0 +1,47 @@ + +
+

+

+
+ Blocking: + Important: + Opportunity: +
+
+ +
+
Findings
+ +
+
Blocking
+

+
+
+ +
+
Important
+

+
+
+ +
+
Opportunity
+

+
+
+
+ +
+
Residual Risk
+

+
diff --git a/skills/do-it/do-it-planning/SKILL.md b/skills/do-it/do-it-planning/SKILL.md index 65773e3..ca04004 100644 --- a/skills/do-it/do-it-planning/SKILL.md +++ b/skills/do-it/do-it-planning/SKILL.md @@ -226,11 +226,22 @@ for a code-facing plan; they go stale faster than domain decisions. When seeing an option is materially clearer than reading it — UI layout alternatives, architecture/data-flow diagrams, before/after states, side-by-side -interface shapes — sketch it under `.do-it/visual//` (descriptive -filenames like `option-a-flow.md`, `api-boundary.svg`). Treat these as auxiliary -evidence, not durable plan output: the decision still lands in the plan card. -Skip visuals for text-only decisions, one-line questions, or where a table is -clearer. A visual aid never promotes a task's tier by itself. +interface shapes, or visual task sequencing for multi-agent work — produce the +smallest useful artifact under `.do-it/visual//` (descriptive filenames +like `option-a-flow.md`, `api-boundary.svg`), compare 2-3 options with explicit +tradeoffs, and name a recommendation. Feed that decision back into this plan card +(or `do-it-interface-drill` / `do-it-architecture-scan` when it shapes a contract +or boundary). + +Treat visuals as auxiliary evidence, not durable plan output: the decision still +lands in the plan card. Skip them for text-only decisions, one-line questions, or +where a table is clearer. A visual aid never promotes a task's tier by itself. + +For browser-based side-by-side comparison, this skill ships an optional local +visual companion under `scripts/` (a small static server plus `plan-card` / +`review-report` render templates). Load `references/visual-companion.md` only +when you actually need the browser render; for everything else, file-based +sketches in `.do-it/visual/` are enough. ## Output Shape diff --git a/skills/do-it/do-it-planning/references/visual-companion.md b/skills/do-it/do-it-planning/references/visual-companion.md new file mode 100644 index 0000000..393118e --- /dev/null +++ b/skills/do-it/do-it-planning/references/visual-companion.md @@ -0,0 +1,267 @@ +# Visual Companion Guide + +Browser-based do-it visual planning companion for showing mockups, diagrams, and options. + +## When to Use + +Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?** + +**Use the browser** when the content itself is visual: + +- **UI mockups** — wireframes, layouts, navigation structures, component designs +- **Architecture diagrams** — system components, data flow, relationship maps +- **Side-by-side visual comparisons** — comparing two layouts, two color schemes, two design directions +- **Design polish** — when the question is about look and feel, spacing, visual hierarchy +- **Spatial relationships** — state machines, flowcharts, entity relationships rendered as diagrams + +**Use the terminal** when the content is text or tabular: + +- **Requirements and scope questions** — "what does X mean?", "which features are in scope?" +- **Conceptual A/B/C choices** — picking between approaches described in words +- **Tradeoff lists** — pros/cons, comparison tables +- **Technical decisions** — API design, data modeling, architectural approach selection +- **Clarifying questions** — anything where the answer is words, not a visual preference + +A question *about* a UI topic is not automatically a visual question. "What kind of wizard do you want?" is conceptual — use the terminal. "Which of these wizard layouts feels right?" is visual — use the browser. + +## How It Works + +The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to `screen_dir`, the user sees it in their browser and can click to select options. Selections are recorded to `state_dir/events` that you read on your next turn. + +**Content fragments vs full documents:** If your HTML file starts with `/.do-it/visual/` for the session directory. + +**Note:** Pass the project root as `--project-dir` so mockups persist in `.do-it/visual/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. The do-it repository ignores `.do-it/`; downstream projects should do the same before using persistent visual sessions. + +**Launching the server:** + +```bash +# Codex-first default. The script auto-detects CODEX_CI and switches to +# foreground mode when the environment would reap detached processes. +scripts/start-server.sh --project-dir /path/to/project +``` + +Other runtimes must keep the server alive across turns. If the environment +reaps detached processes, use `--foreground` and launch the command with that +runtime's background execution mechanism. + +If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host: + +```bash +scripts/start-server.sh \ + --project-dir /path/to/project \ + --host 0.0.0.0 \ + --url-host localhost +``` + +Use `--url-host` to control what hostname is printed in the returned URL JSON. + +## The Loop + +1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`: + - Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity. + - Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html` + - **Never reuse filenames** — each screen gets a fresh file + - Use the normal file-editing tool; avoid cat/heredoc writes that dump noisy + HTML into terminal output. + - Server automatically serves the newest file + +2. **Tell user what to expect and end your turn:** + - Remind them of the URL (every step, not just first) + - Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage") + - Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like." + +3. **On your next turn** — after the user responds in the terminal: + - Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines + - Merge with the user's terminal text to get the full picture + - The terminal message is the primary feedback; `state_dir/events` provides structured interaction data + +4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated. + +5. **Unload when returning to terminal** — when the next step doesn't need the browser (e.g., a clarifying question, a tradeoff discussion), push a waiting screen to clear the stale content: + + ```html + +
+

Continuing in terminal...

+
+ ``` + + This prevents the user from staring at a resolved choice while the conversation has moved on. When the next visual question comes up, push a new content file as usual. + +6. Repeat until done. + +## Writing Content Fragments + +Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure). + +**Minimal example:** + +```html +

Which layout works better?

+

Consider readability and visual hierarchy

+ +
+
+
A
+
+

Single Column

+

Clean, focused reading experience

+
+
+
+
B
+
+

Two Column

+

Sidebar navigation with main content

+
+
+
+``` + +That's it. No ``, no CSS, no `'; + +// ========== Helper Functions ========== + +function isFullDocument(html) { + const trimmed = html.trimStart().toLowerCase(); + return trimmed.startsWith('', content); +} + +function getNewestScreen() { + const files = fs.readdirSync(CONTENT_DIR) + .filter(f => f.endsWith('.html')) + .map(f => { + const fp = path.join(CONTENT_DIR, f); + return { path: fp, mtime: fs.statSync(fp).mtime.getTime() }; + }) + .sort((a, b) => b.mtime - a.mtime); + return files.length > 0 ? files[0].path : null; +} + +// ========== HTTP Request Handler ========== + +function handleRequest(req, res) { + touchActivity(); + if (req.method === 'GET' && req.url === '/') { + const screenFile = getNewestScreen(); + let html = screenFile + ? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8')) + : WAITING_PAGE; + + if (html.includes('')) { + html = html.replace('', helperInjection + '\n'); + } else { + html += helperInjection; + } + + res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); + res.end(html); + } else if (req.method === 'GET' && req.url.startsWith('/files/')) { + const fileName = req.url.slice(7); + const filePath = path.join(CONTENT_DIR, path.basename(fileName)); + if (!fs.existsSync(filePath)) { + res.writeHead(404); + res.end('Not found'); + return; + } + const ext = path.extname(filePath).toLowerCase(); + const contentType = MIME_TYPES[ext] || 'application/octet-stream'; + res.writeHead(200, { 'Content-Type': contentType }); + res.end(fs.readFileSync(filePath)); + } else { + res.writeHead(404); + res.end('Not found'); + } +} + +// ========== WebSocket Connection Handling ========== + +const clients = new Set(); + +function handleUpgrade(req, socket) { + const key = req.headers['sec-websocket-key']; + if (!key) { socket.destroy(); return; } + + const accept = computeAcceptKey(key); + socket.write( + 'HTTP/1.1 101 Switching Protocols\r\n' + + 'Upgrade: websocket\r\n' + + 'Connection: Upgrade\r\n' + + 'Sec-WebSocket-Accept: ' + accept + '\r\n\r\n' + ); + + let buffer = Buffer.alloc(0); + clients.add(socket); + + socket.on('data', (chunk) => { + buffer = Buffer.concat([buffer, chunk]); + while (buffer.length > 0) { + let result; + try { + result = decodeFrame(buffer); + } catch (e) { + socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); + clients.delete(socket); + return; + } + if (!result) break; + buffer = buffer.slice(result.bytesConsumed); + + switch (result.opcode) { + case OPCODES.TEXT: + handleMessage(result.payload.toString()); + break; + case OPCODES.CLOSE: + socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0))); + clients.delete(socket); + return; + case OPCODES.PING: + socket.write(encodeFrame(OPCODES.PONG, result.payload)); + break; + case OPCODES.PONG: + break; + default: { + const closeBuf = Buffer.alloc(2); + closeBuf.writeUInt16BE(1003); + socket.end(encodeFrame(OPCODES.CLOSE, closeBuf)); + clients.delete(socket); + return; + } + } + } + }); + + socket.on('close', () => clients.delete(socket)); + socket.on('error', () => clients.delete(socket)); +} + +function handleMessage(text) { + let event; + try { + event = JSON.parse(text); + } catch (e) { + console.error('Failed to parse WebSocket message:', e.message); + return; + } + touchActivity(); + console.log(JSON.stringify({ source: 'user-event', ...event })); + if (event.choice) { + const eventsFile = path.join(STATE_DIR, 'events'); + fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n'); + } +} + +function broadcast(msg) { + const frame = encodeFrame(OPCODES.TEXT, Buffer.from(JSON.stringify(msg))); + for (const socket of clients) { + try { socket.write(frame); } catch (e) { clients.delete(socket); } + } +} + +// ========== Activity Tracking ========== + +const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes +let lastActivity = Date.now(); + +function touchActivity() { + lastActivity = Date.now(); +} + +// ========== File Watching ========== + +const debounceTimers = new Map(); + +// ========== Server Startup ========== + +function startServer() { + if (!fs.existsSync(CONTENT_DIR)) fs.mkdirSync(CONTENT_DIR, { recursive: true }); + if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true }); + + // Track known files to distinguish new screens from updates. + // macOS fs.watch reports 'rename' for both new files and overwrites, + // so we can't rely on eventType alone. + const knownFiles = new Set( + fs.readdirSync(CONTENT_DIR).filter(f => f.endsWith('.html')) + ); + + const server = http.createServer(handleRequest); + server.on('upgrade', handleUpgrade); + + const watcher = fs.watch(CONTENT_DIR, (eventType, filename) => { + if (!filename || !filename.endsWith('.html')) return; + + if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename)); + debounceTimers.set(filename, setTimeout(() => { + debounceTimers.delete(filename); + const filePath = path.join(CONTENT_DIR, filename); + + if (!fs.existsSync(filePath)) return; // file was deleted + touchActivity(); + + if (!knownFiles.has(filename)) { + knownFiles.add(filename); + const eventsFile = path.join(STATE_DIR, 'events'); + if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); + console.log(JSON.stringify({ type: 'screen-added', file: filePath })); + } else { + console.log(JSON.stringify({ type: 'screen-updated', file: filePath })); + } + + broadcast({ type: 'reload' }); + }, 100)); + }); + watcher.on('error', (err) => console.error('fs.watch error:', err.message)); + + function shutdown(reason) { + console.log(JSON.stringify({ type: 'server-stopped', reason })); + const infoFile = path.join(STATE_DIR, 'server-info'); + if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile); + fs.writeFileSync( + path.join(STATE_DIR, 'server-stopped'), + JSON.stringify({ reason, timestamp: Date.now() }) + '\n' + ); + watcher.close(); + clearInterval(lifecycleCheck); + server.close(() => process.exit(0)); + } + + function ownerAlive() { + if (!ownerPid) return true; + try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; } + } + + // Check every 60s: exit if owner process died or idle for 30 minutes + const lifecycleCheck = setInterval(() => { + if (!ownerAlive()) shutdown('owner process exited'); + else if (Date.now() - lastActivity > IDLE_TIMEOUT_MS) shutdown('idle timeout'); + }, 60 * 1000); + lifecycleCheck.unref(); + + // Validate owner PID at startup. If it's already dead, the PID resolution + // was wrong (common on WSL, Tailscale SSH, and cross-user scenarios). + // Disable monitoring and rely on the idle timeout instead. + if (ownerPid) { + try { process.kill(ownerPid, 0); } + catch (e) { + if (e.code !== 'EPERM') { + console.log(JSON.stringify({ type: 'owner-pid-invalid', pid: ownerPid, reason: 'dead at startup' })); + ownerPid = null; + } + } + } + + server.listen(PORT, HOST, () => { + const info = JSON.stringify({ + type: 'server-started', port: Number(PORT), host: HOST, + url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT, + screen_dir: CONTENT_DIR, state_dir: STATE_DIR + }); + console.log(info); + fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n'); + }); +} + +if (require.main === module) { + startServer(); +} + +module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES }; diff --git a/skills/do-it/do-it-planning/scripts/start-server.sh b/skills/do-it/do-it-planning/scripts/start-server.sh new file mode 100755 index 0000000..55b89ae --- /dev/null +++ b/skills/do-it/do-it-planning/scripts/start-server.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# Start the do-it visual server and output connection info +# Usage: start-server.sh [--project-dir ] [--host ] [--url-host ] [--foreground] [--background] +# +# Starts server on a random high port, outputs JSON with URL. +# Each session gets its own directory to avoid conflicts. +# +# Options: +# --project-dir Store session files under /.do-it/visual/ +# instead of /tmp. Files persist after server stops. +# --host Host/interface to bind (default: 127.0.0.1). +# Use 0.0.0.0 in remote/containerized environments. +# --url-host Hostname shown in returned URL JSON. +# --foreground Run server in the current terminal (no backgrounding). +# --background Force background mode (overrides Codex auto-foreground). + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Parse arguments +PROJECT_DIR="" +FOREGROUND="false" +FORCE_BACKGROUND="false" +BIND_HOST="127.0.0.1" +URL_HOST="" +while [[ $# -gt 0 ]]; do + case "$1" in + --project-dir) + PROJECT_DIR="$2" + shift 2 + ;; + --host) + BIND_HOST="$2" + shift 2 + ;; + --url-host) + URL_HOST="$2" + shift 2 + ;; + --foreground|--no-daemon) + FOREGROUND="true" + shift + ;; + --background|--daemon) + FORCE_BACKGROUND="true" + shift + ;; + *) + echo "{\"error\": \"Unknown argument: $1\"}" + exit 1 + ;; + esac +done + +if [[ -z "$URL_HOST" ]]; then + if [[ "$BIND_HOST" == "127.0.0.1" || "$BIND_HOST" == "localhost" ]]; then + URL_HOST="localhost" + else + URL_HOST="$BIND_HOST" + fi +fi + +# Some environments reap detached/background processes. Auto-foreground when detected. +if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then + FOREGROUND="true" +fi + +# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected. +if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then + case "${OSTYPE:-}" in + msys*|cygwin*|mingw*) FOREGROUND="true" ;; + esac + if [[ -n "${MSYSTEM:-}" ]]; then + FOREGROUND="true" + fi +fi + +# Generate unique session directory +SESSION_ID="$$-$(date +%s)" + +if [[ -n "$PROJECT_DIR" ]]; then + SESSION_DIR="${PROJECT_DIR}/.do-it/visual/${SESSION_ID}" +else + SESSION_DIR="/tmp/do-it-visual-${SESSION_ID}" +fi + +STATE_DIR="${SESSION_DIR}/state" +PID_FILE="${STATE_DIR}/server.pid" +LOG_FILE="${STATE_DIR}/server.log" + +# Create fresh session directory with content and state peers +mkdir -p "${SESSION_DIR}/content" "$STATE_DIR" + +# Kill any existing server +if [[ -f "$PID_FILE" ]]; then + old_pid=$(cat "$PID_FILE") + kill "$old_pid" 2>/dev/null + rm -f "$PID_FILE" +fi + +cd "$SCRIPT_DIR" + +# Resolve the harness PID (grandparent of this script). +# $PPID is the ephemeral shell the harness spawned to run us — it dies +# when this script exits. The harness itself is $PPID's parent. +OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ')" +if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then + OWNER_PID="$PPID" +fi + +# Foreground mode for environments that reap detached/background processes. +if [[ "$FOREGROUND" == "true" ]]; then + echo "$$" > "$PID_FILE" + env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs + exit $? +fi + +# Start server, capturing output to log file +# Use nohup to survive shell exit; disown to remove from job table +nohup env DO_IT_VISUAL_DIR="$SESSION_DIR" DO_IT_VISUAL_HOST="$BIND_HOST" DO_IT_VISUAL_URL_HOST="$URL_HOST" DO_IT_VISUAL_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 & +SERVER_PID=$! +disown "$SERVER_PID" 2>/dev/null +echo "$SERVER_PID" > "$PID_FILE" + +# Wait for server-started message (check log file) +for i in {1..50}; do + if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then + # Verify server is still alive after a short window (catches process reapers) + alive="true" + for _ in {1..20}; do + if ! kill -0 "$SERVER_PID" 2>/dev/null; then + alive="false" + break + fi + sleep 0.1 + done + if [[ "$alive" != "true" ]]; then + echo "{\"error\": \"Server started but was killed. Retry in a persistent terminal with: $SCRIPT_DIR/start-server.sh${PROJECT_DIR:+ --project-dir $PROJECT_DIR} --host $BIND_HOST --url-host $URL_HOST --foreground\"}" + exit 1 + fi + grep "server-started" "$LOG_FILE" | head -1 + exit 0 + fi + sleep 0.1 +done + +# Timeout - server didn't start +echo '{"error": "Server failed to start within 5 seconds"}' +exit 1 diff --git a/skills/do-it/do-it-planning/scripts/stop-server.sh b/skills/do-it/do-it-planning/scripts/stop-server.sh new file mode 100755 index 0000000..8966a93 --- /dev/null +++ b/skills/do-it/do-it-planning/scripts/stop-server.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +# Stop the do-it visual server and clean up +# Usage: stop-server.sh +# +# Kills the server process. Only deletes session directory if it's +# under /tmp (ephemeral). Persistent directories (.do-it/visual/) are +# kept so mockups can be reviewed later. + +SESSION_DIR="$1" + +if [[ -z "$SESSION_DIR" ]]; then + echo '{"error": "Usage: stop-server.sh "}' + exit 1 +fi + +STATE_DIR="${SESSION_DIR}/state" +PID_FILE="${STATE_DIR}/server.pid" + +if [[ -f "$PID_FILE" ]]; then + pid=$(cat "$PID_FILE") + + # Try to stop gracefully, fallback to force if still alive + kill "$pid" 2>/dev/null || true + + # Wait for graceful shutdown (up to ~2s) + for i in {1..20}; do + if ! kill -0 "$pid" 2>/dev/null; then + break + fi + sleep 0.1 + done + + # If still running, escalate to SIGKILL + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + + # Give SIGKILL a moment to take effect + sleep 0.1 + fi + + if kill -0 "$pid" 2>/dev/null; then + echo '{"status": "failed", "error": "process still running"}' + exit 1 + fi + + rm -f "$PID_FILE" "${STATE_DIR}/server.log" + + # Only delete ephemeral /tmp directories + if [[ "$SESSION_DIR" == /tmp/* ]]; then + rm -rf "$SESSION_DIR" + fi + + echo '{"status": "stopped"}' +else + echo '{"status": "not_running"}' +fi diff --git a/skills/do-it/do-it-planning/templates/plan-card.html b/skills/do-it/do-it-planning/templates/plan-card.html new file mode 100644 index 0000000..3d3ef2d --- /dev/null +++ b/skills/do-it/do-it-planning/templates/plan-card.html @@ -0,0 +1,56 @@ + +
+

+

+
+ Tier: + Size: + Owner: +
+
+ +
+
Background & Goal
+

+
+ +
+
Allowed Scope
+
    +
  • +
+
+ +
+
Acceptance Criteria
+ + + + + +
ACCriteriaEvidence
AC1
+
+ +
+
Verification
+

+
+ +
+
Risks & Shared-File Hazards
+
    +
  • +
+
diff --git a/skills/do-it/do-it-planning/templates/review-report.html b/skills/do-it/do-it-planning/templates/review-report.html new file mode 100644 index 0000000..e7c6eb6 --- /dev/null +++ b/skills/do-it/do-it-planning/templates/review-report.html @@ -0,0 +1,47 @@ + +
+

+

+
+ Blocking: + Important: + Opportunity: +
+
+ +
+
Findings
+ +
+
Blocking
+

+
+
+ +
+
Important
+

+
+
+ +
+
Opportunity
+

+
+
+
+ +
+
Residual Risk
+

+