From 81d4e80fd5aabe4e80f58e960affa795cf7d34ec Mon Sep 17 00:00:00 2001 From: godosa Date: Wed, 7 Oct 2026 07:27:17 +0200 Subject: workflow: initial public history --- templates/CLAUDE.md | 21 +++++++++++++++++++++ templates/TASKS.md | 12 ++++++++++++ templates/archive.md | 1 + templates/batch-prompt.md | 1 + templates/cloud-prompt.md | 38 ++++++++++++++++++++++++++++++++++++++ templates/prep-prompt.md | 1 + templates/workflow.toml | 36 ++++++++++++++++++++++++++++++++++++ 7 files changed, 110 insertions(+) create mode 100644 templates/CLAUDE.md create mode 100644 templates/TASKS.md create mode 100644 templates/archive.md create mode 100644 templates/batch-prompt.md create mode 100644 templates/cloud-prompt.md create mode 100644 templates/prep-prompt.md create mode 100644 templates/workflow.toml (limited to 'templates') diff --git a/templates/CLAUDE.md b/templates/CLAUDE.md new file mode 100644 index 0000000..88f70b4 --- /dev/null +++ b/templates/CLAUDE.md @@ -0,0 +1,21 @@ +# CLAUDE.md — {name} + +Project rules; win over the shared /projects/CLAUDE.md on conflict. Terse. Update when you re-learn something. + +## Layout +- + +## Loop additions +- Verify: + +## Gotchas +- + +## Areas +### +- Code map: +- Test recipe: +- Tools: +- Worktree setup: +- Paths: +- Checked: after a refresh> diff --git a/templates/TASKS.md b/templates/TASKS.md new file mode 100644 index 0000000..2148242 --- /dev/null +++ b/templates/TASKS.md @@ -0,0 +1,12 @@ +# Tasks — {name} + +Format and rules: /projects/CLAUDE.md. Done history: [`tasks/archive.md`](tasks/archive.md). +Look and change with `wf` (`wf -h`), not by hand. + +## Awaiting your decision + +## Pending + +## Needs human + +## Deferred diff --git a/templates/archive.md b/templates/archive.md new file mode 100644 index 0000000..14e4146 --- /dev/null +++ b/templates/archive.md @@ -0,0 +1 @@ +# Task archive (newest first) diff --git a/templates/batch-prompt.md b/templates/batch-prompt.md new file mode 100644 index 0000000..1a0f338 --- /dev/null +++ b/templates/batch-prompt.md @@ -0,0 +1 @@ +You are a batch orchestrator. Follow {here}/docs/orchestrator.md 'One worker' for up to {n} tasks (lanes: {lanes}), never implement. Before EVERY spawn (each round, a lane's P0 fix, a recovery worker) run `test -e {stop}`: it exists → spawn nothing, let running workers finish (never kill one), post-check them, append 'stopped: stop file' to {out}, delete the stop file, exit. Else, before each round run `wf batch --time-left {deadline}`: its line ends in ': stop' (less time left than a task takes, p90) → spawn nothing new, let running workers finish, post-check them, append 'stopped: deadline ()' to {out}, exit. Else each round: `wf orch pick ` per lane, spawn one wf-worker per picked lane in ONE message (model and prompt: as printed), foreground (not background), wait for all, post-check each with `wf orch post --result "" --commit --agent --duration --no-pick`, append one line per task to {out} (it exists with its '# wf-batch' header: only append, never rewrite) (time, lane, id, outcome, commit), repeat. If the project has `cloud = true`, the virtual lane cloud also runs each round (nothing to spawn): `wf orch pick cloud` until a `stop lane cloud` / `none fit` / `max parallel` line; never run `wf cloud pull` or `wf orch post cloud` yourself: the batch job's sidecar pulls every 10 min (`wf cloud pull --all` → `wf orch post cloud … --no-pick`, a 'cloud … (sidecar pull)' line in {out}), also while you wait on workers; a cloud stop never stops the local lanes. Stop a lane on its first stop outcome, and keep it stopped (never resume because some other task is pickable) until the task/fix that stopped it is done or the owner says so; done+gate-red is not one (post-check as done, the lane picks the P0 fix next). Never ask the owner: follow-ups → wf add -p 2 --model , decisions → wf add -s awaiting. At batch start note `git branch --list 'fast/*' 'slow/*'` (and worktrees): a branch already there is pre-existing; report it ONCE in {out} as 'pre-existing branch ' (+ the awaiting id when a task/awaiting names it), never per round or per task. End with the ids added in that file, then exit. diff --git a/templates/cloud-prompt.md b/templates/cloud-prompt.md new file mode 100644 index 0000000..6020e90 --- /dev/null +++ b/templates/cloud-prompt.md @@ -0,0 +1,38 @@ +You are a remote worker for one task in a snapshot repo (branch main, base commit {{base}}). +Rules (they override CLAUDE.md where they differ): +- The task tool `wf` is absent: ignore wf / TASKS / lane / worktree / gate rules in CLAUDE.md; never create or edit TASKS.md or the archive. +- Never ask questions. Blocked on a decision you cannot make: end with result awaiting and the one-line question as the report. +- Work: test red -> implement -> green (test recipe below); commit on main, one-line messages; never rewrite {{base}}. +- A needed network source is blocked: say so in the report, continue with what the repo has. +- When done, measure your usage with the usage script at the end of this prompt (it sums your own transcript). +- Commit only what the task needs: `git add `, never -A or `.`; no build output (__pycache__, bin, obj). +- Then build the patch block: git format-patch --binary {{base}}..HEAD --stdout | gzip -9 > /tmp/wf.patch.gz; echo "WF-PATCH-BEGIN sha256=$(sha256sum < /tmp/wf.patch.gz | cut -c1-64) bytes=$(wc -c < /tmp/wf.patch.gz)"; base64 -w 76 /tmp/wf.patch.gz; echo WF-PATCH-END +- Your final message is plain text (not a tool call, no code fences, no other text), first line = the result line. + Every line keeps its key word (WF-RESULT, WF-REPORT, WF-USAGE, then the patch block) literally; replace only <...>: + WF-RESULT + WF-REPORT + + + No commits (awaiting / handback without work): still write the patch block, for the empty patch. + +Task {{id}}: +{{task}} + +Test recipe (area notes): +{{recipe}} +{{note}} +Usage script (run as is): +python3 - <<'PY' +import json, glob, os +f = max(glob.glob(os.path.expanduser("~/.claude/projects/*/*.jsonl")), key=os.path.getmtime) +m = {} +for line in open(f): + try: + j = json.loads(line); x = j.get("message") or {} + if x.get("usage"): m[x.get("id") or j.get("uuid")] = x + except Exception: pass +t = [sum(x["usage"].get(k) or 0 for x in m.values()) for k in + ("input_tokens", "cache_creation_input_tokens", "cache_read_input_tokens", "output_tokens")] +model = next((x["model"] for x in m.values() if x.get("model")), "?") +print("WF-USAGE in=%d cw=%d cr=%d out=%d model=%s" % (*t, model)) +PY diff --git a/templates/prep-prompt.md b/templates/prep-prompt.md new file mode 100644 index 0000000..a503e7a --- /dev/null +++ b/templates/prep-prompt.md @@ -0,0 +1 @@ +You are a prep batch orchestrator: make not-runner-ready tasks runner-ready; never implement, never edit files yourself. wf = python3 {here}/wf.py, project {root}. Tasks: {ids}. First, if out/wf-batch.stop exists → append 'stopped: stop file' to {out}, delete the stop file, exit. Else spawn sonnet workers (Agent tool, general-purpose, model sonnet, foreground, not background), up to 3 tasks each, all in ONE message, and wait for all. Worker prompt (fill in its ids): "Prep wf tasks in project {root} (cd there; wf = python3 {here}/wf.py). Read only task text: wf show (wf ctx for its refs, ~40-line reads). Never implement, never edit files, never commit. Per task: goal clear → wf set --done "". Done = observable check of the task text; never invert recorded original behaviour unless the task is a bug fix. Done names concrete files/runs, not 'each listed X'. Effort > slice_above (default 1h) → no Done on it: wf add --parent slices (each with Done + Model), parent Done = all slices done. Also --model haiku|sonnet|opus if it has no Model line (haiku = mechanical, exact steps; sonnet = exact Done + existing pattern to copy; opus = design forks, debugging, anything unclear; any model above sonnet must be justified in the reply). Unclear (real fork, info only the owner has) → wf add -s awaiting ": ", then wf status blocked . Reply one line per task: → Done: [Model: ] (model above sonnet: [opus: ]) | → awaiting ." Then check each task with wf show and append one line per task to {out} (it exists with its '# wf-batch' header: only append, never rewrite): → Done: | → awaiting | → unchanged . Finally commit only the task file: git -C {root} commit -m "prep batch: " -- {tasks}. Never ask the owner: questions → wf add -s awaiting. Then exit. diff --git a/templates/workflow.toml b/templates/workflow.toml new file mode 100644 index 0000000..b8b05cd --- /dev/null +++ b/templates/workflow.toml @@ -0,0 +1,36 @@ +# wf project config. Design: docs/design.md. Unknown keys are errors. +format = 1 +tasks = "TASKS.md" +archive = "tasks/archive.md" +docs = [] # files/folders whose [[id]] links `wf check` validates, e.g. ["DESIGN.md", "docs/"] +verify = [] # commands `wf done` reminds of (never runs), e.g. ["make test"] +done = [] # extra checklist lines `wf done` prints +# ledgers = ".superpowers/sdd" # in-flight plan ledgers shown by `wf next` +# ctx_hint = 100000 # tokens: `wf next`/`done` suggest /clear above it (0 = off) +# worktree_setup = ["mkdir -p out && ln -sfn \"$WF_MAIN/out/data\" out/data"] +# # `wf setup` in a lane worktree: cwd = worktree, env WF_MAIN = main tree; +# # git-ignored inputs; idempotent (workers run it every start) +# quick_gate = ["make quick-test"] # `wf gate`: fast regression check workers run before `wf done` +# # (cwd = this tree's project folder, env WF_MAIN; red = exit 1) + +# [anchors] # optional: every task Ref anchor into `index` must be a heading there +# index = "DESIGN.md" +# index_section = "Subsystems" +# specs = "docs/superpowers/specs" + +# slice_above = "1h" # effort above this → slice job on the slices lane (never implemented whole) +# [lanes.fast] # default lanes = fast + slow below; defining any [lanes.*] replaces both +# efforts = ["<1h"] # efforts this lane implements (disjoint, cover every effort ≤ slice_above) +# order = "unblock" # unblock = tasks others wait on first · priority = inherited priority first +# slices = true # takes slice jobs (one lane; default: the lane with "<1h") +# [lanes.slow] +# efforts = ["1h"] +# order = "priority" +# fallback = "fast" # nothing pickable here → pick from that lane +# areas = "CLAUDE.md" # area notes (## Areas / ### ): wf areas checks their code maps +# code_root = "../tool" # repo the areas' anchors / Paths / Checked refer to (default: this project); no uncovered nudge then +# area_stale_commits = 20 # commits touching an area's Paths since Checked → stale +# area_ignore = ["tests", "test", "docs", "doc"] # folders never nudged as uncovered (default shown) +# cloud = true # cloud lane opt-in (wf cloud send) +# cloud_include = ["out/pack"] # git-ignored inputs force-added to the cloud snapshot +# cloud_note = "Game data: out/pack" # appended to the cloud prompt -- cgit