diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6da22e6..d3eddf9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -295,7 +295,9 @@ bash lib/tests/doc-lint.test.sh # run its tests It scans the live, normative docs only — `SKILL.md`, `README.md`, `docs/`, `agents/` — and **never** scans `.do-work/`, `CHANGELOG.md`, `.git/`, or `docs/superpowers/` (the dated spec/plan tree). Those locations legitimately preserve retired terminology; scanning them would reproduce the UR-029 over-broad find-and-replace failure. -**The rule: when you fix a doc conflict, add its pattern to the lint in the same commit.** A fix that doesn't also guard against regression is half a fix — the contradiction can drift back the next time someone edits an adjacent file. Add the new check to `scan_file` (or `scan_judgment_markers`) in `lib/doc-lint.sh` and a planted-violation case to `lib/tests/doc-lint.test.sh`, then confirm `bash lib/doc-lint.sh` is still clean against the repo. If a stale term is legitimately used inside an explicit retirement note, exclude that case narrowly (as the `same-branch` check skips lines that also say `retired`) rather than dropping the pattern. +**Path-scoped pattern — `bare-runtime-bash-lib` (ORI-242 / ORI-246):** under `SKILL.md`, `agents/`, and `references/`, bare runtime invocations of the form `bash lib/...` fail the scan. Runtime docs (including the skill entry) must use `bash {skill-root}/lib/...` after skill-root resolve / Load Config. **Allowlist (skill-dev regression gates only, under `agents/` / `references/`):** `bash lib/tests/...` and `bash lib/conformance-scan.sh` (tracker docs / CONTRIBUTING). **Not allowlisted on `SKILL.md`:** bare `bash lib/conformance-scan.sh` — entry conformance must use the skill-root form (a line that also says `never` is treated as a prohibition note documenting the anti-pattern). Catalog identity `lib/*.sh` without a leading `bash ` is not matched. This pass is separate from the default roots so `references/` is not pulled into unrelated patterns. + +**The rule: when you fix a doc conflict, add its pattern to the lint in the same commit.** A fix that doesn't also guard against regression is half a fix — the contradiction can drift back the next time someone edits an adjacent file. Add the new check to `scan_file` (or `scan_judgment_markers` / a path-scoped helper) in `lib/doc-lint.sh` and a planted-violation case to `lib/tests/doc-lint.test.sh`, then confirm `bash lib/doc-lint.sh` is still clean against the repo. If a stale term is legitimately used inside an explicit retirement note, exclude that case narrowly (as the `same-branch` check skips lines that also say `retired`) rather than dropping the pattern. For skill-dev-only bare `bash lib/` lines under `agents/` or `references/`, extend the `bare-runtime-bash-lib` allowlist rather than dropping the pattern — do **not** allowlist bare entry form on `SKILL.md`. ## Questions? diff --git a/SKILL.md b/SKILL.md index 06c906a..beae051 100644 --- a/SKILL.md +++ b/SKILL.md @@ -98,7 +98,7 @@ Full multi-backend deep dive: [references/tracker.md](references/tracker.md). **Load path** (every phase that touches work items): (1) [agents/config.md](agents/config.md), (2) resolve `tracker.backend` (default **markdown**), (3) [agents/tracker/port.md](agents/tracker/port.md), (4) `agents/tracker/.md`, (5) call only named port ops for storage. -**Hard-stop (no silent fallback):** when effective backend is `linear` and Linear is unusable (MCP missing/unauthenticated, team unresolved, missing `status_map` state) **or** `agents/tracker/linear.md` is missing/unreadable, agents **hard-stop** with setup instructions — they never fall through to markdown work-item paths. Canonical contract: `agents/tracker/port.md` + Load Config steps 6–7 in `agents/config.md`. +**Hard-stop (no silent fallback):** when effective backend is `linear` and Linear is unusable (MCP missing/unauthenticated, team unresolved, missing `status_map` state) **or** `agents/tracker/linear.md` is missing/unreadable, agents **hard-stop** with setup instructions — they never fall through to markdown work-item paths. Also hard-stop when skill-root cannot be resolved at entry (Project Root Detection) or later (Load Config step 8). Canonical contract: `agents/tracker/port.md` + Load Config steps 6–8 in `agents/config.md`. **No dual-write.** With `tracker.backend: linear`, Linear is the **only** work-item store. Agents must not mirror URs/REQs into local markdown as a second source of truth, and must not fall back to markdown when Linear fails (hard-stop instead). After idle migration (`/do-work upgrade migrate`), historical `.do-work/user-requests/` and `archive/` trees remain on disk as **read-only history** — work-item ops ignore them. @@ -123,12 +123,41 @@ git rev-parse --show-toplevel If this fails (not a git repo), use the current working directory. All references below use `{project}` to mean this resolved root. +### Skill-root resolve (before conformance) + +Immediately after resolving `{project}` and **before** the conformance check, resolve `$SKILL_ROOT` / `{skill-root}` — the absolute path of the do-work skill install root (directory containing `lib/` **and** at least one skill marker: `SKILL.md` **or** `agents/`). + +**Recipe:** same walk-up as Load Config step 8 in [agents/config.md](agents/config.md) — **not** a second folklore one-level `dirname/..`. Start from the absolute path of **this** file (`SKILL.md`); walk parents until markers match; hard-stop at filesystem root if none found. **No** env / hub / CWD fallback. + +```bash +# Start at the directory of this SKILL.md; walk parents until +# markers match (lib/ AND (SKILL.md OR agents/)). Hard-stop at filesystem +# root if none found. No env/hub/CWD fallback. +d="$(cd "$(dirname "")" && pwd)" +SKILL_ROOT="" +while true; do + if [ -d "$d/lib" ] && { [ -f "$d/SKILL.md" ] || [ -d "$d/agents" ]; }; then + SKILL_ROOT="$d" + break + fi + [ "$d" = "/" ] && break + d="$(dirname "$d")" +done +# non-empty $SKILL_ROOT required — else hard-stop (see below) +``` + +**Inherit for phase agents:** keep this resolved `$SKILL_ROOT` in context for the whole agent turn. Phase agents (and Load Config step 8) **inherit** it when it is still an absolute directory that satisfies the markers — they re-resolve only if missing, empty, non-absolute, or invalid. Do not invent a second resolve recipe in phase docs. + +**Hard-stop when skill-root is unknown at entry.** If the harness did not provide an absolute path for this `SKILL.md` **and** walk-up cannot find a valid skill install root, **stop immediately** — do not run conformance, do not dispatch: + +`skill-root unknown: cannot resolve $SKILL_ROOT (walk-up from loaded file; no env/hub/CWD fallback). Provide an absolute path to the loaded instruction file under the skill install root, or a valid pre-resolved $SKILL_ROOT that contains lib/ and (SKILL.md or agents/).` + ### Conformance check -Immediately after resolving `{project}` and before executing any subcommand-specific instructions, run the conformance detectors: +Immediately after `$SKILL_ROOT` is resolved and before executing any subcommand-specific instructions, run the conformance detectors via the skill install root (**never** bare `bash lib/conformance-scan.sh` — that assumes CWD is the skill root and fails in consumer projects): ```bash -bash lib/conformance-scan.sh {project} +bash {skill-root}/lib/conformance-scan.sh "{project}" ``` The scanner is read-only and may exit `1` when drift is detected. Interpret each output line as ` `: diff --git a/agents/audit.md b/agents/audit.md index 5a9b820..4756bfb 100644 --- a/agents/audit.md +++ b/agents/audit.md @@ -45,7 +45,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### 1. Read ground truth diff --git a/agents/capture.md b/agents/capture.md index f2a06c3..28a60e1 100644 --- a/agents/capture.md +++ b/agents/capture.md @@ -44,7 +44,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Capture REQ store — backend branch (ORI-9) @@ -606,7 +606,7 @@ Background about the rename... After all REQ files are written (Steps 4, 4b, 4c, 4d complete), validate that the `**Depends on:**` graph is acyclic. ```bash -bash lib/cycle-check.sh UR-NNN +bash {skill-root}/lib/cycle-check.sh UR-NNN ``` Replace `UR-NNN` with the actual UR identifier. The script scans all REQs matching that UR across backlog, working, and archive, builds the dep graph, and runs DFS cycle detection. @@ -619,7 +619,7 @@ Replace `UR-NNN` with the actual UR identifier. The script scans all REQs matchi 2. Build a fingerprint: `cap-cycle-UR-NNN` (replace UR-NNN with the actual id). 3. Call file-feedback to log the event: ```bash - bash lib/file-feedback.sh cap-cycle "cap-cycle-UR-NNN" \ + bash {skill-root}/lib/file-feedback.sh cap-cycle "cap-cycle-UR-NNN" \ '{"ur":"UR-NNN","cycle":"'"$cycle_path"'"}' \ "cap-cycle: circular dependency in UR-NNN" \ "Cycle detected during capture of UR-NNN: $cycle_path" diff --git a/agents/close.md b/agents/close.md index 3d4d8f6..edc25c4 100644 --- a/agents/close.md +++ b/agents/close.md @@ -40,7 +40,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Close report home — backend branch (REQ-296) diff --git a/agents/config.md b/agents/config.md index d410fee..ecbe69a 100644 --- a/agents/config.md +++ b/agents/config.md @@ -208,9 +208,68 @@ routing: [] When the effective backend is **`linear`**: load `agents/tracker/port.md` then `agents/tracker/linear.md` for work-item ops after the validations above pass. If `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the backend doc from the skill install / Linear skill setup) — **never** fall through to `markdown.md` or invent Linear tool sequences. -**Phase-agent contract:** every phase agent that touches work items follows the **Tracker load path** (config → resolve `tracker.backend` → `port.md` → `agents/tracker/.md` → only named port ops). The shared load path is defined once here and in `agents/tracker/port.md`; each phase agent restates a short copy so a missing wire cannot cause split-brain storage. +8. **Resolve skill-root (`$SKILL_ROOT` / `{skill-root}`).** Once per agent turn, resolve the absolute path of the do-work skill install root — a directory that contains `lib/` **and** at least one skill marker (`SKILL.md` **or** `agents/`). **Token definition:** `{skill-root}` means this resolved absolute path for **all later steps in the same agent turn**. Keep `$SKILL_ROOT` in context; substitute it wherever docs or bash lines write `{skill-root}` (especially `{skill-root}/lib/...`). -**Never fail or stop because of a missing or incomplete config file** (steps 1–5). If config creation or migration fails for any reason, proceed with in-memory defaults (including `tracker.backend: markdown`). **Exception:** step 7 Linear validation (and missing `linear.md`) is a deliberate hard-stop when the operator has opted into `backend: linear` — that is not a config-file completeness problem. + **Single home:** this step is the only place that defines the resolve recipe. `references/run-loop.md` §2a and the run-worker **Skill root** input are thin consumers — they must not invent a second folklore recipe. + + **Markers (valid skill install root):** a candidate directory is valid iff **both**: + 1. it contains a `lib/` directory, **and** + 2. it contains `SKILL.md` **or** an `agents/` directory (or both). + + Requiring a co-marker with `lib/` avoids monorepo false roots that happen to have a bare `lib/` higher in the tree. + + **Inherit rule:** If `$SKILL_ROOT` is already set in this agent turn's context (orchestrator-passed **Skill root**, or resolved earlier in the same turn) **and** that path is an absolute directory that satisfies the markers above, **keep it — do not re-resolve**. If missing, empty, non-absolute, or invalid (fails markers), clear it and run the walk-up recipe below. Nested agents inherit the entry-resolved root this way. + + **Recipe (walk-up from loaded instruction file — no env / hub / CWD fallback):** + + One-level `dirname/..` is **not** the algorithm — nested paths (e.g. `agents/tracker/linear.md`) and `SKILL.md` at the skill root need more than a single parent hop. + + ```bash + # Start at the directory of the loaded instruction file; walk parents until + # markers match (lib/ AND (SKILL.md OR agents/)). Hard-stop at filesystem + # root if none found. No env/hub/CWD fallback. + d="$(cd "$(dirname "")" && pwd)" + SKILL_ROOT="" + while true; do + if [ -d "$d/lib" ] && { [ -f "$d/SKILL.md" ] || [ -d "$d/agents" ]; }; then + SKILL_ROOT="$d" + break + fi + [ "$d" = "/" ] && break + d="$(dirname "$d")" + done + # non-empty $SKILL_ROOT required — else hard-stop (see below) + ``` + + **Examples** (all resolve to the skill install root): + + | Loaded file | Walk starts at | Resolves to | + |-------------|----------------|-------------| + | `{skill}/agents/run.md` | `…/agents` | `{skill}` (parent has `lib/` + markers) | + | `{skill}/agents/tracker/linear.md` | `…/agents/tracker` | `{skill}` (walk past `tracker` → `agents` → skill root; one-level `..` would wrongly stop at `agents/`) | + | `{skill}/references/run-loop.md` | `…/references` | `{skill}` | + | `{skill}/SKILL.md` | `{skill}` itself | `{skill}` (start directory already matches markers) | + + - Prefer the absolute path of the instruction file the agent is currently executing when walk-up is needed (e.g. `agents/run.md`, `agents/config.md`, `agents/run-worker.md`, `agents/tracker/linear.md`, a loaded `references/*.md`, or `SKILL.md`). + - Use the walk-up result as `$SKILL_ROOT` only when it satisfies the markers. + - When this project **is** the do-work skill itself, `$SKILL_ROOT` equals the project root and lib calls work directly. When the project is any other consumer repo, `$SKILL_ROOT` points at the skill clone where `lib/` actually lives — not at the consumer project root. + - Orchestrators that dispatch workers pass the same absolute `$SKILL_ROOT` as the worker **Skill root** input and substitute it into pasted `run-worker.md` instructions (see `agents/run-worker.md` When Invoked #5 and `references/run-loop.md` Step 2 dispatch). Workers and nested agents **inherit** that value when it still satisfies markers. + + **Hard-stop when the path cannot be determined.** If any of the following is true, **stop immediately** with a clear operator message — do not guess: + + - Inherit failed (missing/invalid `$SKILL_ROOT`) **and** the harness did not provide an absolute path for the loaded instruction file + - Walk-up from the loaded file reaches the filesystem root without finding a directory that satisfies the markers (`lib/` **and** (`SKILL.md` **or** `agents/`)) + - The path is empty or otherwise unknown after the recipe + + Operator message (example): + + `skill-root unknown: cannot resolve $SKILL_ROOT (walk-up from loaded file; no env/hub/CWD fallback). Provide an absolute path to the loaded instruction file under the skill install root, or a valid pre-resolved $SKILL_ROOT that contains lib/ and (SKILL.md or agents/).` + + **Do not** fall back to process CWD, hub paths (`~/.agents/skills/do-work`, `~/.claude/skills/do-work`), or invent a path from `DO_WORK_SKILL_ROOT` / other env vars when inherit markers fail. **Do** inherit a **valid** `$SKILL_ROOT` already set in this turn's context (see inherit rule above). + +**Phase-agent contract:** every phase agent that touches work items follows the **Tracker load path** (config → resolve `tracker.backend` → `port.md` → `agents/tracker/.md` → only named port ops). The shared load path is defined once here and in `agents/tracker/port.md`; each phase agent restates a short copy so a missing wire cannot cause split-brain storage. Every phase agent that invokes skill `lib/` scripts also depends on step 8 (`$SKILL_ROOT` / `{skill-root}`) from this same Load Config block. + +**Never fail or stop because of a missing or incomplete config file** (steps 1–5). If config creation or migration fails for any reason, proceed with in-memory defaults (including `tracker.backend: markdown`). **Exceptions (deliberate hard-stops, not config-file completeness problems):** step 7 Linear validation (and missing `linear.md`) when the operator has opted into `backend: linear`; step 8 skill-root resolve when walk-up (or inherit) cannot determine an absolute skill install root. --- diff --git a/agents/go.md b/agents/go.md index b0fafdf..e164fa8 100644 --- a/agents/go.md +++ b/agents/go.md @@ -37,7 +37,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### 0b. Validate UR exists diff --git a/agents/help.md b/agents/help.md index 9f1b826..65c4a46 100644 --- a/agents/help.md +++ b/agents/help.md @@ -28,7 +28,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### 1. Detect project state diff --git a/agents/ideate.md b/agents/ideate.md index 5092803..e14f3e8 100644 --- a/agents/ideate.md +++ b/agents/ideate.md @@ -37,7 +37,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Ideate store — backend branch (ORI-9) diff --git a/agents/intake.md b/agents/intake.md index ea25f54..86fa109 100644 --- a/agents/intake.md +++ b/agents/intake.md @@ -30,7 +30,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Intake store — backend branch (ORI-9) diff --git a/agents/log.md b/agents/log.md index f8af0d5..fd538fc 100644 --- a/agents/log.md +++ b/agents/log.md @@ -31,7 +31,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. If `config.log.enabled` is `false`, stop silently — output nothing. diff --git a/agents/question.md b/agents/question.md index 8c503ea..5461792 100644 --- a/agents/question.md +++ b/agents/question.md @@ -37,7 +37,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Clarifications store — backend branch (ORI-9) diff --git a/agents/resume.md b/agents/resume.md index 5e84c19..d21ce44 100644 --- a/agents/resume.md +++ b/agents/resume.md @@ -37,7 +37,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. **Branch on effective backend** after load path: diff --git a/agents/retro.md b/agents/retro.md index 48080f6..5b7ffc0 100644 --- a/agents/retro.md +++ b/agents/retro.md @@ -2,7 +2,7 @@ You are the Retro agent in the Do Work system. Your job is to turn the write-only run ledger into a learning signal: run the deterministic rollup, interpret its stats into a human report, and regenerate the project's capture-facing calibration store. -Design contract: `docs/design/retro-learning.md`. The split is fixed — the script (`lib/retro-rollup.sh`) does arithmetic; you do judgment. Do not recompute the script's numbers; interpret them. +Design contract: `docs/design/retro-learning.md`. The split is fixed — the script (`{skill-root}/lib/retro-rollup.sh`) does arithmetic; you do judgment. Do not recompute the script's numbers; interpret them. You are read-only except for **one** calibration write (backend-selected home). You make no commits, run no deploys, and prompt the user for nothing. @@ -32,14 +32,14 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Calibration / run-notes home — backend branch (REQ-296 / REQ-297) | Concern | Markdown | Linear (`linear.md`) | |---------|----------|----------------------| | Calibration write | Truncate-write `{project}/.do-work/state/calibration.md` | **Write calibration Doc** — Team Doc `tracker.linear.calibration_doc_title` (default `do-work/calibration`), create-if-missing, **full replace** body. Create/update failure → hard-stop; never invent alternate titles or local store | -| Run history for rollup | Local `.do-work/runs/RUN-NNN.yml` via `lib/retro-rollup.sh` | **Prefer Linear first (REQ-297):** **List run notes** helper — Issue comments with `` from `append_run_note`. Fall back to local `RUN-NNN.yml` only if comments unavailable. Local files are telemetry only when `ledger.enabled` | +| Run history for rollup | Local `.do-work/runs/RUN-NNN.yml` via `{skill-root}/lib/retro-rollup.sh` | **Prefer Linear first (REQ-297):** **List run notes** helper — Issue comments with `` from `append_run_note`. Fall back to local `RUN-NNN.yml` only if comments unavailable. Local files are telemetry only when `ledger.enabled` | **When effective backend is `linear`:** do **not** write local `state/calibration.md` as the store. Use the calibration Team Doc sequence only. Fixed home — never invent alternate Doc titles. @@ -51,12 +51,12 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * 2. Still run the local rollup script when present (it chews optional telemetry): ```bash -bash lib/retro-rollup.sh +bash {skill-root}/lib/retro-rollup.sh ``` Run the script from the project root (the directory containing `.do-work/`). Capture stdout verbatim. Warnings on stderr (e.g. `skip malformed ledger row ...`) are informational; note them but do not stop. -If `lib/retro-rollup.sh` is missing **and** backend is markdown, report `"lib/retro-rollup.sh not found — cannot run retro."` and stop. If backend is linear and the script is missing but **List run notes** returned rows, continue interpreting from those notes only. +If `$SKILL_ROOT/lib/retro-rollup.sh` is missing **and** backend is markdown, report `"$SKILL_ROOT/lib/retro-rollup.sh not found — cannot run retro."` and stop. If backend is linear and the script is missing but **List run notes** returned rows, continue interpreting from those notes only. **Interpretation priority under Linear:** @@ -152,4 +152,4 @@ Print the report. Confirm the calibration home written (local path or Linear Doc - **Advisory, never blocking.** Calibration informs capture; it is not a requirement. Nothing you produce blocks the pipeline. - **No git commits, no AskUserQuestion prompts, no deploys.** - **Linear homes are fixed (REQ-296 / REQ-297).** Never invent ad-hoc Doc titles; use `calibration_doc_title` only. Prefer **List run notes** over local telemetry when backend is linear. Doc create/update failure → hard-stop (no local substitute store). -- If `lib/retro-rollup.sh` is missing under markdown, report it and stop. Under linear, missing script alone is not fatal when Linear run notes were listed successfully. +- If `$SKILL_ROOT/lib/retro-rollup.sh` is missing under markdown, report it and stop. Under linear, missing script alone is not fatal when Linear run notes were listed successfully. diff --git a/agents/review.md b/agents/review.md index d6f0129..a67a3ef 100644 --- a/agents/review.md +++ b/agents/review.md @@ -44,7 +44,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. - Review is **read-only** for work items: use `read_req` / `read_ur` as needed; **never** call `archive_req`, `claim_req`, `set_req_status`, or `append_run_note`. Review is primarily read-only against the REQ (working file or Linear Issue) and worker report; still resolve the load path so any work-item field reads go through port ops for the active backend. diff --git a/agents/run-worker.md b/agents/run-worker.md index 2ecb5c9..ecd7dab 100644 --- a/agents/run-worker.md +++ b/agents/run-worker.md @@ -24,7 +24,7 @@ The orchestrator dispatches you with these named inputs: 2. **UR input.md path** — absolute path to the originating user request brief 3. **Prior-REQ archived paths** — list of absolute paths to previously archived REQs from the same UR (may be empty) 4. **Context pack path** — absolute path to `.do-work/state/context-pack.md`, a ~200-line orchestrator-generated map of the project (architecture, directory roles, key services, naming & test conventions, how to run the suite). Read it in Step 2. -5. **Skill root** — the resolved absolute path the orchestrator loaded its instructions from (the directory containing `lib/`). Wherever these instructions write `{skill-root}/lib/...`, that means this passed-in value — substitute it. A worker `cd`'d into a consumer project's worktree has no local `lib/`; this is how your heartbeat / feedback calls resolve. +5. **Skill root** — the absolute `$SKILL_ROOT` the orchestrator resolved once in **Load Config step 8** (`agents/config.md`: walk-up from loaded instruction file with `lib/` + (`SKILL.md` or `agents/`) markers, or inherit of a valid pre-set `$SKILL_ROOT`; hard-stop if unknown) and substituted into these instructions. It is the skill install root (the directory containing `lib/` and skill markers). Wherever these instructions write `{skill-root}/lib/...`, that means this passed-in value — substitute it. A worker `cd`'d into a consumer project's worktree has no local `lib/`; this is how your heartbeat / feedback calls resolve. Do **not** invent a second resolve recipe (no env/hub/CWD fallback). If the orchestrator omitted Skill root or left `{skill-root}` unsubstituted and you cannot determine the path, hard-stop per Load Config step 8 (inherit only when the value still satisfies markers; otherwise walk-up from the loaded instruction file). **Context discipline (bounded exploration, not starvation).** Prefer the context pack and the files the REQ and prior REQs cite — they are your primary context. When the implementation genuinely touches a file (a helper you must call, a convention you must match, a test pattern you must follow), you MAY read it to do the work correctly — bounded exploration of files your change actually touches is allowed. You MUST NOT load other REQs or other URs, and you MUST NOT wander into unrelated parts of the repo for general reading. Bounded exploration serves the change in front of you; it is not a license to re-survey the whole project (that is what the context pack is for). @@ -132,7 +132,7 @@ Load config and resolve work-item storage before reading/updating REQs: **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` (including `heartbeat_req` → `lib/heartbeat.sh`) — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` (including `heartbeat_req` → `lib/heartbeat.sh`) — use those ops; do not re-implement store details here. - Runtime/git isolation (worktrees, feature branch, commit) stays local regardless of backend. - **Linear mid-flight (REQ-294):** if Linear MCP fails **after** the orchestrator already claimed this issue (`in_progress` + active claim comment) and before you finish, **leave claimed** — do not release the claim, do not write markdown REQ files as a substitute store, do not invent cleanup. Return `status: stopped` with an appropriate reason (`dependency-missing` / `unknown-error` / etc.); operator uses `/do-work resume` or `unblock` after MCP recovers. Heartbeats under Linear use **`heartbeat_req`** against the Linear issue id (not `lib/heartbeat.sh` on a local working/ file) when the orchestrator passed a Linear-backed REQ. diff --git a/agents/run.md b/agents/run.md index edade2c..02ddcba 100644 --- a/agents/run.md +++ b/agents/run.md @@ -50,9 +50,9 @@ Full budget/parallel resolution text: original detail lives in [run-loop.md](../ ## Load Config -Read and follow the **Load Config** section of [config.md](config.md). +Read and follow the **Load Config** section of [config.md](config.md), including **step 8** (resolve `$SKILL_ROOT` / `{skill-root}` via walk-up from the loaded instruction file with marker requirements, or inherit a valid pre-set `$SKILL_ROOT`; hard-stop if unknown). -Keep `model.default`, `model.escalation`, `cost.budget`, and `ledger.enabled` in context. Resolve effective budget once at startup. If non-empty, enforce at the Step 3b budget gate. +Keep `model.default`, `model.escalation`, `cost.budget`, `ledger.enabled`, and the resolved `$SKILL_ROOT` in context. Resolve effective budget once at startup. If non-empty, enforce at the Step 3b budget gate. ## Tracker load path @@ -67,7 +67,7 @@ Work-item storage goes **only** through named tracker port ops after config is l - **No silent fallback** from `linear` to `markdown`. - If backend is **`linear`** but `agents/tracker/linear.md` is missing/unreadable → **hard-stop**. -- Markdown backend: ops map to `lib/*.sh` + flows in `markdown.md`. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Claim / pick / heartbeat / archive — backend branch @@ -101,7 +101,7 @@ Full stamp lifecycle: [run-loop.md](../references/run-loop.md) § Agent Identity > Default: claim unblocked backlog; stale-slot triage is fallback when backlog empty. Working/ scan is informational, not a start gate. 1. Branch + working-directory checks; `mkdir -p {project}/.do-work/state`. -2. Resolve `AGENT_ID`; resolve `{skill-root}`; refresh context pack. +2. Resolve `AGENT_ID`; resolve `{skill-root}` / `$SKILL_ROOT` via **Load Config step 8** (`agents/config.md` — single home; hard-stop if unknown); refresh context pack. 3. Scan/classify working slots (markdown) or in-flight Linear claims — mine / sibling / stale buckets. 4. Resume any `mine` slot. 5. Try backlog (primary); else evaluate working set; else empty-backlog path. diff --git a/agents/start.md b/agents/start.md index 44cfd1e..1877787 100644 --- a/agents/start.md +++ b/agents/start.md @@ -36,7 +36,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Start store — backend branch (ORI-9) diff --git a/agents/status.md b/agents/status.md index d3f7d70..305a788 100644 --- a/agents/status.md +++ b/agents/status.md @@ -33,13 +33,13 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. **Branch the render path on effective backend** (after load path): | Backend | Work-item situation room | |---------|--------------------------| -| **`markdown`** (default) | Steps **1–2** below (`lib/synth-status.sh`, `derive-status`, `coverage-rollup`, `deadlock-check`) | +| **`markdown`** (default) | Steps **1–2** below (`{skill-root}/lib/synth-status.sh`, `derive-status`, `coverage-rollup`, `deadlock-check`) | | **`linear`** | Step **1L** — Linear claimers / heartbeats via port ops in `agents/tracker/linear.md` (**Status reporting**). Do **not** glob `.do-work/working/` or treat local REQ files as the live store. | ### 1. Render situation (markdown backend) @@ -49,28 +49,28 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * Run: ```bash -bash lib/synth-status.sh [UR-NNN] # passes the optional scope +bash {skill-root}/lib/synth-status.sh [UR-NNN] # passes the optional scope ``` Print stdout verbatim to the user. -If `lib/synth-status.sh` is missing, report `"lib/synth-status.sh not found — cannot render status."` and stop. +If `$SKILL_ROOT/lib/synth-status.sh` is missing, report `"$SKILL_ROOT/lib/synth-status.sh not found — cannot render status."` and stop. Then render a proof-backed status view. Glob REQ files in backlog, `working/`, and `archive/` (respecting `UR-NNN` scope when provided), and run: ```bash -bash lib/derive-status.sh ... +bash {skill-root}/lib/derive-status.sh ... ``` -Print the result under a `Proven` heading. This is a derived view: `proven` means the REQ is done/archived, has a non-empty `**Closure proof:**`, and does not carry `**Suite:** not-run`; `unproven` means proof is missing, the REQ is not done, or it carries the `**Suite:** not-run` marker (its own test/build suite could not be run — see `agents/run-worker.md` §6 and `agents/run.md` Step 4b sub-step 5a). If `lib/derive-status.sh` is missing, report `"lib/derive-status.sh not found — skipping proven view."` and continue. +Print the result under a `Proven` heading. This is a derived view: `proven` means the REQ is done/archived, has a non-empty `**Closure proof:**`, and does not carry `**Suite:** not-run`; `unproven` means proof is missing, the REQ is not done, or it carries the `**Suite:** not-run` marker (its own test/build suite could not be run — see `agents/run-worker.md` §6 and `agents/run.md` Step 4b sub-step 5a). If `$SKILL_ROOT/lib/derive-status.sh` is missing, report `"$SKILL_ROOT/lib/derive-status.sh not found — skipping proven view."` and continue. Then render the intended-vs-proven Coverage section: ```bash -bash lib/coverage-rollup.sh [UR-NNN] +bash {skill-root}/lib/coverage-rollup.sh [UR-NNN] ``` -Print stdout under a `Coverage` heading. Each line shows `intended= proven= unproven=`, any `unproven_ids`, and a trailing `closed=` end-to-end closure field. `closed` reports whether the UR has been validated end-to-end by `/do-work close` (per docs/design/ur-closure.md), distinct from per-REQ proof: `yes` = `UR-NNN/closure.md` exists with `overall: closed`; `no` = closure.md reports gaps, or the UR has path-unit REQs but no closure.md yet (run `/do-work close UR-NNN`); `n/a` = the UR declares no path-unit REQs to walk. `proven` still means per-REQ closure proof; `closed` means the merged whole was walked. Also compute and print a project total by summing the rows. If there are no REQs yet, show `Coverage: no REQs captured yet.` If `lib/coverage-rollup.sh` is missing, report `"lib/coverage-rollup.sh not found — skipping coverage rollup."` and continue. +Print stdout under a `Coverage` heading. Each line shows `intended= proven= unproven=`, any `unproven_ids`, and a trailing `closed=` end-to-end closure field. `closed` reports whether the UR has been validated end-to-end by `/do-work close` (per docs/design/ur-closure.md), distinct from per-REQ proof: `yes` = `UR-NNN/closure.md` exists with `overall: closed`; `no` = closure.md reports gaps, or the UR has path-unit REQs but no closure.md yet (run `/do-work close UR-NNN`); `n/a` = the UR declares no path-unit REQs to walk. `proven` still means per-REQ closure proof; `closed` means the merged whole was walked. Also compute and print a project total by summing the rows. If there are no REQs yet, show `Coverage: no REQs captured yet.` If `$SKILL_ROOT/lib/coverage-rollup.sh` is missing, report `"$SKILL_ROOT/lib/coverage-rollup.sh not found — skipping coverage rollup."` and continue. ### 1L. Render situation (Linear backend) @@ -82,7 +82,7 @@ Print stdout under a `Coverage` heading. Each line shows `intended= proven=`) via **Helper: read active claim**. - Report: **id**, title, do-work status (via inverted `status_map`), **claimer** (`agent_id`), **claimed_at**, **heartbeat**, **fresh/stale** vs effective stale max (`heartbeat_max_age_seconds` or `parallel.stale_threshold_seconds`), claim `status` (`active` / `released`). 4. **Stale banner** — if any active claim is stale, prepend a clear warning (parity with markdown stale/deadlock intent). Surface deps from authoritative `blocks` relations when tools exist. -5. **Do not** invent local REQ paths, run `lib/synth-status.sh` / glob `.do-work/working/` as the live claim source, or change Linear state (read-only). +5. **Do not** invent local REQ paths, run `{skill-root}/lib/synth-status.sh` / glob `.do-work/working/` as the live claim source, or change Linear state (read-only). 6. Optional local telemetry (e.g. gate-owner files under `state/`) may be mentioned separately; they are **not** the work-item store. Print a compact table or list under a `Linear status` heading, then stop (skip markdown Step 2 unless a local deadlock helper is useful for **runtime** locks only — never treat markdown REQ globs as Linear truth). @@ -94,7 +94,7 @@ Print a compact table or list under a `Linear status` heading, then stop (skip m Run: ```bash -bash lib/deadlock-check.sh +bash {skill-root}/lib/deadlock-check.sh ``` If output is non-empty, prepend it to the status report with a clear header: @@ -106,7 +106,7 @@ If output is non-empty, prepend it to the status report with a clear header: ──────────────────── ``` -If `lib/deadlock-check.sh` is missing, report `"lib/deadlock-check.sh not found — skipping deadlock check."` and continue without it. +If `$SKILL_ROOT/lib/deadlock-check.sh` is missing, report `"$SKILL_ROOT/lib/deadlock-check.sh not found — skipping deadlock check."` and continue without it. ### 3. Stop @@ -118,5 +118,5 @@ No prompts, no commits, no state changes. - Read-only. Never write any file under `{project}/.do-work/` or the source tree (and never write Linear issues while rendering status). - No git commits, no AskUserQuestion prompts. -- **Markdown:** If `lib/synth-status.sh` or `lib/deadlock-check.sh` are missing, report the missing script and stop (synth-status missing) or continue without the check (deadlock-check missing). The deadlock banner always renders above the synth-status output when present. +- **Markdown:** If `$SKILL_ROOT/lib/synth-status.sh` or `$SKILL_ROOT/lib/deadlock-check.sh` are missing, report the missing script and stop (synth-status missing) or continue without the check (deadlock-check missing). The deadlock banner always renders above the synth-status output when present. - **Linear:** Use only `agents/tracker/linear.md` status / claim-comment sequences; hard-stop if Linear MCP is unusable; no silent markdown situation room. diff --git a/agents/unblock.md b/agents/unblock.md index 7d18190..366c107 100644 --- a/agents/unblock.md +++ b/agents/unblock.md @@ -45,7 +45,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. **Branch on effective backend** after load path: diff --git a/agents/upgrade.md b/agents/upgrade.md index e1f7f53..59ce883 100644 --- a/agents/upgrade.md +++ b/agents/upgrade.md @@ -29,12 +29,12 @@ to `lib/conformance-scan.sh` and add its fix contract here in the same change. | row-id | detector | fix | class | |---|---|---|---| -| `legacy-dir` | `safe-blocking` drift line from `bash lib/conformance-scan.sh {project}` when `do-work/` exists and `.do-work/` does not | `git mv do-work .do-work` with fallback plain `mv`, then `.gitignore` rewrite, then consumer-ref advisory scan | auto-apply | -| `dir-conflict` | `blocking` drift line from `bash lib/conformance-scan.sh {project}` when both `do-work/` and `.do-work/` exist | none — halt with the existing conflict message | manual | +| `legacy-dir` | `safe-blocking` drift line from `bash {skill-root}/lib/conformance-scan.sh {project}` when `do-work/` exists and `.do-work/` does not | `git mv do-work .do-work` with fallback plain `mv`, then `.gitignore` rewrite, then consumer-ref advisory scan | auto-apply | +| `dir-conflict` | `blocking` drift line from `bash {skill-root}/lib/conformance-scan.sh {project}` when both `do-work/` and `.do-work/` exist | none — halt with the existing conflict message | manual | | `config-keys` | `safe-silent` missing or incomplete `.do-work/config.yml`, detected and migrated by the `agents/config.md` loader | load config per `agents/config.md`; its missing-key migration has already applied by Step 0 | auto-apply | -| `pending-dir` | `destructive` drift line from `bash lib/conformance-scan.sh {project}` when `.do-work/pending/` exists, including when empty | archive parked REQs and delete `.do-work/pending/` after explicit `AskUserQuestion` confirmation | interactive confirm | -| `stale-config-key` | `destructive` drift line from `bash lib/conformance-scan.sh {project}` when a tombstoned config key is present | remove the key line(s) from `.do-work/config.yml` — and the parent section if the removal leaves it empty — after explicit `AskUserQuestion` confirmation | interactive confirm | -| `session-hooks` | `bash lib/install-hooks.sh --check {project}` prints `absent` (session telemetry hooks missing from `.claude/settings.json`) | run `bash lib/install-hooks.sh {project}` — idempotent, additive merge | auto-apply | +| `pending-dir` | `destructive` drift line from `bash {skill-root}/lib/conformance-scan.sh {project}` when `.do-work/pending/` exists, including when empty | archive parked REQs and delete `.do-work/pending/` after explicit `AskUserQuestion` confirmation | interactive confirm | +| `stale-config-key` | `destructive` drift line from `bash {skill-root}/lib/conformance-scan.sh {project}` when a tombstoned config key is present | remove the key line(s) from `.do-work/config.yml` — and the parent section if the removal leaves it empty — after explicit `AskUserQuestion` confirmation | interactive confirm | +| `session-hooks` | `bash {skill-root}/lib/install-hooks.sh --check {project}` prints `absent` (session telemetry hooks missing from `.claude/settings.json`) | run `bash {skill-root}/lib/install-hooks.sh {project}` — idempotent, additive merge | auto-apply | | `migrate-linear` | **Optional / opt-in only** — not an auto-scan drift row (`lib/conformance-scan.sh` never emits it; see header comment there). Operator runs `/do-work upgrade migrate` (or upgrade Step 9) when they want design §12 idle markdown→Linear cutover. Detector for *eligibility* is preflight in Step 9 (working empty, no active claims, backend still markdown, Linear MCP usable) | invoke port op **`migrate_markdown_to_linear`** sequences in `agents/tracker/linear.md` (dry-run or apply). **Apply mode is destructive** — requires explicit operator confirm gate. Dry-run is non-destructive. | **destructive** interactive confirm (or dry-run) | **`session-hooks` detector location.** This row is the one exception to the @@ -78,7 +78,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. This is also the `config-keys` manifest row. If the loader creates or migrates config, report `config-keys: converged`. If it makes no changes, report @@ -89,7 +89,7 @@ config, report `config-keys: converged`. If it makes no changes, report Run: ```bash -bash lib/conformance-scan.sh "{project}" +bash {skill-root}/lib/conformance-scan.sh "{project}" ``` Interpret exit codes: @@ -240,7 +240,7 @@ For each parked REQ file under `{project}/.do-work/pending/` matching 6. Run: ```bash - bash lib/check-archive-integrity.sh "" + bash {skill-root}/lib/check-archive-integrity.sh "" ``` If the check fails for a file, stop before moving that file and report the @@ -354,7 +354,7 @@ by `conformance-scan.sh`, because the hooks live in 1. Check current state: ```bash - bash lib/install-hooks.sh --check "{project}" + bash {skill-root}/lib/install-hooks.sh --check "{project}" ``` 2. If it prints `present`, record `session-hooks: already-conformant` and @@ -362,7 +362,7 @@ by `conformance-scan.sh`, because the hooks live in 3. If it prints `absent`, apply the idempotent installer: ```bash - bash lib/install-hooks.sh "{project}" + bash {skill-root}/lib/install-hooks.sh "{project}" ``` - On `installed`, record `session-hooks: converged`. @@ -379,7 +379,7 @@ so running upgrade twice yields exactly one entry per hook. Run the scanner again: ```bash -bash lib/conformance-scan.sh "{project}" +bash {skill-root}/lib/conformance-scan.sh "{project}" ``` `pending-dir`'s outcome is derived from this re-scan, never pre-declared in diff --git a/agents/verify.md b/agents/verify.md index 15166c4..1cf01ac 100644 --- a/agents/verify.md +++ b/agents/verify.md @@ -33,7 +33,7 @@ Work-item storage (URs, REQs, decisions, verify/close reports, run notes) goes * **Hard rules:** - **No silent fallback** from `linear` to `markdown`. If backend is `linear`, do not substitute UR/REQ markdown as the store. - If backend resolves to **`linear`** but `agents/tracker/linear.md` is **missing or unreadable**, **hard-stop** with setup instructions (restore the Linear backend doc / connect Linear skill). Never fall through to markdown paths. -- Markdown backend: ops map to existing `lib/*.sh` + file flows in `markdown.md` — use those ops; do not re-implement store details here. +- Markdown backend: ops map — **invoke** coordination scripts as `bash {skill-root}/lib/...` after Load Config step 8 resolves `$SKILL_ROOT`; **catalog identity** remains `lib/*.sh` in `markdown.md` — use those ops; do not re-implement store details here. ### Verify report home — backend branch (REQ-296 / REQ-297) @@ -269,8 +269,8 @@ Non-executable step hits (Step 4g) are reported as named Issues on individual RE Run `{skill-root}/lib/score-coverage.sh` with the manifest flags and use its printed integer as the Confidence Score. Do **not** compute the deductions or base ratio by hand — the script is the single arithmetic authority. Example for an 8-full / 1-partial / 1-missing backlog with 2 layer-coverage gaps: -``` -{skill-root}/lib/score-coverage.sh --full 8 --partial 1 --missing 1 --layer-gaps 2 +```bash +bash {skill-root}/lib/score-coverage.sh --full 8 --partial 1 --missing 1 --layer-gaps 2 # → 65 ``` diff --git a/lib/doc-lint.sh b/lib/doc-lint.sh index 17a56fe..653b47a 100755 --- a/lib/doc-lint.sh +++ b/lib/doc-lint.sh @@ -107,6 +107,47 @@ scan_file() { done < "$file" } +# bare-runtime-bash-lib: runtime docs under SKILL.md, agents/, and references/ +# must invoke coordination scripts as `bash {skill-root}/lib/...` (Load Config +# step 8 / entry Project Root Detection). Bare `bash lib/` is a regression of +# the skill-root contract (UR-003 / ORI-242 / ORI-246). +# Allowlist skill-dev regression gates only under agents/ + references/: +# `bash lib/tests/...` and `bash lib/conformance-scan.sh` (tracker docs / +# CONTRIBUTING). On SKILL.md (skill entry), bare `bash lib/conformance-scan.sh` +# fails — entry conformance must use the skill-root form. A line that also +# says "never" is treated as a prohibition note documenting the anti-pattern +# (parity with same-branch + "retired"). Catalog identity `lib/*.sh` without a +# leading `bash ` is not matched. +scan_bare_runtime_bash_lib() { + local file="$1" + local line_no=0 + local line + while IFS= read -r line || [ -n "$line" ]; do + line_no=$((line_no + 1)) + case "$line" in + *'bash lib/'*) + case "$line" in + *'bash lib/tests/'*) : ;; # skill-dev regression suite (any scoped path) + *'bash lib/conformance-scan.sh'*) + case "$file" in + SKILL.md|*/SKILL.md) + # Entry hole: do not allowlist bare conformance-scan on SKILL.md. + # Permit only explicit prohibition notes (also say "never"). + case "$line" in + *never*) : ;; + *) report "$file" "$line_no" "bare-runtime-bash-lib" "$line" ;; + esac + ;; + *) : ;; # skill-dev gate under agents/ + references/ + esac + ;; + *) report "$file" "$line_no" "bare-runtime-bash-lib" "$line" ;; + esac + ;; + esac + done < "$file" +} + # --- Per-file structural check: judgment markers vs the file's own table ------- # A `> **JUDGMENT:** Jn ...` marker must have a matching `| Jn |` row in a # Judgment Points table in the SAME file. Orphan markers indicate table drift. @@ -145,6 +186,31 @@ while IFS= read -r file; do scan_judgment_markers "$file" done < "$FILES_LIST" +# Path-scoped pass: SKILL.md + agents/ + references/ (runtime invocation fences). +# SKILL.md is the skill entry (ORI-246). Not folded into DEFAULT_ROOTS so +# references/ is not subject to unrelated patterns (e.g. judgment-marker tables +# that live in agents/). Use a temp list (not a pipeline) so HITS increments in +# report() are not lost to a subshell — bash 3.2 pipelines run the right-hand +# side in a subshell. +BARE_LIST="$(mktemp -t doc-lint-bare.XXXXXX)" +trap 'rm -f "$FILES_LIST" "$BARE_LIST"' EXIT +: > "$BARE_LIST" +if [ -f SKILL.md ]; then + printf '%s\n' "SKILL.md" >> "$BARE_LIST" +fi +for root in agents references; do + [ -d "$root" ] || continue + find "$root" -type f -name '*.md' 2>/dev/null | while IFS= read -r f; do + is_excluded "$f" && continue + printf '%s\n' "$f" + done +done | sort -u >> "$BARE_LIST" +while IFS= read -r file; do + [ -z "$file" ] && continue + [ -f "$file" ] || continue + scan_bare_runtime_bash_lib "$file" +done < "$BARE_LIST" + if [ "$HITS" -ne 0 ]; then echo "" echo "doc-lint: $HITS drift hit(s) — fix the doc or extend the lint." >&2 diff --git a/lib/tests/doc-lint.test.sh b/lib/tests/doc-lint.test.sh index 1b9681b..04fee26 100755 --- a/lib/tests/doc-lint.test.sh +++ b/lib/tests/doc-lint.test.sh @@ -184,6 +184,97 @@ assert_eq "1" "$RC" "$CURRENT_CASE rc" assert_contains "dl-fixture.md:3" "$OUT" "$CURRENT_CASE file:line" teardown_fixture +# --- bare runtime `bash lib/` under agents/ (runtime invocation) -> exit 1 --- +CURRENT_CASE="bare-runtime-bash-lib-agents-exit-1" +CASES=$((CASES + 1)) +setup_fixture +printf '# Run\n\nbash lib/claim-req.sh "$REQ_PATH"\n' > "$TMP/agents/run.md" +run_lint +assert_eq "1" "$RC" "$CURRENT_CASE rc" +assert_contains "bare-runtime-bash-lib" "$OUT" "$CURRENT_CASE pattern name" +assert_contains "agents/run.md" "$OUT" "$CURRENT_CASE file" +teardown_fixture + +# --- bare runtime `bash lib/` under references/ -> exit 1 --- +CURRENT_CASE="bare-runtime-bash-lib-references-exit-1" +CASES=$((CASES + 1)) +setup_fixture +mkdir -p "$TMP/references" +printf '# Loop\n\nREQ_PATH=$(bash lib/pick-req.sh "$SCOPE" "$AGENT_ID")\n' > "$TMP/references/run-loop.md" +run_lint +assert_eq "1" "$RC" "$CURRENT_CASE rc" +assert_contains "bare-runtime-bash-lib" "$OUT" "$CURRENT_CASE pattern name" +assert_contains "references/run-loop.md" "$OUT" "$CURRENT_CASE file" +teardown_fixture + +# --- skill-dev allowlist: bash lib/tests/... under agents/ -> exit 0 --- +CURRENT_CASE="bare-runtime-bash-lib-allowlist-tests-exit-0" +CASES=$((CASES + 1)) +setup_fixture +mkdir -p "$TMP/agents/tracker" +printf '# Markdown\n\nRun `bash lib/tests/run-all.sh` as the regression gate.\n' > "$TMP/agents/tracker/markdown.md" +run_lint +assert_eq "0" "$RC" "$CURRENT_CASE rc" +teardown_fixture + +# --- skill-dev allowlist: bash lib/conformance-scan.sh under agents/ -> exit 0 --- +CURRENT_CASE="bare-runtime-bash-lib-allowlist-conformance-exit-0" +CASES=$((CASES + 1)) +setup_fixture +mkdir -p "$TMP/agents/tracker" +printf '# Port\n\n`bash lib/conformance-scan.sh` remains the regression gate.\n' > "$TMP/agents/tracker/port.md" +run_lint +assert_eq "0" "$RC" "$CURRENT_CASE rc" +teardown_fixture + +# --- correct skill-root form is allowed under agents/ -> exit 0 --- +CURRENT_CASE="skill-root-bash-lib-agents-exit-0" +CASES=$((CASES + 1)) +setup_fixture +printf '# Run\n\nbash {skill-root}/lib/claim-req.sh "$REQ_PATH"\n' > "$TMP/agents/run.md" +run_lint +assert_eq "0" "$RC" "$CURRENT_CASE rc" +teardown_fixture + +# --- bare bash lib/ outside agents/, references/, and SKILL.md is out of scope -> exit 0 --- +CURRENT_CASE="bare-bash-lib-docs-out-of-scope-exit-0" +CASES=$((CASES + 1)) +setup_fixture +printf '# How\n\nHistorically agents ran bash lib/claim-req.sh from CWD.\n' > "$TMP/docs/HOW-IT-WORKS.md" +run_lint +assert_eq "0" "$RC" "$CURRENT_CASE rc" +teardown_fixture + +# --- bare runtime `bash lib/conformance-scan.sh` in SKILL.md (entry) -> exit 1 --- +# Entry must use skill-root form; skill-dev allowlist does NOT apply on SKILL.md. +CURRENT_CASE="bare-runtime-bash-lib-skill-md-exit-1" +CASES=$((CASES + 1)) +setup_fixture +printf '# Skill\n\nbash lib/conformance-scan.sh "{project}"\n' > "$TMP/SKILL.md" +run_lint +assert_eq "1" "$RC" "$CURRENT_CASE rc" +assert_contains "bare-runtime-bash-lib" "$OUT" "$CURRENT_CASE pattern name" +assert_contains "SKILL.md" "$OUT" "$CURRENT_CASE file" +teardown_fixture + +# --- correct skill-root form in SKILL.md -> exit 0 --- +CURRENT_CASE="skill-root-bash-lib-skill-md-exit-0" +CASES=$((CASES + 1)) +setup_fixture +printf '# Skill\n\nbash {skill-root}/lib/conformance-scan.sh "{project}"\n' > "$TMP/SKILL.md" +run_lint +assert_eq "0" "$RC" "$CURRENT_CASE rc" +teardown_fixture + +# --- SKILL.md prohibition note documenting the bare form (contains "never") -> exit 0 --- +CURRENT_CASE="bare-runtime-bash-lib-skill-md-never-note-exit-0" +CASES=$((CASES + 1)) +setup_fixture +printf '# Skill\n\n(**never** bare `bash lib/conformance-scan.sh` — use skill-root form)\n' > "$TMP/SKILL.md" +run_lint +assert_eq "0" "$RC" "$CURRENT_CASE rc" +teardown_fixture + echo "" echo "doc-lint tests: $CASES cases, $FAILED failure(s)" if [ "$FAILED" -ne 0 ]; then diff --git a/references/run-loop.md b/references/run-loop.md index e812df6..2cf5856 100644 --- a/references/run-loop.md +++ b/references/run-loop.md @@ -83,17 +83,9 @@ AGENT_ID="$(hostname).$$" ### 2a. Resolve `{skill-root}` to a concrete absolute path -`{skill-root}` is the directory these agent instructions were loaded from — the root of the do-work skill clone (the directory containing `agents/`, `lib/`, `SKILL.md`). The lib invocations throughout this file (`{skill-root}/lib/scan-stale.sh`, etc.) and in `agents/run-worker.md` (heartbeat, file-feedback) only resolve when `{skill-root}` is a real absolute path. A worker `cd`'d into a consumer project's worktree has no `lib/` of its own, so the orchestrator must resolve `{skill-root}` **once here** and substitute the concrete path into every `{skill-root}/lib/...` call it makes, and pass it to the worker (Step 2 dispatch) so the worker substitutes it too. +**Single home:** resolve once via **Load Config step 8** in [`agents/config.md`](../agents/config.md) (walk-up from loaded instruction file with marker requirements + inherit of a valid `$SKILL_ROOT`; hard-stop if the path is unknown). Keep `$SKILL_ROOT` in context for this run. Do **not** re-implement a second full recipe here — no env/hub/CWD fallback. -Resolve it from the absolute path of the loaded agent file: - -```bash -# These instructions live at {skill-root}/agents/run.md, so the parent of agents/ is the root. -SKILL_ROOT="$(cd "$(dirname "")/.." && pwd)" -# Example: /Users/you/.claude/skills/do-work -``` - -When this project IS the do-work skill itself, `SKILL_ROOT` resolves to the project root and the lib calls work directly. When the project is any other repo, `SKILL_ROOT` points back at the skill clone where `lib/` actually lives. Use the resolved `$SKILL_ROOT` value everywhere the steps below write `{skill-root}`. +`{skill-root}` is the absolute skill install root (directory containing `agents/`, `lib/`, `SKILL.md`). Lib invocations throughout this file (`{skill-root}/lib/scan-stale.sh`, etc.) and in `agents/run-worker.md` (heartbeat, file-feedback) only resolve when `{skill-root}` is a real absolute path. A worker `cd`'d into a consumer project's worktree has no `lib/` of its own, so the orchestrator substitutes `$SKILL_ROOT` into every `{skill-root}/lib/...` call it makes and passes that same absolute value as the worker **Skill root** input (Step 2 dispatch). ### 2b. Generate or refresh the project context pack @@ -575,7 +567,7 @@ If the worker reports `status: done`, validate acceptance evidence before Step 4 ```bash # markdown: path is working/REQ file. linear: pass issue id / exported body via port read_req — same evidence rules; do not invent a second store. -bash lib/check-acceptance-evidence.sh {project}/.do-work/working/REQ-NNN-slug.md +bash {skill-root}/lib/check-acceptance-evidence.sh {project}/.do-work/working/REQ-NNN-slug.md ``` If validation fails, treat the result as `status: stopped`, `reason: verification-failing`, surface the validator diagnostics, and do not merge, write closure proof, review, or archive. **Under Linear: do not call `archive_req`** — issue stays `in_progress`/`stopped` with claim protocol intact (optional `set_req_status` → stopped + `append_run_note`). This gate extends the checkpoint/closure-proof model; it does not replace `closure_proof`. @@ -591,7 +583,7 @@ If validation fails, treat the result as `status: stopped`, `reason: verificatio Before dispatching review, run deterministic policy checks using changed files, command evidence, and REQ metadata: ```bash -bash lib/check-policy.sh \ +bash {skill-root}/lib/check-policy.sh \ --project {project} \ --files \ --commands \ @@ -672,7 +664,7 @@ When `ledger.enabled` is true (either backend), record one append-only local run Finalize the (local) ledger after the attempt reaches a terminal outcome: ```bash -bash lib/run-ledger.sh \ +bash {skill-root}/lib/run-ledger.sh \ --project {project} \ --req \ --agent \ @@ -706,7 +698,7 @@ When the budget is non-empty: 1. Sum cumulative estimated spend for this run from the ledger: ```bash - SPENT="$(bash lib/run-ledger.sh --sum-run {project}/.do-work/runs)" + SPENT="$(bash {skill-root}/lib/run-ledger.sh --sum-run {project}/.do-work/runs)" ``` 2. Compare `SPENT` against the effective `BUDGET` (numeric, same dollar unit): - **`SPENT < BUDGET` ⇒ under budget.** Continue normally to Step 4 (Integrate) and loop.