The Matt Pocock engineering skills (triage, to-tickets, to-spec, research, implement) assume per-repo config for three things: where work items live, what the triage label vocabulary is, and where domain docs sit. Nothing here declared any of them, so every skill run re-guessed. Frank's decisions, 2026-10-20: Gitea on Dankclaw as the tracker (no gh, no tea on any box, so it is recorded as prose — auth via a 600 curl config, the endpoint table, the 404-on-empty-token / form-encoded-merge / empty-200-on-merge traps, and the AGENTS.md laws a skill must not renegotiate); the canonical triage label vocabulary kept as-is, with the five labels created on the tracker (the repo had zero, so nothing collides); single-context domain docs. The configuration moved out of the skill's default docs/agents/ and into the one knowledge base this repo allows: three pages under omp-docs/skills/, an empty omp-docs/decisions/ carrying the ADR format rule, an "## Agent skills" pointer block in AGENTS.md, index entries, and a log entry. The glossary is deliberately not created — every candidate term already has an owner in system/, core/ or skills/, and a term list that paraphrases them is a second owner of facts already written down. Known cost: re-running setup-matt-pocock-skills will not recognise omp-docs/skills/* and will offer to recreate docs/agents/; the AGENTS.md pointer is what stops that. Also closes a verification gap found on the way: kb-lint.bats only ever points the linter at fixtures, so a page with no frontmatter or an index that stops listing a file passes the suite silently. Two tests now run the linter and the coverage checker against the shipped omp-docs/ tree. Refs #18
77 lines
3.5 KiB
Markdown
77 lines
3.5 KiB
Markdown
---
|
|
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.
|