Merge pull request 'Configure the engineering skills against this repo and this KB' (#39) from feat/agent-skills-config into main

This commit was merged in pull request #39.
This commit is contained in:
2026-10-20 16:14:43 -07:00
9 changed files with 254 additions and 0 deletions
+22
View File
@@ -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
+26
View File
@@ -0,0 +1,26 @@
# Architecture decision records
Decisions this repo has made and will not silently revisit. One file per
decision, named `NNN-<slug>.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:
- `# <Decision as a claim> (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.
+5
View File
@@ -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,
+16
View File
@@ -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`
+51
View File
@@ -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-<slug>.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.
+3
View File
@@ -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).
+76
View File
@@ -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/<pid>/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: <branch>}` — 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 `<type>/<issue#>-<slug>`, 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 cwd> · session:
<session id>`. 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/<cwd-dir>/*.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.
+40
View File
@@ -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.
+15
View File
@@ -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)"* ]]
}