diff --git a/AGENTS.md b/AGENTS.md index 82a625a..faa1f32 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -86,6 +86,28 @@ never committed, only surfaced. Conflicts abort and alert (ntfy); it never force-pushes, auto-resolves, or uses `--no-verify`. Details: [omp-docs/tools/live-sync.md](omp-docs/tools/live-sync.md). +## Agent skills + +The engineering skills (`triage`, `to-tickets`, `to-spec`, `research`, +`implement`, …) read their per-repo configuration from three pages in the +knowledge base. Those pages own their facts; this is only the pointer. + +### Issue tracker + +Work items are Gitea issues on `dank/command-center` (Dankclaw, +`192.168.0.143:3000`) — no `gh`, no `tea`. See +[`omp-docs/skills/issue-tracker.md`](omp-docs/skills/issue-tracker.md). + +### Triage labels + +The five canonical roles, each label string equal to its name. See +[`omp-docs/skills/triage-labels.md`](omp-docs/skills/triage-labels.md). + +### Domain docs + +Single-context, inside the existing knowledge base: `omp-docs/glossary.md` and +`omp-docs/decisions/`. See [`omp-docs/skills/domain-docs.md`](omp-docs/skills/domain-docs.md). + ## Secret gate (HARD rule) The pre-commit hook (`.githooks/pre-commit`, enabled via diff --git a/omp-docs/decisions/index.md b/omp-docs/decisions/index.md new file mode 100644 index 0000000..9f3755e --- /dev/null +++ b/omp-docs/decisions/index.md @@ -0,0 +1,26 @@ +# Architecture decision records + +Decisions this repo has made and will not silently revisit. One file per +decision, named `NNN-.md`, listed here — an unlisted page fails `kb-lint` +and does not exist as far as any agent is concerned. + +**No ADRs yet.** The first one lands the moment a decision stops being +reversible. + +## Format + +Same shape as the `dank/dankvoice` decision records, which read well under time +pressure: + +- `# (YYYY-MM-DD)` — a title you can disagree with. +- **Root** — the situation and the evidence that forced the question, with measured + output rather than recollection where measurement exists. +- **Decision** — what was chosen, and the rule an agent must follow because of it. +- **Rejected** — the alternatives and the specific reason each was turned down, so + nobody spends an afternoon rediscovering them. +- **Verification** — what was run to prove the decision holds, and where that + proof lives. + +Frontmatter is required like any other page in this bundle (`type: decision`), and +an ADR that a code change has superseded gets an amendment section appended rather +than a rewrite: the point of the record is that the reasoning is still readable. diff --git a/omp-docs/index.md b/omp-docs/index.md index 1830896..376e07a 100644 --- a/omp-docs/index.md +++ b/omp-docs/index.md @@ -60,6 +60,11 @@ search practices, open models, MCP. Pre-pruning census of every userspace config on this box — the input for the pruning session. +## [Decisions](decisions/index.md) + +Architecture decision records — the choices that are no longer up for debate, +with what was rejected and why. Currently empty; the format rule is in its index. + ## [Change history](log.md) Chronological update history of this bundle — incident lessons land here first, diff --git a/omp-docs/log.md b/omp-docs/log.md index cf9d3a6..ec464bb 100644 --- a/omp-docs/log.md +++ b/omp-docs/log.md @@ -16,6 +16,22 @@ lesson, a few lines. Full incident narratives are recoverable from git (`git log --follow omp-docs/log.md`); knowledge that outlives an entry lives on its concept page, linked here. Never re-expand an entry in place. +## 2026-10-20 — engineering skills configured against this KB + +`setup-matt-pocock-skills` ran, and its output moved out of the skill's default +`docs/agents/` into the knowledge base: [issue tracker](skills/issue-tracker.md) +(Gitea on Dankclaw is the tracker — no `gh`, no `tea`, token via a `600` curl +config), [triage labels](skills/triage-labels.md) (the five canonical roles, +created on the repo, which carried zero labels before), [domain +docs](skills/domain-docs.md) (single-context; glossary withheld until a term has +no other owner), plus an empty [decisions](decisions/index.md) with its format +rule. `AGENTS.md` gained an `## Agent skills` pointer block. Law: this repo has +one knowledge base, so per-tool configuration is a concept page in `omp-docs/` — +a second `docs/` tree means a second set of index rules, which is where +documentation starts disagreeing with itself. Known cost: re-running that setup +skill will not recognise `omp-docs/skills/*` and will offer to recreate +`docs/agents/`; the `AGENTS.md` pointer is the thing that stops it. + ## 2026-10-19 — dankvoice auto-speak armed at startup Sessions spoke only on explicit `/say`: the settings file carried no `auto` diff --git a/omp-docs/skills/domain-docs.md b/omp-docs/skills/domain-docs.md new file mode 100644 index 0000000..087f3a3 --- /dev/null +++ b/omp-docs/skills/domain-docs.md @@ -0,0 +1,51 @@ +--- +type: reference +title: Domain docs layout and consumer rules +description: Single-context domain documentation for dank/command-center — glossary and ADRs live inside the omp-docs knowledge base, not at the repo root. +tags: + - skills + - documentation + - okf + - agents +timestamp: 2026-10-20 +--- + +# Domain docs: single-context, inside the KB + +One domain, one glossary, one ADR folder — and all of it inside the existing +knowledge base, because this repo caps its root at "config, docs, scripts, +harness dirs" and `omp-docs/` is the one knowledge base. A `docs/` tree at the +repo root would be a second KB with a second set of index rules, which is exactly +how documentation starts disagreeing with itself. + +| Kind | Path | Status | +|---|---|---| +| Glossary | `omp-docs/glossary.md` | deliberately not created yet | +| ADRs | `omp-docs/decisions/NNN-.md`, listed by its `index.md` | directory exists, empty | +| Facts | the rest of `omp-docs/` | existing concept pages own them | + +## Consumer rules + +1. Read [the KB index](/index.md), then the relevant directory's `index.md`, then + the concept page. That is AGENTS.md's existing discipline; the engineering + skills follow it instead of inventing a second entry point. +2. Read the ADRs that govern an area before changing that area, and write one the + moment a decision stops being reversible. An ADR records the choice, the + reasons, and what was rejected — the part that stops a later agent from + re-litigating it. +3. Do not confuse the neighbours. [Research](/research/index.md) is decision + *support* and explicitly not fact. [log.md](/log.md) is chronology, where + incident lessons land before settling into concept pages. An ADR is neither: it + is the decision itself, dated, and it stays true after the code moves on. +4. One fact, one owner. If a glossary term or an ADR sentence restates a concept + page, the concept page wins and the duplicate is deleted. + +## Why the glossary is withheld + +A glossary earns its bytes when it holds terms no other page owns. The obvious +candidates already have owners: host roles in [system](/system/index.md), agent +configuration in [core](/core/index.md), skill tiers in +[skills](/skills/index.md). A term list that paraphrases those is a second owner +of facts already written down, and the first thing to go stale. Create +`omp-docs/glossary.md` when a real term has nowhere else to live, and list it in +the KB index the same commit you create it. diff --git a/omp-docs/skills/index.md b/omp-docs/skills/index.md index 8424b51..b257cb7 100644 --- a/omp-docs/skills/index.md +++ b/omp-docs/skills/index.md @@ -9,6 +9,9 @@ installer CLI, this fleet's provisioning tiers, and the registries. * [Skills CLI](skills-cli.md) — `npx skills`: commands, sources, scopes, discovery, lock file, agent registry. * [Skill Store Wiring](store-wiring.md) — the three skill tiers on Dank workstations and how omp loads them. * [Skills Ecosystem](ecosystem.md) — registries, the skills.sh leaderboard API, live install snapshot. +* [Issue Tracker](issue-tracker.md) — Gitea on Dankclaw as the tracker for the engineering skills: auth via a `600` curl config, the endpoint table, the 404-on-empty-token and form-encoded-merge traps. +* [Triage Labels](triage-labels.md) — the five canonical role labels as they exist on the tracker, and what renaming one costs. +* [Domain Docs](domain-docs.md) — single-context layout inside this KB: glossary and ADR paths, the read-before-acting rules, and why the glossary is still empty. Pi-era skill packaging (`pi install npm:...`, the `pi` package manifest) is archived under [pi](/pi/index.md). diff --git a/omp-docs/skills/issue-tracker.md b/omp-docs/skills/issue-tracker.md new file mode 100644 index 0000000..87fe013 --- /dev/null +++ b/omp-docs/skills/issue-tracker.md @@ -0,0 +1,76 @@ +--- +type: reference +title: Issue tracker for engineering skills +description: Where work items live for dank/command-center — Gitea on Dankclaw — with the exact API mechanics, traps, and laws the engineering skills must follow. +tags: + - skills + - gitea + - sdlc + - agents +timestamp: 2026-10-20 +verified: 2026-10-20 +--- + +# Issue tracker: Gitea on Dankclaw + +Issues and PRs for this repo live in Gitea: `dank/command-center` at +`http://192.168.0.143:3000`. There is no `gh` and no `tea` on any box — talk to +the REST API with `curl`. + +## Authentication + +The token lives in `~/.config/secrets/gitea` (never embedded in a remote URL, +never committed). Hand it to curl as a `600`-permission config file: `-H` puts it +in world-readable `/proc//cmdline`. + +```bash +tok=$(sed -nE 's#^https?://[^:/@]+:([^@]+)@192\.168\.0\.143.*#\1#p' ~/.config/secrets/gitea | head -1) +[ "${#tok}" -ge 40 ] || { echo "token extraction failed"; exit 1; } +cfg=$(mktemp); chmod 600 "$cfg"; printf 'header = "Authorization: token %s"\n' "$tok" > "$cfg" +curl -sS -K "$cfg" … ; shred -u "$cfg" +``` + +Assert the length before posting anything. **An empty token answers `404 not +found`, not `401`** — Gitea hides the private repo, so a 404 on a path that worked +yesterday is an auth failure rather than a typo. The awk-style alternative that +splits the store line on `/` silently yields an empty variable, because the host +sits in field three. Deeper detail: [Gitea client access](/tools/gitea/client-access.md). + +Multi-line bodies: build the JSON with `python3 -c 'json.dumps(...)'` reading the +body from a file. Never pass `---` as a bare `jq` argument (it parses as a flag), +and never escape quotes inside a single-quoted `python3 -c`. + +## Endpoints the skills use + +| Action | Call | +|---|---| +| Open a work item | `POST /api/v1/repos/dank/command-center/issues` `{title, body}` | +| Correct a body afterwards | `PATCH …/issues/N` (works on PRs too — a PR is an issue) | +| Open a PR | `POST …/pulls` `{title, body, base: "main", head: }` — JSON accepted here | +| Merge | `POST …/pulls/N/merge` **form-encoded**: `do=merge`, `merge_style=no-ff` | +| Labels | `GET` / `POST …/labels` | + +Three traps that cost time before: + +- `POST /pulls` answers `409 … already exists for these targets` when the branch + already has a PR (Frank clicks Create from the push message). `GET + /pulls?state=all`, find it, `PATCH` it — do not re-post. +- A JSON merge body (`{"Do":"merge"}`) returns `422 {"message":"[Do]: Required"}`. + The field name is lowercase `do` and the body must be form-encoded. +- A successful merge returns `200` with an **empty body**. Verify by landing a + checkout (`git merge --ff-only origin/main`), never by re-reading the PR. + +## Laws inherited from AGENTS.md + +A skill working in this repo does not get to renegotiate these: + +- A work item is a Gitea issue. Anything with more than one moving part gets the + issue before the branch. Branch naming `/-`, PRs target + `main` directly, merge with `--no-ff`. +- **Never merge without Frank's explicit per-PR OK**, and `xdg-open` the PR URL + into his browser the moment it exists — he should not have to hunt for it. +- Every issue and PR body ends with `---`, then `cwd: · session: + `. The session id is the UUID of the transcript file being appended + to right now (`ls -l --time-style=+%H:%M:%S ~/.omp/agent/sessions//*.jsonl`), + not the session directory name — one cwd can hold several sessions. +- `git * --no-verify` is forbidden; the pre-commit hook is the secret gate. diff --git a/omp-docs/skills/triage-labels.md b/omp-docs/skills/triage-labels.md new file mode 100644 index 0000000..6c4471d --- /dev/null +++ b/omp-docs/skills/triage-labels.md @@ -0,0 +1,40 @@ +--- +type: reference +title: Triage label vocabulary +description: The five canonical triage roles and the exact Gitea label strings applied to dank/command-center issues. +tags: + - skills + - gitea + - triage + - agents +timestamp: 2026-10-20 +verified: 2026-10-20 +--- + +# Triage labels + +Canonical vocabulary, unchanged: the label string equals the role name. Created +on `dank/command-center` on 2026-10-20 — the repo carried zero labels before that, +so nothing collides and nothing needs renaming. + +| Label | Means | +|---|---| +| `needs-triage` | filed, not yet read by a human or agent | +| `needs-info` | blocked on a question back to the reporter | +| `ready-for-agent` | specified enough to implement without further decisions | +| `ready-for-human` | needs a human decision, credential, or judgement first | +| `wontfix` | decided against; keep the record, close it | + +The `triage` skill applies and removes these strings directly, so a label must +exist on the tracker before it can be applied: + +```bash +curl -sS -K "$cfg" -X POST -H 'content-type: application/json' \ + -d '{"name":"ready-for-agent","color":"0e8a16"}' \ + http://192.168.0.143:3000/api/v1/repos/dank/command-center/labels +``` + +Renaming is a two-sided edit — change the strings here *and* on the tracker, or +`triage` starts failing to apply them. Adding near-duplicates (`needs-reinfo`, +`ready-for-ai`) is worse than either option: two labels for one role means no +issue reliably carries either. diff --git a/tests/kb-lint.bats b/tests/kb-lint.bats index 79fead1..b7868fb 100755 --- a/tests/kb-lint.bats +++ b/tests/kb-lint.bats @@ -90,3 +90,18 @@ EOF run bash "$LINT" "$KB/no-such-dir" [ "$status" -eq 2 ] } + +@test "the shipped knowledge base itself is conformant" { + # The tests above exercise the linter against fixtures; nothing else in the + # suite ever points it at the real bundle, so a page added without frontmatter + # or an index that stops listing a file passes CI silently. This is the gate. + run bash "$BATS_TEST_DIRNAME/../scripts/kb-lint.sh" "$BATS_TEST_DIRNAME/../omp-docs" + [ "$status" -eq 0 ] + [[ "$output" == *"0 violation(s)"* ]] +} + +@test "every page in the shipped knowledge base is listed by an index" { + run python3 "$BATS_TEST_DIRNAME/../scripts/kb-coverage.py" "$BATS_TEST_DIRNAME/../omp-docs" + [ "$status" -eq 0 ] + [[ "$output" == *"0 issue(s)"* ]] +}