Files
command-center/AGENTS.md
T
Frank 04f93133fc Close the secret-gate scope hole, and make it fail closed
The gate scanned only `*.md *.yml *.yaml *.json *.toml *.sh *.ts *.js`. A
`postgres.env`, a `.container` quadlet, an `.ini`, or an extension-less dotfile
— exactly the shapes the dotfiles tier is made of — was never read at all.
Discovered while deciding what else belongs in `dotfiles/`: `~/.config`
carries `containers/systemd/postgres.env` with a real `POSTGRES_PASSWORD`,
which the ignore list did not cover either (`git check-ignore` says so: `.env`
does not match `postgres.env`).

Token SHAPES now scan the entire staged diff, every file type; bcrypt hashes
and `Authorization: Basic` headers joined the shape list. Credential
ASSIGNMENTS are scanned in non-prose files only — the auto-learned memory tier
is prose *about* credentials (7 such hits measured on the tracked tree), and a
gate that fires there gets overridden until it means nothing. Markdown keeps
shape detection, which is what it had before.

Three invariants, each pinned by a test in tests/secret-gate.bats (13 tests,
black-box: the hook is copied into a scratch repo and git itself runs it):

- Fail closed. The first version of this rewrite passed `-I` to `git diff`,
  which is not valid there; the empty file list made every secret commit sail
  through, and a blind gate looks exactly like a clean tree. If the hook cannot
  read the staged diff it now refuses the commit.
- Only ADDED lines can leak. The gate refused the redaction commit in this
  branch because the diff still carried the removed password — a gate that
  blocks the removal of a secret holds the leak hostage.
- Path-valued variables (`…_FILE=`, `…_PATH=`) and placeholder/indirected
  values are not secrets, so the gate stays worth listening to.

`.gitignore` quarantines `*.env` at any name, and gains the theme-media rule
whose untracking lands in the next commit. `AGENTS.md` states the new contract.

Refs #40
2026-10-20 16:48:33 -07:00

9.6 KiB
Raw Blame History

AGENTS.md — ~/.omp command center

System-configuration command center for Frank's fleet: agent config, knowledge base, small system utilities, and (soon) dotfiles. You — the reader — are probably an agent running on one of Frank's workstations with this repo as your working directory. Read omp-docs/index.md before you touch anything. This file is the operating contract; omp-docs/ is the knowledge base (OKF v0.1 format: directory of markdown files with YAML frontmatter, spec at omp-docs/references/okf-spec.md).

What this repo is

  • The live agent-config directory AND a git repo pushed to Gitea (dank/command-center on the Dankclaw instance). There is no staging copy: the checkout is the deployment. Branch switches swap live config files out from under the running agent — keep feature branches short-lived, and never end a work session checked out on anything but main.
  • Contents that belong here: AGENTS.md, omp-docs/ (knowledge base), scripts/ (small system utilities), agent/ + plugins/ (harness config and plugin manifests). Everything else under this directory is runtime state and is gitignored on principle — see .gitignore. History must mean "the configuration changed", not "the agent breathed".

