Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54f5555470 | ||
|
|
e52aa6a4a3 | ||
|
|
d8647ef5cd | ||
|
|
7a0062e9e8 | ||
|
|
534b221a45 | ||
|
|
8089693e58 | ||
|
|
e5d00fd91f | ||
|
|
59a89553b7 | ||
|
|
ae82aa00e4 | ||
|
|
72a3dbbe08 | ||
|
|
43c19ae74c | ||
|
|
a2b1b6d9c6 | ||
|
|
876d8cd519 | ||
|
|
c2d855b33d | ||
|
|
246189f054 | ||
|
|
04d3628c94 | ||
|
|
e0920dc067 | ||
|
|
e044700ef7 | ||
|
|
7b7dbf55c2 | ||
|
|
a4218361e2 | ||
|
|
c6fa584d0a | ||
|
|
541f27f316 | ||
|
|
e2fe36519c | ||
|
|
7fb6d36801 | ||
|
|
23901a190d | ||
|
|
d015493219 | ||
|
|
ae426434bc | ||
|
|
ae12063de9 |
@@ -13,26 +13,32 @@ with YAML frontmatter, spec at `omp-docs/references/okf-spec.md`).
|
||||
(`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 `develop` or `main`.
|
||||
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".
|
||||
|
||||
## Git-flow SDLC (full flow, from day one)
|
||||
## 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.
|
||||
Release cuts: `release/X.Y.Z` from `develop`; hotfixes: `hotfix/<slug>` from `main`.
|
||||
- **Merge, never rebase**, when updating a branch against a moved main — Frank
|
||||
dislikes the history rewrite. **Never merge a PR without an explicit OK from Frank.**
|
||||
- Merge into `develop` with `--no-ff` so feature arcs stay visible in history.
|
||||
- Releases: cut `release/X.Y.Z` from `develop`, verify, merge to `main`, tag
|
||||
`vX.Y.Z`, back-merge `main` into `develop`. Tags are the deploy markers every
|
||||
other machine pulls to.
|
||||
- **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.
|
||||
- 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.
|
||||
|
||||
@@ -56,6 +62,25 @@ commit"). Applied here:
|
||||
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
|
||||
@@ -71,8 +96,8 @@ secret in every agent's context window on every machine that pulls this repo.
|
||||
| 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, runs the large serving model | Strix Halo APU — **unified memory** | ROCmFPX fork at `~/GitPackages/ROCmFPX/build-qwen38/bin/`; prod service `frank-default-large`, port 7770; ssh: `ssh dankclaw` |
|
||||
| Dankserver | FreeToken box | RTX 3090 dGPU — non-unified | runs `frank-default-small`; ssh: `ssh dankserver` |
|
||||
| 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
|
||||
|
||||
@@ -84,9 +109,10 @@ secret in every agent's context window on every machine that pulls this repo.
|
||||
- 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-default-large` on Dankclaw is a **production service** shared with this
|
||||
repo's operator: never stop, mask, or restart it (or any production service on
|
||||
any box) without an explicit, current, per-run OK from Frank.
|
||||
- `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)
|
||||
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
# OMP — Command Center
|
||||
# Command Center
|
||||
|
||||
## Configuration repository for Frank's Userspace configurations (i.e. his desktop setup)
|
||||
|
||||
### AI Disclosures:
|
||||
- Slop rating: 3/5 - **Actively using, actively de-slopping, repository still mostly AI owned**
|
||||
- Completeness: **Unfinished, planning planned, no plan yet**
|
||||
- Datacenter model/spend: Less than $5 of Deepseek 4.1 Flash
|
||||
- Local model: Qwen 3.8 27B
|
||||
|
||||
### slop rating of 3 or higher indicates human reading is a waste of time outside of this README, and that you might as well ask an agent for help with this.
|
||||
### slop rating 3 indicates Frank is comfortable using this for professional use -- but barely.
|
||||
|
||||
|
||||
Configuration repository for Frank's homelab fleet and the agent tooling that runs on it.
|
||||
|
||||
## The Fleet
|
||||
|
||||
|
||||
+29
-3
@@ -18,7 +18,7 @@ modelRoles:
|
||||
memory: llamacpp (dankclaw-3090)/frank-zealot:medium
|
||||
symbolPreset: nerd
|
||||
composer:
|
||||
shape: claude
|
||||
shape: band
|
||||
theme:
|
||||
dark: dark-terminal
|
||||
light: light
|
||||
@@ -99,11 +99,37 @@ disabledExtensions:
|
||||
[]
|
||||
statusLine:
|
||||
separator: powerline
|
||||
preset: nerd
|
||||
preset: custom
|
||||
contextLine: embedded
|
||||
transparent: true
|
||||
compactThinkingLevel: true
|
||||
showHookStatus: true
|
||||
sessionAccent: true
|
||||
leftSegments:
|
||||
- session_name
|
||||
- vim
|
||||
- mode
|
||||
- hostname
|
||||
- path
|
||||
- git
|
||||
- pr
|
||||
rightSegments:
|
||||
- model
|
||||
- cost
|
||||
- context_pct
|
||||
- time_spent
|
||||
segmentOptions:
|
||||
model:
|
||||
showThinkingLevel: true
|
||||
path:
|
||||
abbreviate: true
|
||||
stripWorkPrefix: true
|
||||
maxLength: 120
|
||||
git:
|
||||
showBranch: false
|
||||
showStaged: true
|
||||
showUnstaged: true
|
||||
showUntracked: true
|
||||
tui:
|
||||
textSizing: true
|
||||
codexResetFireworks: false
|
||||
@@ -115,7 +141,7 @@ display:
|
||||
showTokenUsage: true
|
||||
task:
|
||||
showResolvedModelBadge: true
|
||||
maxConcurrency: 2
|
||||
maxConcurrency: 3
|
||||
agentModelOverrides:
|
||||
designer: llamacpp (dankclaw-3090)/frank-zealot
|
||||
librarian: llamacpp (dankclaw-3090)/frank-zealot
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ providers:
|
||||
# config.yml (192.168.0.143:7771 — frank-zealot's 3090); the
|
||||
# compactionModel candidate keeps the wire model id valid there.
|
||||
compactionModel: llamacpp (dankclaw-3090)/frank-zealot
|
||||
name: "frank-archon (dankserver)"
|
||||
name: "frank-archon"
|
||||
# Dankserver: BOTH Radeon AI PRO R9700s (gfx1201, TP=2 over the
|
||||
# 2026-09-20 board swap's root ports, wht6 wire). Engine:
|
||||
# radiance (StillDeadcode, Apache-2.0) from the digest-pinned
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=command-center live-sync heartbeat (commits machine-written paths)
|
||||
Documentation=file://%h/.omp/omp-docs/tools/live-sync.md
|
||||
|
||||
[Service]
|
||||
# One-shot heartbeat: commit allowlisted live paths, merge trunk, push, reap
|
||||
# stale wt/* worktrees. Self-healing by design — a failed fetch/merge alerts
|
||||
# via ntfy and simply retries on the next tick; nothing to restart.
|
||||
Type=oneshot
|
||||
Nice=19
|
||||
IOSchedulingClass=idle
|
||||
ExecStart=%h/.omp/scripts/live-sync.sh
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=command-center live-sync heartbeat every hour
|
||||
|
||||
[Timer]
|
||||
OnBootSec=5min
|
||||
OnUnitActiveSec=1h
|
||||
RandomizedDelaySec=3min
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -57,10 +57,12 @@ binds {
|
||||
Mod+J { focus-window-down; }
|
||||
|
||||
// swap-window = window walks sideways, joining/exiting columns it passes
|
||||
Mod+CTRL+Left { swap-window-left; }
|
||||
Mod+CTRL+H { swap-window-left; }
|
||||
Mod+CTRL+Right { swap-window-right; }
|
||||
Mod+CTRL+L { swap-window-right; }
|
||||
// Mod+CTRL+arrows retargeted 2026-10-17 to consume-or-expel (was
|
||||
// swap-window) at Frank's request; swap-window-* now unbound.
|
||||
Mod+CTRL+Left { consume-or-expel-window-left; }
|
||||
Mod+CTRL+H { consume-or-expel-window-left; }
|
||||
Mod+CTRL+Right { consume-or-expel-window-right; }
|
||||
Mod+CTRL+L { consume-or-expel-window-right; }
|
||||
Mod+CTRL+Alt+Left { move-column-left; }
|
||||
Mod+CTRL+Alt+H { move-column-left; }
|
||||
Mod+CTRL+Alt+Right { move-column-right; }
|
||||
@@ -141,10 +143,10 @@ binds {
|
||||
Mod+CTRL+F { expand-column-to-available-width; }
|
||||
Mod+C { center-column; }
|
||||
Mod+CTRL+C { center-visible-columns; }
|
||||
Mod+Minus { set-column-width "-10%"; }
|
||||
Mod+Equal { set-column-width "+10%"; }
|
||||
Mod+Shift+Minus { set-window-height "-10%"; }
|
||||
Mod+Shift+Equal { set-window-height "+10%"; }
|
||||
Mod+Minus { set-column-width "-5%"; }
|
||||
Mod+Equal { set-column-width "+5%"; }
|
||||
Mod+Shift+Minus { set-window-height "-5%"; }
|
||||
Mod+Shift+Equal { set-window-height "+5%"; }
|
||||
|
||||
|
||||
// ─── Modes ───
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
background-color "transparent" // <- needed for noctalia-shell to set wallpaper
|
||||
|
||||
preset-column-widths {
|
||||
proportion 0.25 // 1/4
|
||||
proportion 0.3333 // 1/3
|
||||
proportion 0.5 // 1/2
|
||||
proportion 0.2 // 1/5
|
||||
proportion 0.4 // 2/5
|
||||
proportion 0.6 // 3/5
|
||||
}
|
||||
}
|
||||
|
||||
preset-window-heights {
|
||||
proportion 0.25 // 1/4
|
||||
proportion 0.5 // 1/2
|
||||
}
|
||||
|
||||
struts {
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
# Core Documentation
|
||||
|
||||
These files define the structural conventions that govern the pi agent system itself. They are the grammar rules — boring until you break them, then devastating.
|
||||
These files define the structural conventions that govern the agent system itself. They are the grammar rules — boring until you break them, then devastating.
|
||||
|
||||
> **Archive note (2026-10-18).** The settings pages (`settings.md`, `settings.json`)
|
||||
> capture the retired **pi** harness configuration (`frank-default-*` endpoints,
|
||||
> RTX 3090-era hardware) and are historical records. The live config is
|
||||
> `agent/config.yml` + `agent/models.yml` in this repo; current fleet endpoints
|
||||
> are on [System hosts](/system/index.md). The AGENTS.md format pages remain current.
|
||||
|
||||
## Concept Files
|
||||
|
||||
* [AGENTS.md Format Specification](agents-md-format.md) — Canonical structure and conventions for the system-level instruction file that governs agent behavior.
|
||||
* [AGENTS.md Index](index-doc.md) — Overview of the cached tool documentation system and how to add new entries.
|
||||
* [Pi Settings System](settings.md) — Current system configuration: providers, models, packages, subagent overrides, and runtime options.
|
||||
* [Pi Settings System](settings.md) — pi-era `settings.json` record (archive): providers, models, packages, subagent overrides.
|
||||
|
||||
## Change Tracking
|
||||
|
||||
|
||||
@@ -11,6 +11,47 @@ timestamp: 2026-08-28
|
||||
|
||||
# Bundle Change Log
|
||||
|
||||
## 2026-10-18 — live-sync heartbeat for machine-written paths (Refs #11)
|
||||
|
||||
Root-caused the month of silent divergence in the live checkout (~61 auto-learned skills on one disk only, a stranded `unexpectedStopDetection` fix, merge-refusals from dirty trees): the checkout IS the deployment, symlinks make machine writes dirty tracked files by design, and no commit law covered that churn. Added `scripts/live-sync.sh` + systemd user timer — allowlist tiers (memories, managed-skills, live config, dotfiles) auto-commit with hooks armed, merge `origin/main`, push, and reap stale `wt/*` worktrees; everything outside the allowlist is never staged, conflicts abort-and-alert. Black-box suite `tests/live-sync.bats` (9 tests). Tier law in AGENTS.md § Live-sync tiers; reference page `tools/live-sync.md` registered in the tools index.
|
||||
|
||||
## 2026-10-18 — Fleet law: filed PRs open in Frank's browser immediately
|
||||
|
||||
Both repos' git rules now require it: the moment a PR is opened, `xdg-open <PR-URL>` drops a Firefox tab on the workstation (AGENTS.md § Trunk-based SDLC here; § Git Workflow step 6 in `dank/serverAppConfigs`, riding their PR #6 branch).
|
||||
|
||||
## 2026-10-18 — Trunk law: extension route closed unmerged; direct repo alignment instead
|
||||
|
||||
Built and live-verified a cwd-scoped `before_agent_start` extension (quote probes: fires under `~/Projects`, silent elsewhere; kept as `.AGENTTRASH/trunk-law.js`). **Operator closed PR #9 unmerged** in favor of editing each repo's own AGENTS.md. Durable finding from the exploration: every context-file provider (AGENTS.md walk-up, `.omp/` dirs, CLAUDE.md) resolves at or below the repo root — a `~/Projects/AGENTS.md` for ancestor scope can never load; user-level `APPEND_SYSTEM.md` broadcasts to *all* sessions. Second finding: **serverAppConfigs never had git-flow** — its AGENTS.md mandated no branch regime at all (direct commit+push); a trunk + PR law is being added there by PR in that repo, not corrected.
|
||||
|
||||
## 2026-10-18 — SDLC switched to trunk-based development
|
||||
|
||||
`develop` retired by operator decision (single-dev repo; the branch bought nothing and cost a back-merge every release). New law in AGENTS.md § *Trunk-based SDLC*: branch off the freshest `origin/main` before every work item, PRs target `main` directly, `--no-ff` merges, tags `vX.Y.Z` straight on main. No back-merges, no release branches. The last back-merge (`527596a`) lands with this switch; the managed skill `gitflow-back-merge-plumbing` is now historical.
|
||||
|
||||
## 2026-10-18 — Sibling-vault overlap census; system docs realigned to live ground truth
|
||||
|
||||
Census of `omp-docs/` against `~/Projects/serverAppConfig/serverAppConfigs-docs/` (subagent + live-ssh verification) found four contradicting pairs; all OURS-side stale pages corrected, THEIRS side flagged only (their repo, their PR flow). Ground truth from read-only probes on both boxes 2026-10-18.
|
||||
|
||||
* **Hardware drift corrected** (`system/dankserver.md`, `system/dankclaw.md` rewritten, `AGENTS.md` machine table): RTX 3090 moved Dankserver→Dankclaw 2026-09; dankserver now 2× Radeon AI PRO R9700 (7700X stays — the "board swap" story is false), 246 GiB RAM, no swap; dankclaw 121 GiB RAM + 64 GiB swap. Served models per live units: frank-archon (:7770 dankserver, radiance TP=2 iq4r), frank-dragoon (:7770 dankclaw, halogen NATIVE v2, iGPU), frank-zealot (:7771 dankclaw, llama.cpp PrismML, Ternary-Bonsai-2-27B PQ2_0, 3090). Both kernels 7.0.0-38-generic; dankclaw :7770 needs no auth.
|
||||
* **Gitea pages corrected** (`tools/gitea/` index + 3 subpages): `gitea-caddy` quadlet retired — fleet Caddy fronts the domain; data tree is `/home/dank/Containers/gitea/{data,postgres,env}` (2026-09-01 standard), `/opt/gitea/` is a do-not-use leftover; LAN IP, live domain, no WAN address.
|
||||
* **Pi-era pages demarcated as archive** (`pi/index.md`, `core/index.md` banners; `core/index.md` said settings.md was "Current"): `frank-default-small/large` endpoints, role tables, and 3090/4070 hardware rows now read as pi-era records. `tools/llama-cpp/index.md` fleet note modernized to the one remaining llama.cpp endpoint (zealot :7771).
|
||||
* **Their-side staleness flagged, NOT edited** (for operator clarification): `Agent/OMP Harness.md` still says thresholdPercent 70 — live config is **95** (`agent/config.yml:84`); `index.md:18` says Dankserver Ubuntu 24.04 vs their own specs page 26.04; `Dankclaw/Stack.md` "current mapping (2026-09-03)" predates the ACTIVE dragoon/zealot runbooks it links beside; `index.md:548` links the superseded pi-era KB at `~/.pi/agent/docs/`.
|
||||
* Consistent duplicates (no action): niri/noctalia desktop pages, Caddy reference. Divergence clarified: their "composer" = OpenWebUI chat box; ours = omp composer shape — unrelated subjects.
|
||||
|
||||
## 2026-10-18 — Status line docs truth audit (full-source re-verification)
|
||||
|
||||
Exhaustive claim-by-claim re-audit of [OMP Status Line Customization](/pi/statusline.md) against the minified `dist/cli.js` bundle plus a live screenshot matrix (band × {off, percentage, embedded}, claude × off). Page carries an **Audit log** section; four first-pass claims were false and are corrected (see there): claude's rule is *not* the context meter (meter is `box`/`band` only; the "red rule" was the session-accent filler), the "Tern-only" composer-bar claim was bogus (the readout is `composer.tokenRate`, default off), `segmentOptions` are **not** gated to `preset: custom` (only the segment arrays are), and the `mode` segment's states are Plan/Prewalk/Goal/Vibe/Loop (no yolo). Page expanded with: the 7-preset defaults table, per-shape `statusAttachment`/`bottomBar` model (8 built-ins + plugin shape registry), `contextLine` per-value behavior, the 27-segment catalog with triggers/options, `segmentOptions` schema, and the full `statusLine.*`/`composer.*` knob registry. The bundle's own "(box composer only)" knob description for `contextLine` is upstream-wrong — band honors it.
|
||||
|
||||
ServerAppConfigs-docs overlap census: flagged separately for the operator (morning report); no doc merged/changed on either side.
|
||||
|
||||
## 2026-10-18 — Status line rebuilt on custom segments; frank-archon display name slimmed
|
||||
|
||||
Interactive tune-up of the omp status bar (grilling session, live loop: config edit → watcher repaint → niri screenshot verify). New knowledge page: [OMP Status Line Customization](/pi/statusline.md).
|
||||
|
||||
* **Mechanics discovered:** `leftSegments`/`rightSegments` are inert unless `preset: custom` (fleet was on `nerd` with dead arrays; `segmentOptions` *do* merge under named presets); `composer.shape` routes them — `band` merges both arrays into one row above the editor (title rides the working row), `claude` splits them into top chip + bottom strip. The context meter exists **only in `box`/`band`** — `contextLine`: `off` plain rule, `embedded` hoists the context segment into the labeled inline meter (`60% ——— × 200K`), `percentage`/`annotated` paint an unlabeled proportional rule meter (all four live-verified); every other shape's rule is a constant session-accent filler. Working row (session title + tok/s readout gated by `composer.tokenRate`, default off) is composer chrome — model/thinking can never join it. Eight composer shapes ship in the bundle; plugins can register more.
|
||||
* **Final bar (`band`, after a `claude` sojourn):** left = `session_name · vim · mode · hostname · path · git(no branch text) · pr`; right cluster in array order = `model · cost · time_spent` (`context_pct` hoists out of the run to paint the labeled inline meter `60% ——— × 200K` as a flexible spacer between the groups). Cut: tok/s duplicate, clock, cache trio, `context_total`, `subagents`, `session` hash, and `token_in`/`token_out` (cumulative totals live in `/session`). `path`: logical `project/worktree` label (`stripWorkPrefix: true`, kept after a live `false` trial of the full cwd); branch text dropped (worktree branches are autogenerated), dirty badges kept.
|
||||
* **models.yml:** frank-archon display `name` slimmed to `"frank-archon"` (endpoint suffix dropped; `id` untouched).
|
||||
* **Out of scope noted:** worktree name generation (`wt-<date>-<hash>`) is omp-internal; possible upstream feature request.
|
||||
|
||||
## 2026-10-09 — Blankpad DE redesign: desk profiles, keybind rework, Handy fleet wiring
|
||||
|
||||
Branch `blankpad-de-redesign` (worktree `wt/de-redesign-20261009`). Full sweep + redesign of the niri/noctalia/Handy stack on blankpad.
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
# Pi Configuration
|
||||
|
||||
Documentation for the pi coding agent installation on ](../system/index.md).
|
||||
Everything here is configured locally on the workstation; the LLM providers are the
|
||||
two llama.cpp servers (Dankserver, Dankclaw).
|
||||
> **Archive note (2026-10-18).** Most pages in this directory document the retired
|
||||
> **pi** harness (settings.json / models.json, `frank-default-*` endpoints, verified
|
||||
> 2026-08-28). The live harness is **omp** — its config is `agent/config.yml` +
|
||||
> `agent/models.yml` in this repo, the current fleet endpoints are on
|
||||
> [System hosts](/system/index.md), and omp-specific knowledge lands in pages like
|
||||
> [OMP Status Line Customization](/pi/statusline.md) below. Read pi pages as
|
||||
> historical records, not current state.
|
||||
|
||||
## Configuration Files
|
||||
|
||||
- [Pi Settings System (settings.json)](/core/settings.md) — Main `settings.json` reference. Providers, models, packages, subagent overrides.
|
||||
- [Pi Models Configuration](/pi/models.md) — `models.json` reference. Provider definitions, model specs, endpoints.
|
||||
- [OMP Status Line Customization](/pi/statusline.md) — How presets, composer shapes, and segment arrays actually interact; the fleet's tuned bar.
|
||||
|
||||
## Extensions
|
||||
|
||||
|
||||
@@ -0,0 +1,199 @@
|
||||
---
|
||||
type: reference
|
||||
title: OMP Status Line Customization
|
||||
description: How the omp status line actually works — presets vs custom arrays, composer-shape segment routing, the context meter (box/band only), the 27-segment catalog, and the fleet's tuned layout.
|
||||
tags:
|
||||
- omp
|
||||
- tui
|
||||
- statusline
|
||||
- config
|
||||
timestamp: 2026-10-18
|
||||
---
|
||||
|
||||
# OMP Status Line Customization
|
||||
|
||||
Ground truth from the installed bundle (`@oh-my-pi/pi-coding-agent/dist/cli.js`),
|
||||
verified live on blankpad 2026-10-18 and re-audited line-by-line against the
|
||||
minified source the same day (see [Audit log](#audit-log)). Status knobs live
|
||||
in `agent/config.yml` under `statusLine:`; the two composer knobs
|
||||
(`composer.shape`, `composer.tokenRate`) under `composer:`. The file is
|
||||
file-watched — edits repaint a running session without restart (verify
|
||||
visually: niri screenshot, see [niri capture recipe](../system/index.md)).
|
||||
`/settings` (Appearance tab) previews these live with sample data.
|
||||
|
||||
## Preset vs custom — the trap
|
||||
|
||||
`statusLine.preset` ships whole configurations. **`leftSegments` /
|
||||
`rightSegments` are ignored unless `preset: custom`** (`s ? user ?? preset
|
||||
: preset` in the resolver). **`segmentOptions` is NOT gated** — user options
|
||||
merge over the preset's own options under *every* preset.
|
||||
|
||||
| preset | leftSegments | rightSegments | separator |
|
||||
|---|---|---|---|
|
||||
| `default` | pi vim model mode collab stream path git pr context_pct cost | session_name | powerline-thin |
|
||||
| `minimal` | vim path git | session_name mode context_pct | slash |
|
||||
| `compact` | vim model mode git pr | session_name cost context_pct | powerline-thin |
|
||||
| `full` | pi vim hostname model mode path git pr subagents | session_name cache_hit token_in token_out token_rate cache_read cost context_pct time_spent time | powerline |
|
||||
| `nerd` | pi vim hostname model mode path git pr session subagents | session_name token_in token_out cache_read cache_write token_rate cost context_pct context_total time_spent time | powerline |
|
||||
| `ascii` | vim model mode path git pr | session_name token_total cost context_pct | ascii |
|
||||
| `custom` | your `statusLine.leftSegments` | your `statusLine.rightSegments` | powerline-thin |
|
||||
|
||||
The built-in default for `statusLine.leftSegments`/`rightSegments` themselves
|
||||
is the `ascii`-era pair (`vim model mode path git pr` / `session_name
|
||||
token_total cost context_pct`) — a config carrying those arrays with a named
|
||||
preset is running the preset, not the arrays. The fleet runs `preset: custom`.
|
||||
|
||||
## Composer shape routes the segments
|
||||
|
||||
`composer.shape` decides *where* the two arrays render. Eight shapes ship in
|
||||
the bundle; the plugin API can register more (`zG()` = built-ins + a live
|
||||
registration map). Internally each shape carries `statusAttachment`,
|
||||
`bottomBar`, `bottomBarGap`:
|
||||
|
||||
| shape | attach | bottom bar | leftSegments | rightSegments |
|
||||
|---|---|---|---|---|
|
||||
| `band` (fleet, default) | top-band | none | merged single row above editor, left | same row, right (`session_name` skipped — title rides the working row) |
|
||||
| `box` | top-border | none | box top border | box top border |
|
||||
| `claude` | top-rule-chip | left | bottom strip, left | top rule chip, right-aligned |
|
||||
| `rule` | top-rule-chip | left + gap | like claude, gap above strip | like claude |
|
||||
| `pi` | none | full | single bottom bar | single bottom bar |
|
||||
| `borderless` | none | full | single bottom bar | single bottom bar |
|
||||
| `field` / `rail` | none | full + gap (filled surface) | single bottom bar | single bottom bar |
|
||||
|
||||
The chip/strip layouts paint their rules as **session-accent fillers, not
|
||||
meters** — the context meter exists only in `box` and `band`
|
||||
(see next section). The top-rule chip renders right segments only, the bottom
|
||||
strip left segments only.
|
||||
|
||||
The working row is composer chrome, not segment-addressable: session title +
|
||||
shimmer, plus the tok/s readout when `composer.tokenRate: true` (default
|
||||
false). The readout is estimated from streamed deltas, corrected by billed
|
||||
output counts; the bundle also mentions a native-composer-bar placement in
|
||||
filled styles.
|
||||
|
||||
## The context meter
|
||||
|
||||
`statusLine.contextLine` (enum `off` / `percentage` / `annotated` /
|
||||
`embedded`, default `embedded`) tunes the rule between the segment groups.
|
||||
The knob description says "box composer only" — **that is wrong**: the meter
|
||||
renders in `box` **and** `band`; in every other shape the rule is a constant
|
||||
session-accent filler regardless of this setting (live-verified claude with
|
||||
`off` vs `embedded`: identical, and not context-proportional).
|
||||
|
||||
In box/band:
|
||||
|
||||
- `off` → plain accent rule (single color, full width).
|
||||
- `embedded` → the inline labeled meter: `60% ——— × 200K`. Requires
|
||||
`contextWindow > 0`, a `context_pct`/`context_total` segment present in
|
||||
either array, and at least one non-context segment. The context segment(s)
|
||||
are **hoisted out of the arrays** — they never render as text in this mode.
|
||||
- `percentage` / `annotated` → unlabeled proportional meter painted into the
|
||||
rule (live-verified in band: colored fill ∝ usage at the rule's right end);
|
||||
`context_pct` stays a normal text segment.
|
||||
|
||||
Fill length ∝ `min(100, contextPercent)`; >100% paints the raw percent and
|
||||
shortens the meter. Meter/segment color thresholds scale with window size —
|
||||
warning at ≥ min(50 %, 150K tokens), purple ≥ min(70 %, 270K), error ≥
|
||||
min(90 %, 500K); below that the theme's `statusLineContext` color.
|
||||
|
||||
## Segment universe (27)
|
||||
|
||||
`pi`, `status`, `model`, `mode`, `path`, `git`, `pr`, `subagents`,
|
||||
`token_in`, `token_out`, `token_total`, `token_rate`, `cost`, `context_pct`,
|
||||
`context_total`, `time_spent`, `time`, `session`, `hostname`, `cache_read`,
|
||||
`cache_write`, `cache_hit`, `session_name`, `usage`, `collab`, `stream`, `vim`.
|
||||
|
||||
Zero/inactive segments render nothing — dead weight costs no width.
|
||||
|
||||
| segment | renders | trigger / notes |
|
||||
|---|---|---|
|
||||
| `pi` | brand glyph + turn-elapsed | while streaming; focused-agent ghost id (warning color) when a subagent is focused |
|
||||
| `status` | hook/extension statuses, dot-joined | extension pushes via `ctx.ui.setStatus()` (ordered by key); suppressed in footer when `statusLine.showHookStatus: false` |
|
||||
| `model` | display `name` + thinking level | suffix hidden by `segmentOptions.model.showThinkingLevel: false`; `statusLine.compactThinkingLevel: true` (default) swaps in a compact glyph; fast-mode, advisor/tariff badges attach here |
|
||||
| `mode` | `Plan` / `Prewalk` / `Goal` / `Vibe` / `Loop …` | only in those modes (paused variants add a pause glyph); there is **no yolo/auto-approval display** in this segment |
|
||||
| `path` | cwd or `project/worktree` label | see [Path segment](#path-segment-and-stripworkprefix) |
|
||||
| `git` | branch + dirty badges | `+N` staged, `*N` unstaged, `?N` untracked (`segmentOptions.git.showStaged/showUnstaged/showUntracked`, default true); `showBranch: false` hides branch text and keeps badges (git icon carries them); color flips on dirty |
|
||||
| `pr` | `#<number>` hyperlink | only once the session has an associated PR |
|
||||
| `subagents` | count | hidden at 0; when subagents are actively running the composer paints its own live badge and this segment self-suppresses |
|
||||
| `token_in` / `token_out` | cumulative session input/output tokens | hidden at 0; `cache_read` / `cache_write` likewise cumulative |
|
||||
| `token_total` | `input + output + cache_write + orchestration_in + orchestration_out` | hidden at 0 |
|
||||
| `token_rate` | `N.N tok/s` | hidden when not streaming (the working-row readout is a separate, `composer.tokenRate`-gated thing) |
|
||||
| `cost` | session cost | includes subagent-tree + advisor cost; `↑`/`↓` peak/off-peak arrow for time-priced providers |
|
||||
| `context_pct` | `NN.N%/200K` (or window alone when percent is unknown) | hoisted into the meter in `embedded` box/band; auto-compact speculation icon rides along |
|
||||
| `context_total` | absolute context tokens | also hoisted by the embedded meter |
|
||||
| `time_spent` | active session time | hidden under 1 s; this is *active* time, not wall clock |
|
||||
| `time` | wall clock | `segmentOptions.time.format: "12h"/"24h"`, `showSeconds` |
|
||||
| `session` | first 8 chars of session id (`new` before resume exists) | resume-by-id handle |
|
||||
| `session_name` | session title, accent | in `band` it renders on the working row instead |
|
||||
| `hostname` | short hostname | accent-tinted with session color |
|
||||
| `usage` | rate-limit windows | 5h / daily / 7d / monthly bars + tier badge, when the provider reports them |
|
||||
| `collab` | `collab:N` / `collab guest:N` | only in collab sessions |
|
||||
| `stream` | `● LIVE <viewers>` / `● REC` | only while streaming/recording |
|
||||
| `vim` | mode glyph/word | only while vim keybindings are active; selected-line count appended (` 3L`); `display` icon vs text comes from the vim runtime, not config |
|
||||
|
||||
## Path segment and `stripWorkPrefix`
|
||||
|
||||
`segmentOptions.path.stripWorkPrefix` (default **true** — the code tests
|
||||
`!== false`) gates two behaviors in the `path` renderer:
|
||||
|
||||
1. **Worktree sessions:** `true` never shows the disk path — it renders the
|
||||
logical `projectName/worktreeName` label (bare `projectName` when the
|
||||
current branch is named after the worktree) with the worktree glyph.
|
||||
`false` opts out and shows the real cwd with a folder glyph, plus a
|
||||
` ↳ relativeRepoRoot` suffix inside a repo. Base-directory-only is not
|
||||
renderable in either mode.
|
||||
2. **All sessions:** `true` uses the pretty display path (scratch sessions
|
||||
get the scratch-folder icon); `false` uses the raw absolute cwd.
|
||||
|
||||
`abbreviate` (default **true**: home → `~`; `false` keeps the full path —
|
||||
also affects tool labels/errors per upstream docs) and `maxLength` (clip,
|
||||
default 40) apply afterwards in both modes. The fleet runs `true` — logical
|
||||
label, worktree glyph (verified live 2026-10-18; an earlier trial of `false`
|
||||
for the full cwd was rejected by eye).
|
||||
|
||||
## Status knobs (registry-verified)
|
||||
|
||||
`statusLine.preset` · `.leftSegments` · `.rightSegments` · `.segmentOptions` ·
|
||||
`.separator` (`powerline` `powerline-thin` `slash` `pipe` `block` `none`
|
||||
`ascii`; default `powerline-thin`) · `.contextLine` · `.sessionAccent`
|
||||
(default true; hashes the session name into the editor border *and* the
|
||||
accent-tinted segments/meter color) · `.transparent` (terminal background,
|
||||
no status bg fill) · `.showHookStatus` · `.compactThinkingLevel` (default
|
||||
true). Plus `symbolPreset` at top level (`unicode` `nerd` `ascii` — segment
|
||||
glyphs follow it).
|
||||
|
||||
## Fleet configuration (2026-10-18)
|
||||
|
||||
- Shape `band`: one merged status row. Left group: `session_name`→working
|
||||
row (skipped), `vim`, `mode`, `hostname`, `path`, `git` (no branch text —
|
||||
worktree branches are autogenerated names), `pr`. Right group (array order
|
||||
= paint order, so the last entry hugs the screen edge): `model`, `cost`,
|
||||
`context_pct`, `time_spent` — `context_pct` hoists out of the run to paint
|
||||
the labeled inline meter (`60% ——— × 200K`) between the groups under
|
||||
`contextLine: embedded`.
|
||||
- Deliberately cut: `token_rate` (working-row readout covers it), `time`
|
||||
(panel clock), `cache_*` (noise), `context_total` (implied by the meter),
|
||||
`subagents` (live badge supersedes it), `session`, `token_in`/`token_out`
|
||||
(cumulative totals are in `/session` anyway).
|
||||
- `models.yml`: frank-archon's display `name` slimmed to `"frank-archon"`
|
||||
(endpoint suffix dropped); frank-dragoon/frank-zealot keep their endpoint
|
||||
suffixes. `name:` is free-form display, `id:` is the wiring — renaming ids
|
||||
is the cutover procedure, see [Pi Models](/pi/models.md).
|
||||
|
||||
## Audit log
|
||||
|
||||
2026-10-18 full-source re-audit corrected the first pass of this page:
|
||||
|
||||
- ~~claude shape's top rule is the context meter~~ — **false**. The
|
||||
meter code path runs only for `box`/`band`; claude/rule/pi/borderless/
|
||||
field/rail rules are constant session-accent fillers. (Earlier reading
|
||||
mistook the accent rule for a meter.)
|
||||
- ~~working-row composer-bar variant is "Tern-only"~~ — **false**; the
|
||||
tok/s readout is the `composer.tokenRate` option (default false), title
|
||||
placement is composer chrome.
|
||||
- ~~`segmentOptions` gated to `preset: custom`~~ — **false**; options merge
|
||||
under every preset, only the segment *arrays* are gated.
|
||||
- ~~`mode` covers yolo~~ — **false**; states are Plan/Prewalk/Goal/Vibe/Loop.
|
||||
- `contextLine` "(box composer only)" — the *bundle description* is wrong;
|
||||
band honors it too (verified live: `off` plain rule, `percentage` rule
|
||||
meter, `embedded` inline meter, screenshots + code).
|
||||
+45
-49
@@ -1,83 +1,79 @@
|
||||
---
|
||||
type: reference
|
||||
title: Dankclaw
|
||||
description: Secondary inference server at 192.168.0.143. Runs llama.cpp (frank-default-large).
|
||||
description: Inference and services box at 192.168.0.143 — frank-dragoon (halogen-flash-server, Strix Halo iGPU, :7770) and frank-zealot (llama.cpp on the RTX 3090, :7771), plus Gitea/Caddy/OpenWebUI services.
|
||||
tags:
|
||||
- network
|
||||
- llamacpp
|
||||
- inference
|
||||
- server
|
||||
- comfyui
|
||||
- unverified
|
||||
generated:
|
||||
by: chief-designer/agent
|
||||
at: 2026-08-26T00:00:00Z
|
||||
verified: 2026-08-28
|
||||
verified: 2026-10-18
|
||||
---
|
||||
|
||||
# Dankclaw
|
||||
|
||||
Secondary llama.cpp inference server for the Frank Program. Serves larger models used by planner, worker, reviewer, oracle, and context-builder subagents.
|
||||
Strix Halo mini-PC carrying the fleet's secondary models and most of the
|
||||
service stack (Gitea, Caddy, OpenWebUI, SearXNG). Two GPU-class devices: the
|
||||
Radeon 8060S iGPU with 119 GiB unified memory, and the RTX 3090 moved over
|
||||
from Dankserver in September 2026.
|
||||
|
||||
## Connection Details
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Hostname** | dankclaw |
|
||||
| **IP Address** | 192.168.0.143 |
|
||||
| **Port** | 7770 |
|
||||
| **Base URL** | `http://192.168.0.143:7770/v1` |
|
||||
| **API** | OpenAI-compatible completions |
|
||||
| **Authentication** | API key configured |
|
||||
| **IP Address** | 192.168.0.143 (LAN) |
|
||||
| **Auth** | none required on :7770 (verified 2026-10-18) |
|
||||
|
||||
## Models
|
||||
## Inference Services
|
||||
|
||||
| Model ID | Context Window | Reasoning | Input Types |
|
||||
|----------|---------------|-----------|-------------|
|
||||
| `frank-default-large` | 262,144 tokens | Yes | Text, *Image* (unverified) |
|
||||
| Model ID | Unit | Endpoint | Engine / weights |
|
||||
|----------|------|----------|------------------|
|
||||
| `frank-dragoon` | `frank-dragoon.service` (root) | `:7770` | halogen-flash-server container — Quat3rnion NATIVE v2 abliterated Qwen3.8-Flash-Next, MTP spec decode, 2 slots over ONE 200,704-position pool, vision ON, **Strix Halo iGPU** (unified memory) |
|
||||
| `frank-zealot` | `frank-zealot.service` (root) | `:7771` | llama.cpp (PrismML fork, build 10754) — Ternary-Bonsai-2-27B PQ2_0 GGUF (qwen35 hybrid), 2×200,704 slots, q8_0 K+V, mmproj vision, **RTX 3090** |
|
||||
|
||||
## Services
|
||||
|
||||
### llama.cpp
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Port** | 7770 |
|
||||
| **Models** | `frank-default-large` |
|
||||
|
||||
## Hardware
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **CPU** | AMD Ryzen AI MAX+ 395 (16C/16T, Strix Halo) |
|
||||
| **GPU** | Radeon 8060S integrated (gfx1151, amdgpu) |
|
||||
| **RAM** | 119 GiB |
|
||||
| **Storage** | Kingston SNV3S1000G NVMe (931.5 GB), ~676 GB free |
|
||||
| **OS** | Ubuntu 26.04 LTS, kernel 7.0.0-30-generic |
|
||||
| **ROCm** | 7.2.4 (driver: 7.0.0-30-generic) |
|
||||
| **Python** | 3.14.4 (system) |
|
||||
|
||||
## Usage
|
||||
|
||||
Dankclaw handles complex tasks delegated by subagent overrides. The `frank-default-large` model provides extended context. *Multimodal input support is unverified.*
|
||||
Harness-side context windows (`agent/models.yml`): dragoon 155,648,
|
||||
zealot 200,704 per slot. The models.yml display labels "(dankclaw-gpu)" /
|
||||
"(dankclaw-3090)" predate naming cleanup; the hardware column above is
|
||||
current. Subagent roles `scout`, `sonic`, `designer`, `librarian`,
|
||||
`security-reviewer` route to frank-zealot; `reviewer`/`task` run on
|
||||
frank-archon (Dankserver).
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl http://192.168.0.143:7770/health
|
||||
|
||||
# Test with large model
|
||||
curl http://192.168.0.143:7770/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer <key>" \
|
||||
-d '{"model":"frank-default-large","messages":[{"role":"user","content":"Hello"}],"max_tokens":32}'
|
||||
curl http://192.168.0.143:7770/v1/models # dragoon
|
||||
curl http://192.168.0.143:7771/v1/models # zealot
|
||||
```
|
||||
|
||||
## Related Knowledge Bases (sibling project on the workstation)
|
||||
## Hardware (verified live 2026-10-18)
|
||||
|
||||
- **serverAppConfigs** — `/home/dank/Projects/serverAppConfigs/` — Podman deployment config for this host (AI, search, development, observability stack, incl. the Hermes compose service) **plus the LLM inference fleet** (frank-default-large, CIRU ROCmFPX llama.cpp, :7770). The former `vllmScripts` repo merged into it on 2026-08-22 (history preserved). Start at `/home/dank/Projects/serverAppConfigs/docs/index.md` (see `dankclaw/compose.yaml` + `docs/Dankclaw/`; LLM fleet at `docs/LLM/index.md`, deploy runbook at `docs/LLM/deployment.md`).
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **CPU/APU** | AMD Ryzen AI MAX+ 395 (Strix Halo, Radeon 8060S, gfx1151) |
|
||||
| **dGPU** | NVIDIA GeForce RTX 3090 (moved from Dankserver 2026-09) |
|
||||
| **RAM** | 121 GiB (mostly usable as GPU unified memory) |
|
||||
| **Swap** | 64 GiB |
|
||||
| **OS** | Ubuntu 26.04 LTS, kernel 7.0.0-38-generic |
|
||||
|
||||
The pre-rename story (`frank-default-large` on ROCmFPX llama.cpp/CIRU,
|
||||
262,144-token context) was superseded by the 2026-10-08/09 model-id rename
|
||||
and the dragoon/zealot engine swaps; the 119→121 GiB RAM figure follows the
|
||||
live `free` reading.
|
||||
|
||||
## Related Knowledge Bases (sibling project)
|
||||
|
||||
- **serverAppConfigs** — deployment repo + vault, on this workstation at
|
||||
`~/Projects/serverAppConfig/` (docs vault: `~/Projects/serverAppConfig/serverAppConfigs-docs/`).
|
||||
Live runbooks: `LLM/frank-dragoon-flash-server-v2-native.md` and
|
||||
`LLM/frank-zealot-llama-prism-bonsai2-pq20.md` — deploy-side source of
|
||||
truth for engines, flags, and restart procedures. Service stack docs under
|
||||
`Dankclaw/`, `Infrastructure/`.
|
||||
|
||||
## See Also
|
||||
|
||||
- [[models|models]] — Provider definitions
|
||||
- [[dankserver|dankserver]] — Primary server
|
||||
- [[dankserver|dankserver]] — the main-model box (frank-archon)
|
||||
- [/tools/gitea/index.md](/tools/gitea/index.md) — Gitea stack on this host
|
||||
- [[network|network]] — Network topology
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
---
|
||||
type: reference
|
||||
title: Dankserver
|
||||
description: Primary llama.cpp inference server at 192.168.0.235:7770, serving frank-default-small with 163,840-token context window.
|
||||
description: Radiance inference server at 192.168.0.235:7770, serving frank-archon (Qwen3.8-Flash-Next iq4r, 2x R9700 TP=2, 200,000-token context).
|
||||
tags:
|
||||
- network
|
||||
- llamacpp
|
||||
- inference
|
||||
- server
|
||||
- unverified
|
||||
generated:
|
||||
by: chief-designer/agent
|
||||
verified: 2026-08-28
|
||||
verified: 2026-10-18
|
||||
status: stable
|
||||
---
|
||||
|
||||
# Dankserver
|
||||
|
||||
Primary llama.cpp inference server for the Frank Program. Serves `frank-default-small` — a fast, capable model with image support.
|
||||
Primary inference server for the Frank Program. Serves `frank-archon`, the
|
||||
main agent model, from a pair of Radeon AI PRO R9700s (tensor-parallel 2).
|
||||
The RTX 3090 that used to live here was removed 2026-09-15 and now runs on
|
||||
Dankclaw.
|
||||
|
||||
## Connection Details
|
||||
|
||||
@@ -28,19 +30,24 @@ Primary llama.cpp inference server for the Frank Program. Serves `frank-default-
|
||||
| **Base URL** | `http://192.168.0.235:7770/v1` |
|
||||
| **API** | OpenAI-compatible completions |
|
||||
| **Authentication** | None |
|
||||
| **Systemd unit** | `frank-archon.service` (root) |
|
||||
|
||||
## Model
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Model ID** | `frank-default-small` |
|
||||
| **Context Window** | 163,840 tokens |
|
||||
| **Reasoning** | Supported |
|
||||
| **Input Types** | Text, *Image* (unverified) |
|
||||
| **Model ID** | `frank-archon` (display name `frank-archon`) |
|
||||
| **Weights** | Qwen3.8-Flash-Next, radiance iq4r (publisher build) |
|
||||
| **Engine** | radiance, tensor-parallel 2 across both R9700s |
|
||||
| **Context Window** | 200,000 tokens (harness `models.yml`; served pool may differ — see runbook) |
|
||||
|
||||
`frank-medium` (former dual-GPU mid tier) is masked and retired.
|
||||
|
||||
## Usage
|
||||
|
||||
Dankserver serves the small subagent model `frank-default-small`. Small subagent roles route here unless a role override picks a different model.
|
||||
Dankserver carries the main-session model. Subagent role overrides in
|
||||
`agent/models.yml` route here for `task` and `reviewer`; scout/sonic/designer
|
||||
route to Dankclaw.
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
@@ -49,27 +56,34 @@ curl http://192.168.0.235:7770/health
|
||||
# Quick test
|
||||
curl http://192.168.0.235:7770/v1/chat/completions \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"model":"frank-default-small","messages":[{"role":"user","content":"Hello"}],"max_tokens":32}'
|
||||
-d '{"model":"frank-archon","messages":[{"role":"user","content":"Hello"}],"max_tokens":32}'
|
||||
```
|
||||
|
||||
## Hardware
|
||||
## Hardware (verified live 2026-10-18)
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **CPU** | AMD Ryzen 7 7700X (8C/16T, Raphael) |
|
||||
| **GPU** | NVIDIA GeForce RTX 3090 (24 GiB VRAM, EVGA) |
|
||||
| **RAM** | 60 GiB |
|
||||
| **Swap** | 64 GiB (/swapfile) |
|
||||
| **Storage** | Kingston SNV3S1000G NVMe (931.5 GB) + md0 RAID (6×18.2T Toshiba, /mnt/entropy, 91T) |
|
||||
| **OS** | Ubuntu 26.04 LTS, kernel 7.0.0-30-generic |
|
||||
| **NVIDIA Driver** | 595.84 |
|
||||
| **CPU** | AMD Ryzen 7 7700X (8C/16T, Raphael iGPU on board) |
|
||||
| **GPU** | 2× AMD Radeon AI PRO R9700 (Navi 48, 32 GiB each) |
|
||||
| **RAM** | 246 GiB |
|
||||
| **Swap** | effectively none (~0.1 GiB) — the 64 GiB swapfile is on Dankclaw, not here |
|
||||
| **Storage** | 7× 18.2 TB HDD + 1.8 TB NVMe (layout owned by the deploy repo) |
|
||||
| **OS** | Ubuntu 26.04.1 LTS, kernel 7.0.0-38-generic |
|
||||
|
||||
## Related Knowledge Bases (sibling project on the workstation)
|
||||
The old page (verified 2026-08-28) listed an RTX 3090, 60 GiB RAM, and a
|
||||
64 GiB swapfile here; all three were superseded by the 2026-09 hardware swap.
|
||||
|
||||
- **serverAppConfigs** — `/home/dank/Projects/serverAppConfigs/` — Podman deployment config for this host (media and library stack: RomM, Copyparty, Calibre-Web) **plus the LLM inference fleet** (frank-default-small, llama.cpp, :7770). The former `vllmScripts` repo merged into it on 2026-08-22 (history preserved). Start at `/home/dank/Projects/serverAppConfigs/docs/index.md` (see `dankserver/compose.yaml` + `docs/Dankserver/`; LLM fleet at `docs/LLM/index.md`, deploy runbook at `docs/LLM/deployment.md`).
|
||||
## Related Knowledge Bases (sibling project)
|
||||
|
||||
- **serverAppConfigs** — deployment repo + vault, on this workstation at
|
||||
`~/Projects/serverAppConfig/` (docs vault: `~/Projects/serverAppConfig/serverAppConfigs-docs/`).
|
||||
Podman/quadlet deploy config for both servers plus the LLM inference fleet.
|
||||
The live frank-archon runbook (engine flags, KV pool sizing, restart
|
||||
procedures) is `LLM/frank-archon-radiance-qwen38-iq4r.md` in that vault —
|
||||
it, not this page, is the deploy-side source of truth.
|
||||
|
||||
## See Also
|
||||
|
||||
- [[models|models]] — Provider definitions
|
||||
- [[dankclaw|dankclaw]] — Secondary server
|
||||
- [[dankclaw|dankclaw]] — the other inference box (dragoon + zealot)
|
||||
- [[network|network]] — Network topology
|
||||
- [/pi/statusline.md](/pi/statusline.md) — where these models surface in the TUI
|
||||
|
||||
@@ -11,8 +11,8 @@ Dankclaw are the inference servers it talks to.
|
||||
|
||||
## Network Systems
|
||||
|
||||
- [Dankserver](/system/dankserver.md) — Primary llama.cpp inference server at 192.168.0.235:7770, serving `frank-default-small` (163,840-token context). AMD Ryzen 7 7700X, RTX 3090, Ubuntu 26.04.
|
||||
- [Dankclaw](/system/dankclaw.md) — Secondary inference server at 192.168.0.143:7770, serving `frank-default-large` (262,144-token context). AMD Ryzen AI MAX+ 395 (Strix Halo), Ubuntu 26.04, ROCm.
|
||||
- [Dankserver](/system/dankserver.md) — Main-model inference server at 192.168.0.235:7770, serving `frank-archon` (radiance Qwen3.8-Flash-Next, 200K ctx). AMD Ryzen 7 7700X, 2× Radeon AI PRO R9700, Ubuntu 26.04.
|
||||
- [Dankclaw](/system/dankclaw.md) — Secondary inference + services box at 192.168.0.143: `frank-dragoon` (:7770, halogen-flash-server on the Strix Halo iGPU) and `frank-zealot` (:7771, llama.cpp on the RTX 3090). AMD Ryzen AI MAX+ 395, Ubuntu 26.04.
|
||||
|
||||
## Infrastructure Diagram
|
||||
|
||||
@@ -26,8 +26,8 @@ graph TB
|
||||
end
|
||||
|
||||
subgraph Network[192.168.0.0/24]
|
||||
E[dankserver<br/>192.168.0.235:7770<br/>frank-default-small]
|
||||
F[dankclaw<br/>192.168.0.143:7770<br/>frank-default-large]
|
||||
E[dankserver<br/>192.168.0.235:7770<br/>frank-archon]
|
||||
F[dankclaw<br/>192.168.0.143:7770 dragoon<br/>:7771 zealot]
|
||||
end
|
||||
|
||||
D --> E
|
||||
@@ -42,7 +42,7 @@ graph TB
|
||||
The fleet has one sibling OKF knowledge base outside this bundle. Read it for
|
||||
deployment and inference details. This bundle links to it from the server pages.
|
||||
|
||||
* **serverAppConfigs** — `/home/dank/Projects/serverAppConfigs/` (index: `/home/dank/Projects/serverAppConfigs/docs/index.md`). Podman deployment configuration for both servers: compose files, Caddy reverse proxy, deploy scripts, bats tests, and the Obsidian-vault service docs (Dankclaw, Dankserver, Architecture, Infrastructure) — **plus the LLM inference fleet** (merged from the former `vllmScripts` repo on 2026-08-22, history preserved): llama.cpp on Dankserver (:7770, `frank-default-small`) and CIRU ROCmFPX llama.cpp on Dankclaw (:7770, `frank-default-large`). LLM fleet docs: `docs/LLM/index.md`; deploy runbook: `docs/LLM/deployment.md`.
|
||||
* **serverAppConfigs** — deploy repo + Obsidian vault, on this workstation at `~/Projects/serverAppConfig/` with docs in `~/Projects/serverAppConfig/serverAppConfigs-docs/` (root `index.md` at the vault top — the old `docs/` prefix is gone). Podman deployment configuration for both servers: compose/quadlet files, Caddy reverse proxy, deploy scripts, bats tests, and the vault service docs (Dankclaw, Dankserver, Architecture, Infrastructure) — **plus the LLM inference fleet** (merged from the former `vllmScripts` repo on 2026-08-22, history preserved): radiance frank-archon on Dankserver (:7770), halogen frank-dragoon (:7770) and llama.cpp frank-zealot (:7771) on Dankclaw. The vault's `LLM/` runbooks are the deploy-side source of truth; this bundle documents the agent/harness side.
|
||||
|
||||
## Related
|
||||
|
||||
|
||||
@@ -5,13 +5,12 @@ description: Gitea container architecture, network topology, and Caddy reverse p
|
||||
tags:
|
||||
- gitea
|
||||
- architecture
|
||||
- unverified
|
||||
verified: 2026-08-28
|
||||
verified: 2026-10-18
|
||||
---
|
||||
|
||||
# Gitea Architecture
|
||||
|
||||
Three quadlet-managed containers on a shared private Podman network (rootless, user `dank`). Gitea connects to PostgreSQL via network DNS. Caddy proxies HTTP/S to Gitea.
|
||||
Two quadlet-managed containers (Gitea, PostgreSQL) on a shared private Podman network (rootless, user `dank`). Gitea connects to PostgreSQL via network DNS. The fleet Caddy (separate stack, see [/caddy/index.md](/caddy/index.md)) proxies HTTP/S to Gitea — the old dedicated `gitea-caddy` container is retired.
|
||||
|
||||
## Network Topology
|
||||
|
||||
@@ -63,10 +62,10 @@ Key environment variables:
|
||||
- `DATABASE_HOST=gitea-postgres` (network DNS)
|
||||
- `DATABASE_NAME=gitea`
|
||||
- `DATABASE_USER=gitea`
|
||||
- `DATABASE_PASSWD` from `/opt/gitea/.env` (mode 0600)
|
||||
- `DATABASE_PASSWD` from `/home/dank/Containers/gitea/env` (mode 0600)
|
||||
- `USER_UID=1000`, `USER_GID=1000`
|
||||
|
||||
Gitea writes `/data/gitea/conf/app.ini` on first start (host: `/opt/gitea/data/gitea-gitea/gitea/conf/app.ini`). The `[database] HOST` and `PASSWD` lines in app.ini override the env vars. When you rename the database container, edit the `HOST` line in app.ini as well.
|
||||
Gitea writes `/data/gitea/conf/app.ini` on first start (host: `/home/dank/Containers/gitea/data/gitea/conf/app.ini`). The `[database] HOST` and `PASSWD` lines in app.ini override the env vars. When you rename the database container, edit the `HOST` line in app.ini as well.
|
||||
|
||||
## Ports
|
||||
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
---
|
||||
type: reference
|
||||
title: Gitea Data Persistence
|
||||
description: Gitea data persistence, volume mounts, ownership, and backup strategy on dankclaw.
|
||||
description: Gitea data persistence, volume mounts, ownership, and backup strategy on dankclaw (Containers/gitea layout).
|
||||
tags:
|
||||
- gitea
|
||||
- data
|
||||
- unverified
|
||||
verified: 2026-08-28
|
||||
verified: 2026-10-18
|
||||
---
|
||||
|
||||
# Gitea Data Persistence
|
||||
|
||||
All data lives on host bind mounts under `/opt/gitea/data/`. Containers are ephemeral. Quadlet stops remove the container (`podman run --rm --replace`). The next start recreates it. Data survives.
|
||||
All data lives on host bind mounts under `/home/dank/Containers/gitea/` (fleet storage standard since 2026-09-01; quadlet units re-pointed from the old `/opt/gitea/data/` tree, which lingers on disk as a leftover — never write to it). Containers are ephemeral. Quadlet stops remove the container (`podman run --rm --replace`). The next start recreates it. Data survives.
|
||||
|
||||
## Volume Layout
|
||||
|
||||
| Host Path | Container Mount | Contents |
|
||||
|---|---|---|
|
||||
| `/opt/gitea/data/gitea-gitea/` | `/data` | Git repositories, avatars, attachments, LFS objects, `app.ini` |
|
||||
| `/opt/gitea/data/gitea-postgres/` | `/var/lib/postgresql/data` | PostgreSQL WAL, tables, indexes |
|
||||
| `/home/dank/Containers/gitea/data/` | `/data` (gitea-server) | Git repositories, avatars, attachments, LFS objects, `app.ini` |
|
||||
| `/home/dank/Containers/gitea/postgres/` | `/var/lib/postgresql/data` (gitea-postgres) | PostgreSQL WAL, tables, indexes |
|
||||
|
||||
## Ownership
|
||||
|
||||
@@ -37,7 +36,7 @@ podman exec --user 1000 gitea-server sed -i 's/old/new/' /data/gitea/conf/app.in
|
||||
Tar the entire data directory. This captures Gitea repos and PostgreSQL data in one archive.
|
||||
|
||||
```
|
||||
tar czf gitea-backup-$(date +%F).tar.gz -C /opt/gitea data/
|
||||
tar czf gitea-backup-$(date +%F).tar.gz -C /home/dank/Containers/gitea data/ postgres/
|
||||
```
|
||||
|
||||
### PostgreSQL-only backup
|
||||
@@ -48,17 +47,17 @@ Use `pg_dump` for a portable SQL dump. Useful for restoring to a different Postg
|
||||
podman exec -e PGPASSWORD="$GITEA_DB_PASSWORD" gitea-postgres pg_dump -U gitea gitea > gitea-db-$(date +%F).sql
|
||||
```
|
||||
|
||||
Set `PGPASSWORD` from `/opt/gitea/.env` (mode 0600).
|
||||
Set `PGPASSWORD` from `/home/dank/Containers/gitea/env` (mode 0600, `GITEA_DB_PASSWORD`).
|
||||
|
||||
### Restore procedure
|
||||
|
||||
1. Stop the stack: `systemctl --user stop gitea-server gitea-postgres`
|
||||
2. Restore data: `tar xzf backup.tar.gz -C /opt/gitea/`
|
||||
2. Restore data: `tar xzf backup.tar.gz -C /home/dank/Containers/gitea/`
|
||||
3. Start the stack: `systemctl --user start gitea-postgres gitea-server`
|
||||
|
||||
## Data Growth
|
||||
|
||||
- Git repositories grow with each commit and push. Monitor with `du -sh /opt/gitea/data/gitea-gitea/git/repositories/`.
|
||||
- Git repositories grow with each commit and push. Monitor with `du -sh /home/dank/Containers/gitea/data/git/repositories/`.
|
||||
- PostgreSQL WAL files accumulate. VACUUM via `podman exec gitea-postgres psql -U gitea -c "VACUUM;"`.
|
||||
- Gitea's log files grow with usage.
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# Gitea on dankclaw
|
||||
|
||||
Private Git hosting on dankclaw. Three quadlet-managed containers in the rootless podman session of user `dank`: Gitea, PostgreSQL, Caddy.
|
||||
Private Git hosting on dankclaw. Two quadlet-managed containers in the rootless podman session of user `dank`: Gitea and PostgreSQL, sharing a dedicated network unit. The former `gitea-caddy` container is **retired** — the canonical fleet Caddy (`caddy.service`, see [/caddy/index.md](/caddy/index.md)) fronts `gitea.franksdank.cloud`; do not recreate the retired unit.
|
||||
|
||||
**Host:** dankclaw (71.227.227.172)
|
||||
**Config:** `~/.config/containers/systemd/gitea-{postgres,server,caddy}.container` + `gitea.network`
|
||||
**Local access:** `http://dankclaw:3000`
|
||||
**Domain:** `https://gitea.franksdank.cloud` (DNS pending)
|
||||
**Host:** dankclaw (192.168.0.143 LAN)
|
||||
**Config:** `~/.config/containers/systemd/gitea-{postgres,server}.container` + `gitea.network`
|
||||
**Local access:** `http://dankclaw:3000` (verified 2026-10-18)
|
||||
**Domain:** `https://gitea.franksdank.cloud` (live; served by fleet Caddy, DNS-01 TLS)
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -13,7 +13,7 @@ Private Git hosting on dankclaw. Three quadlet-managed containers in the rootles
|
||||
|---|---|---|---|
|
||||
| `gitea-server` | `gitea-server.service` | 3000 (HTTP), 2222 (SSH) | Git web UI, API, SSH daemon |
|
||||
| `gitea-postgres` | `gitea-postgres.service` | 5432 (internal) | Database |
|
||||
| `gitea-caddy` | `gitea-caddy.service` | 80, 443 | Reverse proxy, auto-TLS |
|
||||
| (network) | `gitea-network.service` | — | quadlet `gitea.network` bring-up |
|
||||
|
||||
The containers share the private network `systemd-gitea` (quadlet `gitea.network`, DNS enabled). The automatic `podman` default network has DNS disabled; do not run the stack on it.
|
||||
|
||||
@@ -23,21 +23,21 @@ All commands run as `dank` on dankclaw.
|
||||
|
||||
| Action | Command |
|
||||
|---|---|
|
||||
| Start all | `systemctl --user start gitea-postgres gitea-server gitea-caddy` |
|
||||
| Stop all | `systemctl --user stop gitea-caddy gitea-server gitea-postgres` |
|
||||
| Start all | `systemctl --user start gitea-postgres gitea-server` |
|
||||
| Stop all | `systemctl --user stop gitea-server gitea-postgres` |
|
||||
| Restart Gitea only | `systemctl --user restart gitea-server` |
|
||||
| Follow logs | `podman logs -f gitea-server` or `journalctl --user -u gitea-server -f` |
|
||||
| Check status | `systemctl --user status gitea-postgres gitea-server gitea-caddy` |
|
||||
| Check status | `systemctl --user status gitea-postgres gitea-server` |
|
||||
|
||||
## Data Persistence
|
||||
|
||||
All data lives on host bind mounts under `/opt/gitea/data/`. Containers are ephemeral. Stopping a quadlet unit removes its container; the next start recreates it. Volumes survive.
|
||||
All data lives on host bind mounts under `/home/dank/Containers/gitea/` (fleet storage standard since 2026-09-01; verified live 2026-10-18). Containers are ephemeral. Stopping a quadlet unit removes its container; the next start recreates it. Volumes survive. The old `/opt/gitea/` tree remains on disk as a leftover — do not use it.
|
||||
|
||||
| Volume Path | Container Mount | Contents |
|
||||
|---|---|---|
|
||||
| `/opt/gitea/data/gitea-gitea/` | `/data` | Git repositories, app.ini, attachments |
|
||||
| `/opt/gitea/data/gitea-postgres/` | `/var/lib/postgresql/data` | PostgreSQL data files |
|
||||
| `/opt/gitea/data/caddy/data/` | `/root/.local/share/caddy` | Caddy configuration, TLS certs |
|
||||
| Path | Contents |
|
||||
|---|---|
|
||||
| `/home/dank/Containers/gitea/data/` | Git repositories, app.ini, attachments |
|
||||
| `/home/dank/Containers/gitea/postgres/` | PostgreSQL data files |
|
||||
| `/home/dank/Containers/gitea/env` | EnvironmentFile (mode 0600; `GITEA_DB_PASSWORD`) |
|
||||
|
||||
See [[data-persistence|data-persistence]] for backup and restore.
|
||||
|
||||
@@ -49,7 +49,7 @@ See [[management|management]] for boot persistence details and troubleshooting.
|
||||
|
||||
## Repo Copies
|
||||
|
||||
The quadlet files, Caddyfile, and `.env.example` are tracked in the `serverAppConfigs` repo under `dankclaw/gitea/`. The live password lives only in `/opt/gitea/.env` on the host (mode 0600).
|
||||
The quadlet files and `.env` templates are tracked in the `serverAppConfigs` deploy repo; the sibling vault page `Infrastructure/Gitea.md` (in `~/Projects/serverAppConfig/serverAppConfigs-docs/`) is the deploy-side source of truth. Secrets live only on the host under `Containers/gitea/` (mode 0600), never in either docs tree.
|
||||
|
||||
## See Also
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ tags:
|
||||
- gitea
|
||||
- management
|
||||
- quadlet
|
||||
- unverified
|
||||
verified: 2026-08-28
|
||||
verified: 2026-10-18
|
||||
---
|
||||
|
||||
# Gitea Management
|
||||
@@ -45,8 +44,8 @@ After editing a quadlet file: run `systemctl --user daemon-reload`, then restart
|
||||
| File | Path |
|
||||
|---|---|
|
||||
| Quadlet units | `~/.config/containers/systemd/gitea-*.container`, `gitea.network` |
|
||||
| Secrets | `/opt/gitea/.env` (mode 0600, `GITEA_DB_PASSWORD`) |
|
||||
| Gitea app config | `/opt/gitea/data/gitea-gitea/gitea/conf/app.ini` (container-owned, UID 100999) |
|
||||
| Secrets | `/home/dank/Containers/gitea/env` (mode 0600, `GITEA_DB_PASSWORD`) — quadlet `EnvironmentFile` |
|
||||
| Gitea app config | `/home/dank/Containers/gitea/data/gitea/conf/app.ini` (container-owned, UID 100999) |
|
||||
|
||||
Repo copies: `serverAppConfigs/dankclaw/gitea/` (quadlet files, `.env.example`). Copy edits to the target, then `daemon-reload` + restart.
|
||||
|
||||
@@ -62,7 +61,7 @@ Gitea handles database migrations automatically on startup. PostgreSQL version b
|
||||
|
||||
### Gitea cannot reach the database
|
||||
|
||||
Check the `[database] HOST` line in `/opt/gitea/data/gitea-gitea/gitea/conf/app.ini`. It must be `gitea-postgres:5432`. app.ini overrides the `DATABASE_HOST` env var.
|
||||
Check the `[database] HOST` line in `/home/dank/Containers/gitea/data/gitea/conf/app.ini`. It must be `gitea-postgres:5432`. app.ini overrides the `DATABASE_HOST` env var.
|
||||
|
||||
Then check name resolution from the container:
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ Configuration guides and reference material for installed software. Each tool ha
|
||||
|
||||
* [[cachyos|cachyos]] — Arch-based rolling release with performance-optimized kernels, repositories, and gaming stack. Running on the workstation.
|
||||
* [comfyui](comfyui/index.md) — Node-based AI image generation engine on dankclaw. FLUX.2 klein 4B, CPU backend, systemd managed.
|
||||
* [live-sync](live-sync.md) — Heartbeat daemon committing machine-written paths (memories, managed-skills, live config, dotfiles) in the command-center checkout; systemd user timer, alerts via ntfy.
|
||||
* [[applications|applications]] — Default userspace applications on CachyOS with Niri — browsers, editor, terminal, file manager, audio, screenshots, gaming.
|
||||
* ](ghostty/index.md) — GPU-accelerated terminal emulator with extensive configuration, keybindings, and shaders.
|
||||
* ](gitea/index.md) — Private Git hosting on dankclaw. Quadlet-managed containers: Gitea, PostgreSQL, Caddy.
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
---
|
||||
type: reference
|
||||
title: live-sync heartbeat
|
||||
description: Auto-commit daemon for machine-written paths in the command-center checkout — the deployment is live, so symlinks make config churn dirty tracked files continuously.
|
||||
tags:
|
||||
- git
|
||||
- automation
|
||||
- systemd
|
||||
- deployment
|
||||
- fleet
|
||||
verified: 2026-10-18
|
||||
timestamp: 2026-10-18
|
||||
---
|
||||
|
||||
# live-sync heartbeat
|
||||
|
||||
The command-center checkout IS the deployment, and several tracked files are
|
||||
live state: the harness writes memories and managed-skills, the operator
|
||||
edits `config.yml`/`models.yml` through the `cfg://` surface, and desktop
|
||||
GUIs (Noctalia, niri) rewrite dotfiles through symlinks. Before Refs #11 this
|
||||
machine churn just piled up unpushed — one disk holding the only copy of ~61
|
||||
auto-learned skills, a settings fix stranded locally, and merge-refusals
|
||||
because the dirty tree collided with incoming work.
|
||||
|
||||
`scripts/live-sync.sh` is the pressure valve: a heartbeat that commits the
|
||||
machine's own writes on a schedule. Tier law (which paths it may touch) lives
|
||||
in [AGENTS.md](../../AGENTS.md) § Live-sync tiers.
|
||||
|
||||
## Contract (black-box)
|
||||
|
||||
Run = one pass: flock → branch guard (`main` only) → stage allowlisted dirty
|
||||
tiers → commit (hooks armed) → fetch + merge `origin/main` → push → reap
|
||||
stale `wt/*` worktrees. Exit `0` = quiet heartbeat (synced/no-op/reaped);
|
||||
exit `1` = an alert was raised. Pinned by `tests/live-sync.bats`.
|
||||
|
||||
Hard properties:
|
||||
|
||||
- **Allowlist only.** Task dirt (`plugins/`, `omp-docs/`, prose) is never
|
||||
staged — merge conflicts with in-flight work become impossible by
|
||||
construction.
|
||||
- **Hooks stay armed.** A secret-gate refusal aborts the commit, leaves
|
||||
changes staged for a human, and alerts. Never `--no-verify`, never force.
|
||||
- **Never fights the remote.** Merge conflict → `merge --abort`, local
|
||||
commit kept, alert. Retries are automatic next tick.
|
||||
- **Branch guard.** On a non-`main` checkout it refuses and alerts — same
|
||||
rule as the doctrine ("never end a session off main").
|
||||
- **Polite reaper.** `wt/wt-*` worktrees untouched for 7+ days are removed
|
||||
with their `wt/*` branch; dirty or process-occupied worktrees are skipped.
|
||||
|
||||
## Alerts
|
||||
|
||||
`notify()` writes stderr always; pushes to ntfy when the topic file
|
||||
`~/.config/ntfy/live-sync` (mode 600, topic text only) exists, throttled to
|
||||
one push per hour. Test seams: `LIVE_SYNC_REPO`, `LIVE_SYNC_NOTIFY`,
|
||||
`LIVE_SYNC_NTFY_TOPIC_FILE`, `LIVE_SYNC_AGE_DAYS`.
|
||||
|
||||
## Install
|
||||
|
||||
Units ship in `dotfiles/systemd-user/.config/systemd/user/` and propagate
|
||||
with the usual dotfiles chain:
|
||||
|
||||
```bash
|
||||
systemctl --user enable --now live-sync.timer # after the unit is linked
|
||||
systemctl --user start live-sync.service # one manual heartbeat
|
||||
journalctl --user -u live-sync.service -n 20 # observe
|
||||
```
|
||||
|
||||
## Failure modes
|
||||
|
||||
| Event | Result |
|
||||
|-------|--------|
|
||||
| Harness mid-write | commits a valid snapshot; remainder lands next heartbeat |
|
||||
| Gitea down | commit safe locally; push retries next tick (≤1 h stale window) |
|
||||
| Feature branch checked out in main checkout | refuses + alerts; protects the never-end-off-main rule |
|
||||
| Secret shape in machine-written content | hook blocks, changes stay staged, alert |
|
||||
@@ -50,7 +50,7 @@ llama-server -hf ggml-org/gemma-3-1b-it-GGUF
|
||||
|
||||
**Defaults**: Listens on `127.0.0.1:8080`. Single slot (one concurrent request).
|
||||
|
||||
> **System note:** On this network the Pi inference hosts do not use the default port. Pi serves `frank-default-small` (dankserver) and `frank-default-large` (dankclaw), each on port `7770`. The local Ornith host runs on port `8080`. See [Pi Models Configuration](../../pi/models.md).
|
||||
> **System note:** On this network the fleet inference hosts do not use the default port. As of 2026-10 the only llama.cpp endpoint is `frank-zealot` on dankclaw **:7771** (PrismML fork build); `frank-dragoon` (dankclaw :7770, halogen-flash-server) and `frank-archon` (dankserver :7770, radiance) are different engines — see [System hosts](/system/index.md). The pi-era `frank-default-small`/`frank-default-large` llama.cpp pair (each :7770) is retired; [Pi Models Configuration](../../pi/models.md) is a pi-era archive.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Executable
+131
@@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env bash
|
||||
# live-sync.sh — heartbeat committer for machine-written paths in the command
|
||||
# center checkout. Refs #11 (see omp-docs/tools/live-sync.md).
|
||||
#
|
||||
# The checkout IS the deployment; the harness, auto-learn, and desktop GUIs
|
||||
# write tracked files continuously through symlinks. This script commits ONLY
|
||||
# the allowlisted machine-live + desktop-live tiers (AGENTS.md § Live-sync
|
||||
# tiers), merges the trunk, pushes, and reaps stale session worktrees. Task
|
||||
# dirt outside the allowlist is NEVER committed — only surfaced.
|
||||
#
|
||||
# Black-box contract (tests/live-sync.bats pins it):
|
||||
# input git state of $LIVE_SYNC_REPO
|
||||
# output exit 0 = quiet heartbeat (synced, no-op, or reaped)
|
||||
# exit 1 = alert raised (branch guard, hook refusal, merge conflict,
|
||||
# fetch/push failure); alert goes to stderr + notify sink
|
||||
# Env overrides (test seams):
|
||||
# LIVE_SYNC_REPO target repo (default $HOME/.omp)
|
||||
# LIVE_SYNC_NOTIFY alert command, message on stdin
|
||||
# LIVE_SYNC_NTFY_TOPIC_FILE ntfy topic file, mode 600 (default
|
||||
# ~/.config/ntfy/live-sync; absent/empty = no push)
|
||||
# LIVE_SYNC_AGE_DAYS wt/wt-* reap threshold (default 7)
|
||||
set -euo pipefail
|
||||
|
||||
REPO="${LIVE_SYNC_REPO:-$HOME/.omp}"
|
||||
AGE_DAYS="${LIVE_SYNC_AGE_DAYS:-7}"
|
||||
TOPIC_FILE="${LIVE_SYNC_NTFY_TOPIC_FILE:-$HOME/.config/ntfy/live-sync}"
|
||||
STATE_DIR="${XDG_RUNTIME_DIR:-/tmp}"
|
||||
|
||||
# Allowlist tiers. Human prose (AGENTS.md, omp-docs, scripts, plugins,
|
||||
# agent/skills) is deliberately absent: branch -> PR territory, never swept.
|
||||
LIVE_PATHS=(
|
||||
agent/memories
|
||||
agent/managed-skills
|
||||
agent/config.yml
|
||||
agent/models.yml
|
||||
dotfiles
|
||||
)
|
||||
|
||||
notify() {
|
||||
local msg="live-sync: $1" stamp now
|
||||
stamp=$(cat "$STATE_DIR/live-sync.alert" 2>/dev/null || echo 0)
|
||||
now=$(date +%s)
|
||||
if (( now - stamp >= 3600 )); then
|
||||
date +%s > "$STATE_DIR/live-sync.alert"
|
||||
if [[ -n "${LIVE_SYNC_NOTIFY:-}" ]]; then
|
||||
printf '%s' "$msg" | $LIVE_SYNC_NOTIFY || true
|
||||
elif [[ -s "$TOPIC_FILE" ]]; then
|
||||
curl -fsS -m 10 -d "$msg" "https://ntfy.sh/$(<"$TOPIC_FILE")" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
printf '%s\n' "$msg" >&2
|
||||
}
|
||||
|
||||
cd "$REPO" 2>/dev/null || exit 0
|
||||
exec 9>"$STATE_DIR/live-sync.lock"
|
||||
flock -n 9 || exit 0 # another heartbeat owns the repo
|
||||
git rev-parse --verify -q HEAD >/dev/null || exit 0
|
||||
|
||||
branch=$(git symbolic-ref --quiet --short HEAD || true)
|
||||
if [[ "$branch" != main ]]; then
|
||||
notify "on branch '$branch', not main — refusing to sync, nothing changed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 1. stage only allowlisted paths that actually hold dirt (pathspecs that
|
||||
# match nothing would make git add fatal, so check per-path)
|
||||
for p in "${LIVE_PATHS[@]}"; do
|
||||
if [[ -n $(git status --porcelain -- "$p") ]]; then
|
||||
git add -A -- "$p"
|
||||
fi
|
||||
done
|
||||
|
||||
if ! git diff --cached --quiet; then
|
||||
# 2. commit WITH hooks armed — the secret gate stays pointed at the diff;
|
||||
# a refusal here is the system working, never bypassed
|
||||
if ! git commit -q -m "live: heartbeat sync $(date -Is) (Refs #11)"; then
|
||||
notify "commit rejected by hook/secret gate — live changes left STAGED for a human"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 3. integrate trunk and publish; never fight the remote
|
||||
if git remote get-url origin >/dev/null 2>&1; then
|
||||
if ! git fetch -q origin; then
|
||||
notify "fetch failed — commit is safe locally, will retry next heartbeat"
|
||||
exit 1
|
||||
fi
|
||||
if git rev-parse --verify -q origin/main >/dev/null \
|
||||
&& ! git merge -q --no-edit origin/main; then
|
||||
git merge --abort || true
|
||||
notify "merge conflict with origin/main — local commit kept; needs you at the keyboard"
|
||||
exit 1
|
||||
fi
|
||||
if ! git push -q origin main; then
|
||||
notify "push failed — commit is safe locally, will retry next heartbeat"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# 4. reap session worktrees older than AGE_DAYS. Dirty worktrees are left
|
||||
# alone (git refuses), and so are any with a live process cwd inside.
|
||||
in_use() {
|
||||
local p
|
||||
for p in /proc/[0-9]*/cwd; do
|
||||
if [[ "$(readlink "$p" 2>/dev/null || true)" == "$1"* ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
git worktree prune
|
||||
reap_path="" reap_ref=""
|
||||
reap_flush() {
|
||||
if [[ "$reap_path" == "$REPO/wt/wt-"* && -d "$reap_path" ]] \
|
||||
&& [[ -z $(find "$reap_path" -mtime "-$AGE_DAYS" -print -quit) ]] \
|
||||
&& ! in_use "$reap_path"; then
|
||||
git worktree remove -- "$reap_path" 2>/dev/null && git worktree prune || true
|
||||
if [[ -n "$reap_ref" ]]; then
|
||||
git branch -q -d "${reap_ref#refs/heads/}" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
reap_path="" reap_ref=""
|
||||
}
|
||||
while IFS= read -r line; do
|
||||
case "$line" in
|
||||
"worktree "*) reap_flush; reap_path="${line#worktree }" ;;
|
||||
"branch "*) reap_ref="${line#branch }" ;;
|
||||
esac
|
||||
done < <(git worktree list --porcelain)
|
||||
reap_flush
|
||||
Executable
+176
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env bats
|
||||
# tests/live-sync.bats — black-box tests for scripts/live-sync.sh (Refs #11)
|
||||
#
|
||||
# Contract (see script header): the heartbeat commits ONLY allowlisted live
|
||||
# paths, merges origin/main, pushes, and reaps stale wt/* worktrees. Nothing
|
||||
# is observed except exit status, stderr, the notify-sink log, and git state.
|
||||
|
||||
setup() {
|
||||
TEST_TMP="$(mktemp -d)"
|
||||
REPO="$TEST_TMP/repo"
|
||||
export XDG_RUNTIME_DIR="$TEST_TMP/xdg"
|
||||
mkdir -p "$XDG_RUNTIME_DIR"
|
||||
export GIT_CONFIG_GLOBAL="$TEST_TMP/gitconfig" GIT_CONFIG_SYSTEM=/dev/null
|
||||
export GIT_AUTHOR_DATE="2026-10-18T12:00:00+00:00" GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
|
||||
export LIVE_SYNC_REPO="$REPO"
|
||||
export LIVE_SYNC_NTFY_TOPIC_FILE="$TEST_TMP/no-topic-file"
|
||||
export LIVE_SYNC_NOTIFY="$TEST_TMP/notify-stub"
|
||||
export LIVE_SYNC_AGE_DAYS=7
|
||||
|
||||
# notify sink: appends each alert line to alerts.log
|
||||
cat > "$LIVE_SYNC_NOTIFY" <<STUB
|
||||
#!/usr/bin/env bash
|
||||
cat >> "$TEST_TMP/alerts.log"
|
||||
echo >> "$TEST_TMP/alerts.log"
|
||||
STUB
|
||||
chmod +x "$LIVE_SYNC_NOTIFY"
|
||||
|
||||
# bare "origin" + seeded clone with all tiers represented
|
||||
git init -q --bare -b main "$TEST_TMP/origin.git"
|
||||
git clone -q "$TEST_TMP/origin.git" "$REPO"
|
||||
git -C "$REPO" config user.email frank@dank
|
||||
git -C "$REPO" config user.name Frank
|
||||
git -C "$REPO" checkout -q -b main
|
||||
mkdir -p "$REPO/agent/memories" "$REPO/agent/managed-skills/s1" \
|
||||
"$REPO/dotfiles/bash" "$REPO/plugins/bench" "$REPO/scripts"
|
||||
echo base > "$REPO/agent/config.yml"
|
||||
echo base > "$REPO/agent/models.yml"
|
||||
echo base > "$REPO/agent/memories/learned.md"
|
||||
echo base > "$REPO/agent/managed-skills/s1/SKILL.md"
|
||||
echo base > "$REPO/dotfiles/bash/bashrc"
|
||||
echo base > "$REPO/AGENTS.md"
|
||||
echo base > "$REPO/scripts/deploy.sh"
|
||||
echo base > "$REPO/plugins/bench/server.py"
|
||||
git -C "$REPO" add -A
|
||||
git -C "$REPO" commit -q -m seed
|
||||
git -C "$REPO" push -q origin main
|
||||
SEED="$(git -C "$REPO" rev-parse HEAD)"
|
||||
}
|
||||
|
||||
teardown() { rm -rf "$TEST_TMP"; }
|
||||
|
||||
@test "heartbeat commits allowlisted live dirt only; task dirt stays dirty" {
|
||||
echo new > "$REPO/agent/memories/learned.md"
|
||||
mkdir "$REPO/agent/managed-skills/s2"
|
||||
echo new > "$REPO/agent/managed-skills/s2/SKILL.md"
|
||||
echo new > "$REPO/AGENTS.md"
|
||||
echo new > "$REPO/plugins/bench/server.py"
|
||||
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# exactly one new commit ahead of the seed
|
||||
[ "$(git -C "$REPO" rev-list --count "$SEED"..main)" -eq 1 ]
|
||||
# it touches ONLY live paths (untracked new dirs picked up too)
|
||||
run git -C "$REPO" show --pretty=format: --name-only HEAD
|
||||
printf '%s\n' "${lines[@]}" | grep -v '^$' | sort | diff -q - <(
|
||||
printf '%s\n' agent/managed-skills/s2/SKILL.md agent/memories/learned.md)
|
||||
# task dirt untouched, uncommitted
|
||||
[ -n "$(git -C "$REPO" status --porcelain -- AGENTS.md plugins)" ]
|
||||
# pushed: origin caught up
|
||||
[ "$(git -C "$REPO" rev-parse origin/main)" = "$(git -C "$REPO" rev-parse main)" ]
|
||||
}
|
||||
|
||||
@test "clean tree is a silent no-op" {
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(git -C "$REPO" rev-list --count "$SEED"..main)" -eq 0 ]
|
||||
[ ! -e "$TEST_TMP/alerts.log" ]
|
||||
}
|
||||
|
||||
@test "non-allowlist dirt alone never commits" {
|
||||
echo new > "$REPO/AGENTS.md"
|
||||
echo new > "$REPO/scripts/deploy.sh"
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(git -C "$REPO" rev-list --count "$SEED"..main)" -eq 0 ]
|
||||
[ -n "$(git -C "$REPO" status --porcelain -- AGENTS.md scripts)" ]
|
||||
}
|
||||
|
||||
@test "merge conflict aborts, keeps local commit, alerts, leaves remote alone" {
|
||||
# a second clone advances origin/main on the same live file
|
||||
git clone -q -b main "$TEST_TMP/origin.git" "$TEST_TMP/pocket"
|
||||
git -C "$TEST_TMP/pocket" config user.email pocket@dank
|
||||
git -C "$TEST_TMP/pocket" config user.name Pocket
|
||||
echo remote-side > "$TEST_TMP/pocket/agent/models.yml"
|
||||
git -C "$TEST_TMP/pocket" commit -qam "remote advance"
|
||||
git -C "$TEST_TMP/pocket" push -q origin main
|
||||
|
||||
echo local-side > "$REPO/agent/models.yml"
|
||||
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"merge conflict"* ]]
|
||||
[ -s "$TEST_TMP/alerts.log" ]
|
||||
# HEAD is my local commit, merge left no residue, remote untouched
|
||||
[[ "$(git -C "$REPO" log --format=%s -1)" == live:*"heartbeat sync"* ]]
|
||||
[ ! -e "$REPO/.git/MERGE_HEAD" ]
|
||||
[ "$(git -C "$REPO" rev-parse origin/main)" = "$(git -C "$TEST_TMP/pocket" rev-parse main)" ]
|
||||
}
|
||||
|
||||
@test "branch guard refuses to sync on a feature branch" {
|
||||
git -C "$REPO" checkout -q -b feature/whatever
|
||||
echo new > "$REPO/agent/config.yml"
|
||||
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"not main"* ]]
|
||||
[ "$(git -C "$REPO" rev-list --count "$SEED"..feature/whatever)" -eq 0 ]
|
||||
[ -n "$(git -C "$REPO" status --porcelain -- agent/config.yml)" ]
|
||||
}
|
||||
|
||||
@test "pre-commit hook refusal is surfaced, not bypassed; changes stay staged" {
|
||||
mkdir "$TEST_TMP/hooks"
|
||||
printf '#!/bin/sh\nexit 1\n' > "$TEST_TMP/hooks/pre-commit"
|
||||
chmod +x "$TEST_TMP/hooks/pre-commit"
|
||||
git -C "$REPO" config core.hooksPath "$TEST_TMP/hooks"
|
||||
echo new > "$REPO/dotfiles/bash/bashrc"
|
||||
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"rejected"* ]]
|
||||
[ -n "$(git -C "$REPO" diff --cached --name-only -- dotfiles)" ]
|
||||
[ "$(git -C "$REPO" rev-list --count "$SEED"..main)" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "repo without origin still commits locally and exits clean" {
|
||||
git -C "$REPO" remote remove origin
|
||||
echo new > "$REPO/dotfiles/bash/bashrc"
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$(git -C "$REPO" rev-list --count "$SEED"..main)" -eq 1 ]
|
||||
}
|
||||
|
||||
@test "stale wt/* worktree and its branch are reaped; fresh one survives" {
|
||||
git -C "$REPO" worktree add -q wt/wt-old -b wt/old
|
||||
git -C "$REPO" worktree add -q wt/wt-new -b wt/new
|
||||
touch -d "10 days ago" "$REPO/wt/wt-old"
|
||||
find "$REPO/wt/wt-old" -exec touch -d "10 days ago" {} +
|
||||
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[ ! -d "$REPO/wt/wt-old" ]
|
||||
[ -d "$REPO/wt/wt-new" ]
|
||||
run git -C "$REPO" show-ref --verify refs/heads/wt/old
|
||||
[ "$status" -ne 0 ]
|
||||
git -C "$REPO" show-ref --verify --quiet refs/heads/wt/new
|
||||
}
|
||||
|
||||
@test "second heartbeat inside the throttle window alerts once, never twice" {
|
||||
# two conflicting heartbeats: alert sink must see exactly one line
|
||||
git clone -q -b main "$TEST_TMP/origin.git" "$TEST_TMP/pocket"
|
||||
git -C "$TEST_TMP/pocket" config user.email pocket@dank
|
||||
git -C "$TEST_TMP/pocket" config user.name Pocket
|
||||
echo remote-side > "$TEST_TMP/pocket/agent/config.yml"
|
||||
git -C "$TEST_TMP/pocket" commit -qam "remote advance"
|
||||
git -C "$TEST_TMP/pocket" push -q origin main
|
||||
echo local-side > "$REPO/agent/config.yml"
|
||||
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 1 ]
|
||||
rm -f "$XDG_RUNTIME_DIR/live-sync.lock" # flock releases with the process; state stays
|
||||
echo local-side2 > "$REPO/agent/config.yml"
|
||||
run "$BATS_TEST_DIRNAME/../scripts/live-sync.sh"
|
||||
[ "$status" -eq 1 ]
|
||||
[ "$(wc -l < "$TEST_TMP/alerts.log")" -eq 1 ]
|
||||
}
|
||||
Reference in New Issue
Block a user