# 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 ∈ 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 ` 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: · session: ` (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](omp-docs/tools/live-sync.md). ## Secret gate (HARD rule) The pre-commit hook (`.githooks/pre-commit`, enabled via `git config core.hooksPath .githooks`) scans every staged diff for live-secret shapes (`sk-…`, `ghp_…`, `github_pat_…`, `glpat-…`, `xox…`, `AKIA…`, PEM headers, JWTs) and blocks the commit. Quarantine list — never tracked, ever: `auth.json`, `.env`, `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. ## Machine facts (verify before trusting) | box | role | GPU | notes | |-----|------|-----|-------| | Dev workstation | client box, never runs inference | laptop iGPU + dGPU (non-unified) | mainline llama.cpp at `~/GitPackages/llama.cpp/build/bin/`; this repo lives here at `~/.omp` | | 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 embed the token locally in `.git/config` — 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 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.