The docs-fact census wave re-read the live hosts and re-keyed every page it could: runtime/payload identities, ports, sizes, ledger figures, unit state, and the retirement banners that drifted as the fleet moved. The wave was interrupted mid-run, so this commit carries only what passed the integrity gates: every touched page parses (front matter or H1+status convention intact, balanced fences, no truncated tables, trailing newline), the docs_completeness and link-integrity seams are green, and bats is 384/384. Numbers that this session proved on live hosts are keyed to the measured value, not the page's earlier claim.
16 KiB
type, title, description, tags, timestamp
| type | title | description | tags | timestamp | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| reference | OMP Harness | The omp agent harness as configured on this fleet — compaction chain arithmetic, per-model sampler routing via compat.extraBody, and the static-preamble/skill-library audits that keep session context lean. |
|
2026-10-18T00:00:00Z |
OMP Harness
The harness reaches the fleet through ~/.omp/agent/models.yml (model
registry; single source of truth — there is no copy on the servers) and
~/.omp/agent/config.yml (roles, compaction, global samplers). Nothing in
this file is repo-managed; edits are harness-side only.
Model ids are the StarCraft unit names (official 2026-10-08, on the wire
since 2026-10-09): frank-archon (dankserver :7770, radiance),
frank-dragoon (dankclaw :7770, flash-server), frank-zealot (dankclaw
:7771, the 3090 compaction hub) — formerly frank-archon, frank-dragoon,
frank-zealot. The SERVICES keep the old names (units, scripts, env
files, runbook pages); pages written in the old era name the service,
the harness names the model. The wire now matches: each endpoint's
/v1/models answers with the Protoss name, so models.yml, the OpenWebUI
picker/grants, the homepage docs and the raw API all use one id per model
(see OpenWebUI for the grant re-key and the frank-archon-radiance-swift15-w4dn8
note on radiance echoing the requested name).
Verified 2026-10-18: /v1/models on 192.168.0.235:7770, 192.168.0.143:7770 and
192.168.0.143:7771 each answer with the unit name (frank-archon,
frank-dragoon, frank-zealot).
Compaction chain arithmetic (verify before ANY window change)
When a fleet endpoint's context grows past its harness-declared window, OMP
compacts by sending the conversation to a designated target model. Before
changing any contextWindow/maxTokens, verify the chain arithmetically —
a target whose window is smaller than the source's trigger point silently
breaks compaction.
Where the contract lives:
~/.omp/agent/config.yml→compaction.remoteEndpoint(target URL:http://192.168.0.143:7771/v1/chat/completions,config.yml:76),methodOrder(shake → snapcompact → soft → handoff → remote,config.yml:77-82),thresholdPercent(95,config.yml:84), idle settings (idleEnabled,idleThresholdTokens: 100000)~/.omp/agent/models.yml→ per-modelcontextWindow,maxTokens,compactionModelreferences- Implementation: omp plugin
~/.omp/plugins/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js
The arithmetic (the coupled contract every endpoint's maxTokens comment
encodes). Recomputed from the live files 2026-10-18 — contextWindows
200,000 (archon) / 155,648 (dragoon) / 200,704 (zealot) at
models.yml:48,131,206; maxTokens 16,384 / 45,056 / 16,384 at
models.yml:56,143,212:
- Source trigger =
thresholdPercent × source contextWindow; at the live 95 % that is 190,000 (archon), 147,866 (dragoon), 190,669 (zealot). The bundle clamps the percentage to 1–99 and converts it to a token threshold. - Output budget = capped at the target model's
maxTokens— every role here compacts to frank-zealot, so the budget is its 16,384. - REQUIREMENT: prompt (≤ trigger) + budget ≤ the target's per-slot
window. At 95 % this no longer holds: 190,000 + 16,384 = 206,384 >
200,704. The registry's own comments design around an 85 % trigger (archon:
170,000 est × 1.03 + 16,384 ≈ 191,500 ≤ 200,704,
models.yml:49-56), which does hold. Whileconfig.ymland those comments disagree, treat 85 % as the design point and re-run this arithmetic after ANY window change — a 400 from the compaction target mid-conversation is the symptom. (Historic 2026-10-05 pairs, atthresholdPercent: 70: 140,492 + 36,864 = 177,356 ≤ 200,704 archon; 140,490 + 57,344 ≤ 200,700 dragoon; 140,492 + 32,768 ≤ 200,704 zealot.)
Procedure (recompute from the LIVE files every time — windows rotate with every swap; the block above is the 2026-10-18 state):
- Read the
config.ymlcompaction block +models.ymlentries for source and target. Every endpoint'scontextWindowcomment carries its own arithmetic — read them. - Read the target checkpoint's
max_position_embeddings(native window) — the served window may be a concurrency contract, not the native limit (--parallel NDIVIDES the pool; the per-slot number is the contract). - If native ≥ trigger + budget, reslice the pinned pool:
MAX_RUNNING × CONTEXT_LENGTH ≤ MAX_TOTAL_TOKENS(the pin exists because the runtime's autofit leaves too little for deferred loads + prefill workspace; checknvidia-smiheadroom — expect ~0.8 GB workspace margin). - Changes: host env (CONTEXT_LENGTH-style env tunables) via git →
./tests/run.sh→ deploy; harnessmodels.ymldirectly (no repo copy). - Verify:
/health200, boot log's pool line, then a long-prompt probe at ≥ trigger height (the compaction-fit guarantee), then concurrent requests.
Known reconciliation trap: comments in models.yml have described compaction
as running "on the dankserver endpoint" while remoteEndpoint pointed at
dankclaw — the comment/config disagreed. The comments now name the real
target (compaction.remoteEndpoint = dankclaw :7771). The config is
truth; fix comments in the same change. A fresh instance of the same trap is
open 2026-10-18: every maxTokens comment still says "compaction fires at
85 % of the window" while config.yml:84 sets thresholdPercent: 95.
maxTokens never changes for a reslice — it caps output; contextWindow caps
input. Boot-shape OOM laddering is a different problem
(Llama Cpp Serving Sizing).
Per-model sampler config (compat.extraBody)
models.yml has no per-model sampler keys. The global knobs are
config.yml's temperature, topP, topK, minP, presencePenalty,
repetitionPenalty, and a knob reaches the wire only when it is set — the
bundle guards each one with !== void 0 (e.g. minP!==void 0)e.min_p=t.minP),
and this workstation's config.yml sets none of them. The 2026-10-05 note
that the unset default is -1/"not sent" is retired: there is no -1
sentinel, an unset key is simply absent. The per-model hook is
compat.extraBody:
Why it works: applyOpenAIExtraBody runs last in the
openai-completions builder — after applyChatCompletionsCompatPolicy — via
Object.assign(params, extraBody). So extraBody overrides global settings
and compat-policy output.
compat:
reasoningEffortMap:
max: xhigh
extraBody:
temperature: 1.0
top_p: 0.95
top_k: 20
min_p: 0.0
presence_penalty: 0.0
repetition_penalty: 1.0
preserve_thinking: true
Use wire names, not OMP camelCase. Two traps:
preserve_thinkingis not user-settable as a compat key.qwenPreserveThinkingis auto-derived inbuildOpenAICompatfrom the auto-detectedthinkingFormat+ local baseUrl, beforeapplyCompatOverrides. Settingcompat.thinkingFormat: qwenin models.yml does not enable it. Custom-named models (frank-dragoon) match no Qwen id pattern → useextraBody: {preserve_thinking: true}.- Never put
chat_template_kwargsinextraBodywhere a compat policy also sets it —Object.assignis shallow and replaces the whole object, silently dropping thereasoning_effortkwarg the compat policy set. Top-levelpreserve_thinkingis honoured by halogen. Live state 2026-10-18: frank-archon's radiance entry carrieschat_template_kwargs: {enable_thinking, preserve_thinking}inextraBody(models.yml:89-91) and nothing else sets that object at that endpoint, so the shallow-merge hazard is latent rather than firing; the FreeToken-era "verify-and-prune at the next swap" note is retired with that swap (2026-10-05,scripts/serve-frank-archon.sh:9-10).
Gotcha (retired 2026-10-17): silent greedy decode. Earlier flash-server
builds carried no server-side sampler defaults, so an absent
temperature decoded greedy while the endpoint looked configured. That era is
over: HALOGEN_TEMPERATURE/TOP_P/TOP_K now set the card's thinking recipe
(1.0 / 0.95 / 20) as engine defaults (scripts/frank-dragoon.env:98-103,
exported at scripts/serve-frank-dragoon.sh:186-188), so an absent temperature
is no longer greedy. frank-dragoon's extraBody still carries the same trio —
consistent, not load-bearing. Treat any older "do not drop it or you get
greedy" wording as history.
Reasoning-effort folding. Qwen3.8's template accepts only
{xhigh (default), medium, low} for reasoning_effort and 400s on anything
else ("Unexpected reasoning effort high"). Every endpoint's
reasoningEffortMap folds all harness levels onto that set; a role whose
level is unmapped fails on its FIRST request, and the failure names Jinja,
not the model.
Verify the exact wire body (echo-capture)
Don't trust the YAML — capture what OMP actually emits:
- Echo server on
127.0.0.1:18099that dumps the JSON body to a file and returns a cannedchat.completion(includereasoning_contentso thinking paths exercise). - Copy the real models.yml into a throwaway profile with only the
baseUrl swapped:
sed 's|http://<host>:7770/v1|http://127.0.0.1:18099/v1|' \ ~/.omp/agent/models.yml > ~/.omp/profiles/wiretest/agent/models.yml - Run and inspect:
Confirm every intended field is present with the right value.
omp --profile wiretest --model "<provider>/<model>" -p "hi" \ --no-tools --no-session --no-extensions --no-skills --no-rules jq 'del(.messages, .tools)' last-body.json
Verify a field is honoured, not just accepted — unknown fields often
return 200 anyway. Prove behavior with a prompt-token delta: replay an
assistant turn carrying a long reasoning_content, then compare
usage.prompt_tokens with the flag true vs false. A large delta means the
field changed template rendering; zero delta means it was ignored.
Cleanup: trash the probe profile and echo server (profiles/.AGENTTRASH),
never rm.
Static-preamble audit ("the context feels bloated")
What loads statically every session (measure each, don't guess):
- Repo rules file —
wc -c AGENTS.md(baseline 2026-10-05: 72,179 B, ~18k tokens — historically the largest block; re-measured 2026-10-18: 89,723 B). - Skill index — only names+descriptions load; bodies are on-demand. Sum
description bytes across all SKILL.md frontmatter:
Baseline 2026-10-05: 171 managed skills / ~38 KB descriptions + 9 user skills. Re-measured 2026-10-18 with the same glob: 87 managed
python3 - <<'EOF' import glob, re, os for root in [os.path.expanduser("~/.omp/agent/managed-skills"), os.path.expanduser("~/.omp/agent/skills"), ".omp/skills"]: n=tot=0 for sk in glob.glob(root+"/*/SKILL.md"): fm=re.search(r'^---.*?---', open(sk, encoding="utf-8", errors="replace").read(), re.S) d=re.search(r'description:\s*(.*(?:\n(?:\s{2,}.*)*)?)', fm.group(0) if fm else "") n+=1; tot+=len(d.group(1)) if d else 0 print(root, n, tot) EOFSKILL.md+ 9 user skills — the dedupe happened. - Memory lessons —
find ~/.omp/agent/memories -name 'MEMORY.md' -o -name 'memory_summary.md' | xargs wc -c. The injected block ≈ the largest MEMORY.md. - Harness/system prompt + tool schemas + CLI persona: fixed cost, ~20 KB; not prunable.
Known rot patterns:
- Near-duplicate auto-captures of the same lesson (three "authentik ORM"
entries, the freetoken-build pair, the three job-runner skills) — dedupe
via
manage_skill delete/update. - Corrupted captures containing stray CJK characters (
一团ly,等方法) mid-sentence — a known defect of the auto-capture path; delete the corrupt copy, keep the clean one. - Stale host/service names in consolidated memory (pre-rename
frank-default-large) — the repo's AGENTS.md topology table is ground truth.
Fix strategy: AGENTS.md prose (measured runbook narratives) → move to
serverAppConfigs-docs/LLM/ runbooks, keep laws + tables in AGENTS.md (the
repo's own docs-tree rule mandates this). Managed skills live in
~/.omp/agent/managed-skills (safe to edit); user-authored skills in
~/.omp/agent/skills are NEVER touched by tooling. Memory store edits:
stage removed captures to trash first (~/.AGENTTRASH/YYYYMMDD-topic).
Baseline to beat (2026-10-05): ~35–40k tokens of preamble — AGENTS.md ~18k, skill index ~10k, lessons ~3.5k, harness ~6k. Proposed reductions: −12k (AGENTS.md slimming), −3k (skill dedupe).
Managed-skill library hygiene
Use when auditing, pruning, or consolidating ~/.omp/agent/managed-skills
(the auto-captured skill store; the full index is injected into EVERY
session's context, so dead or duplicate entries are a permanent tax).
The static-context budget (measured 2026-10-05):
| Block | Size | Notes |
|---|---|---|
AGENTS.md (repo) |
72,179 B ≈ 18k tok | biggest single item |
| Skill index (~173 skills) | ~40 KB ≈ 10k tok | names+descriptions only |
| Learned-lessons block | ~14 KB | can contain corrupted/duplicate captures |
| Harness system prompt + tool schemas | ~23 KB | fixed |
Re-measured 2026-10-18: the skill library is down to 87 managed skills, but
AGENTS.md has grown to 89,723 B — the dedupe landed, the slimming did not.
Audit procedure:
- Build an inventory: per skill, name, mtime, body word count, description, first 12 headings (one pass, out to a file; read in pages).
- Group into: retired-runtime (host/service gone; its runbook already lives
in
serverAppConfigs-docs/LLM/), verbatim-duplicate pairs/triples (same lesson captured twice — often the SAME DAY), same-lesson families (N skills = one procedure), keep. - Read full bodies of every merge candidate before proposing a merge; description alone proves overlap only for exact dupes.
- Present A/B/C/D verdicts for user approval. NEVER execute before the discussion concludes — the user gates execution explicitly.
- On approval: stage everything to trash first
(
~/.AGENTTRASH/YYYYMMDD-<topic>/), never rm. After merging: recreate the surviving skill viamanage_skillupdate with body = superset, delete absorbed ones.
Known rot classes (this library, 2026-10-05):
- Same-day duplicate captures (freetoken-build-dankclaw vs freetoken-dankclaw-build; the three job-runner skills).
- CUDA-skill vs its self-declared HIP twin (pcie-link-capability-probe vs pcie-link-probe-hip-rdna4) → merge.
- Era ghosts: skills naming retired runtimes (freetoken, lucebox, r9v/ radiance, old halogen-flash-server image, ik_llama, GLM-5.3 experiment).
- Skills contradicting user standing orders (live-bench-dashboard vs the 2026-09-29 delete-dashboards order) — flag for user, don't assume.
- Memory store: corrupted captures with CJK noise from broken ssh commands; stale host/service renames.
Sizing verdicts that worked: bench family → 2 skills (harness vs discipline), not one mega-skill; keep profiler/kernel-time attribution standalone; fold go/no-go arithmetic skills into their probe skill (heterogeneous-accelerator-split-triage → PCIe probe).
Related
- Agent Docs and Edits — editing vault docs and hashline targets safely
- Command Center Dotfiles — the
~/.omprepo deploy this config rides - Llama Cpp Serving Sizing — the engine-side sizing the chain must fit
- LLM Bench Windows and Measurement — measuring the endpoints this config routes