Trunk-based SDLC (since 2026-10-18; replaces the old git-flow regime)

  • main is the only long-lived branch. Frank is the only dev; develop and the release-branch ceremony are retired — no develop, no back-merges, no release/X.Y.Z branches.
  • Before every work item: fetch and branch off the freshest origin/main. If main moves under you, merge it into your branch (never rebase — Frank dislikes the history rewrite).
  • Work item = Gitea issue on dank/command-center (Gitea at 192.168.0.143:3000, owner dank). Small fixes may go straight to a branch; anything with more than one moving part gets an issue first.
  • Branch naming: <type>/<issue#>-<slug>, type ∈ feat|fix|docs|chore.
  • Pull requests target main directly. Merge with --no-ff so feature arcs stay visible in history. Never merge a PR without an explicit OK from Frank.
  • The moment a PR is open, open it in Frank's browser — xdg-open <PR-URL> lands a tab in his Firefox; never make him hunt for it in Gitea.
  • Attribution footer (issues and PRs) — every issue or PR body you open ends with a --- line, then cwd: <working directory> · session: <omp session id> (session id from /status; cwd is that session's own working directory — not the build checkout, when they differ). Machine-made artifacts stay attributable to the box and session that spawned them.
  • Releases: tag vX.Y.Z straight on main after verifying; tags are the deploy markers every other machine pulls to. Hotfixes are ordinary branches off the tag you are fixing forward from.
  • Trash convention: never rm anything user-authored — move it to .AGENTTRASH/ (gitignored). Deletion is a pruning session with Frank present.

Commit hygiene (mirrors dank/serverAppConfigs)

The law is imported from the serverAppConfigs repo — checkout on the dev box at ~/Projects/serverAppConfig, see its AGENTS.md § Git Workflow and § Testing ("All edits flow through git", "tests are mandatory before commit"). Applied here:

  • git pull before starting new work; start from a clean tree. The checkout IS the deployment here — a dirty tracked file is a half-deployed config serving the live agent.
  • Commit atomically and early: one commit = one complete functional unit, never a pile of half-edited files; docs land in the same commit as the change they document.
  • bats tests/ green + the pre-commit secret gate = the commit precondition; the full suite runs at pre-push.
  • Push to the local Gitea as soon as a unit is green — every other workstation pulls from there. git * --no-verify is forbidden (the secret gate is the point of the hook).
  • Messages: imperative mood, what + why, Refs #N when a Gitea issue exists.

Live-sync tiers (the machine is a committer too — Refs #11)

The checkout is the deployment, so several tracked files are live state written continuously through symlinks by the harness, auto-learn, and desktop GUIs. "Dirty tree" is judged by the writer:

Tier Paths Commit law
Human/agent prose AGENTS.md, omp-docs/, scripts/, plugins/, agent/skills/ branch → PR → Frank OK (unchanged)
Machine live agent/memories/, agent/managed-skills/, agent/config.yml, agent/models.yml scripts/live-sync.sh heartbeat
Desktop live dotfiles/ same heartbeat

The heartbeat (systemd user timer, hourly) stages ONLY allowlisted tiers, commits with hooks armed — the secret gate included — merges origin/main, pushes, and reaps wt/* worktrees older than 7 days. Non-allowlist dirt is 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.

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.

Triage labels

The five canonical roles, each label string equal to its name. See 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.

Secret gate (HARD rule)

The pre-commit hook (.githooks/pre-commit, enabled via git config core.hooksPath .githooks) blocks the commit in two ways. Token shapes (sk-…, ghp_…, github_pat_…, glpat-…, xox…, AKIA…, PEM headers, JWTs, bcrypt hashes, Authorization: Basic headers) are scanned across the entire staged diff — every file type, because the first version of the gate whitelisted extensions and never read a .env, .container, .ini, or extension-less dotfile at all. Credential assignments (PASSWORD=…, secret_key: …) are scanned in non-prose files only; markdown keeps shape detection, because the auto-learned memory tier is prose about credentials and a gate that fires there gets overridden until it means nothing. The gate fails closed: if it cannot read the staged diff it refuses the commit rather than passing it. Quarantine list — never tracked, ever: auth.json, .env and *.env (postgres.env, frank-job-hunt.env are the ones that carry real values), trust.json, *.pem, *.key, identity*. Deliberate override: ALLOW_SECRETS=1 git commit …. Remember why: a secret in a tracked file is a secret in every agent's context window on every machine that pulls this repo, and redacting it later does not un-leak the history.

Machine facts (verify before trusting)

box role GPU notes
Dev workstation (blankpad) client box, never runs inference Lenovo laptop, AMD Ryzen 5 PRO 5650U / Cezanne APU (unified memory, s2idle sleep only, no dGPU) this repo lives here at ~/.omp; the earlier "iGPU + dGPU / ~/GitPackages/llama.cpp" description belonged to the sold dankware box
Dankclaw bench target, secondary models + service stack Strix Halo APU (unified memory) + RTX 3090 (moved over from Dankserver 2026-09) prod services frank-dragoon (halogen-flash-server, :7770, iGPU) and frank-zealot (llama.cpp PrismML fork, :7771, 3090); runbooks in the serverAppConfigs vault (~/Projects/serverAppConfig/serverAppConfigs-docs/LLM/); ssh: ssh dankclaw
Dankserver main-model box 2× Radeon AI PRO R9700 — non-unified (was RTX 3090 until 2026-09) runs frank-archon (radiance, TP=2, :7770) — this repo's operator session runs on it; ssh: ssh dankserver

Environment gotchas

  • Gitea API needs a token: GITEA_TOKEN env (gitignored .env). No tea CLI installed anywhere. Remote URLs carry NO embedded token (2026-10-09 credential-store cutover) — git and the API both read ~/.config/secrets/gitea (store --file, URL-line format; see omp-docs/tools/gitea/client-access.md). That file is never pushed; it is not a substitute for the secret gate.
  • Passwordless sudo (sudo -n) works on Dankclaw and Dankserver for systemctl verbs only; user units need no sudo at all.
  • SSH into both servers is BatchMode-capable from here: ssh -o BatchMode=yes dankclaw '<read-only command>' — read-only probes are always allowed; state changes on remote boxes are not, without a per-run OK.
  • frank-archon (Dankserver), frank-dragoon, and frank-zealot (Dankclaw) are production services shared with this repo's operator: never stop, mask, or restart them (or any production service on any box) without an explicit, current, per-run OK from Frank.

File-organization doctrine (why this repo stays readable)

  • One concept, one file; directories get an index.md listing their contents — that's the OKF contract, and it is also the anti-rot mechanism: nothing may appear in a directory that its index.md doesn't list.
  • Root of the repo is capped: config, docs, scripts, harness dirs. A new top-level entry requires a commit message that justifies itself.
  • Runtime state (dbs, logs, caches, sessions) is gitignored on principle — if you feel the urge to commit one of those, stop and reread this section.