Files
serverAppConfigs/serverAppConfigs-docs/Agent/OMP Harness.md
T
Frank 55f87fcdce llm: retire the trio service names — fleet services renamed to frank-archon/frank-dragoon/frank-zealot
The 2026-10-09 wire aliases become the service names everywhere:
systemd units, serve scripts, env files and FRANK_* variables,
deploy-plan/deploy-remote service keys, container names, Prometheus
job names + alert rules, Grafana dashboard queries, bats seams,
runbook filenames, homepage/AGENTS lore, and historical prose.
Rollback tags renamed in lockstep. Residue in the tree: zero.
Retired frank-medium/small/npu names are history and stay.

Known casualty: scripts/patches/*.patch context lines were rewritten;
those retired-era vLLM-fork patches no longer apply byte-exact.
2026-10-10 17:03:14 -07:00

275 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
type: reference
title: OMP Harness
description: 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.
tags: [omp, harness, compaction, models-yml, context, samplers]
timestamp: 2026-10-05T00:00:00-07:00
---
# 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).
## 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),
`methodOrder`, `thresholdPercent` (70), idle settings
- `~/.omp/agent/models.yml` → per-model `contextWindow`, `maxTokens`,
`compactionModel` references
- Implementation: omp plugin `dist/core/compaction/compaction.js`
The arithmetic (the coupled contract every endpoint's maxTokens comment
encodes):
1. **Source trigger** = `thresholdPercent × source contextWindow`
(0.70 × 200,704 = 140,492 for frank-archon on the current shape)
2. **Output budget** = capped at the target model's `maxTokens`
(32,768 for frank-zealot; 36,864 frank-archon; 57,344 frank-dragoon — the
largest, because halogen's `HALOGEN_MAX_TOKENS_CAP` must stay ≥ it)
3. **REQUIREMENT**: prompt (≤ trigger) + budget ≤ the target's per-slot
window. Worked pairs from the live registry: 140,492 + 36,864 = 177,356 ≤
200,704 (frank-archon); 140,490 + 57,344 = 197,834 ≤ 200,700
(frank-dragoon); 140,492 + 32,768 = 173,260 ≤ 200,704 (frank-zealot).
Procedure (recompute from the LIVE files every time — windows rotate with
every swap; the numbers above are the 2026-10-05 state):
1. Read the `config.yml` compaction block + `models.yml` entries for source
and target. Every endpoint's `contextWindow` comment carries its own
arithmetic — read them.
2. Read the target checkpoint's `max_position_embeddings` (native window) —
the served window may be a concurrency contract, not the native limit
(`--parallel N` DIVIDES the pool; the per-slot number is the contract).
3. 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; check `nvidia-smi` headroom — expect ~0.8 GB workspace margin).
4. Changes: host env (CONTEXT_LENGTH-style env tunables) via git →
`./tests/run.sh` → deploy; harness `models.yml` directly (no repo copy).
5. Verify: `/health` 200, 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.** `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**. Sampling is global
(`config.yml`: `temperature`, `topP`, `topK`, `minP`, `presencePenalty`,
`repetitionPenalty`; default `-1` = **not sent**). 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.
```yaml
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:
1. **`preserve_thinking` is not user-settable as a compat key.**
`qwenPreserveThinking` is auto-derived in `buildOpenAICompat` from the
*auto-detected* `thinkingFormat` + local baseUrl, **before**
`applyCompatOverrides`. Setting `compat.thinkingFormat: qwen` in
models.yml does **not** enable it. Custom-named models (`frank-dragoon`)
match no Qwen id pattern → use `extraBody: {preserve_thinking: true}`.
2. **Never put `chat_template_kwargs` in `extraBody`** where a compat policy
also sets it — `Object.assign` is shallow and replaces the whole object,
silently dropping the `reasoning_effort` kwarg the compat policy set.
Top-level `preserve_thinking` is honoured by halogen. (frank-archon's
FreeToken entry currently carries a `chat_template_kwargs` extraBody with
a comment asking to verify-and-prune — the exact trap to check at that
endpoint's next swap.)
**Gotcha: silent greedy decode.** halogen has **no server-side sampler
defaults** — `temperature` absent or `0` = greedy. If OMP sends nothing, the
endpoint decodes greedy while looking configured. This is why frank-dragoon's
entry carries the recipe on the wire and a comment saying "do not drop it".
**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:
1. Echo server on `127.0.0.1:18099` that dumps the JSON body to a file and
returns a canned `chat.completion` (include `reasoning_content` so
thinking paths exercise).
2. Copy the **real** models.yml into a throwaway profile with only the
baseUrl swapped:
```bash
sed 's|http://<host>:7770/v1|http://127.0.0.1:18099/v1|' \
~/.omp/agent/models.yml > ~/.omp/profiles/wiretest/agent/models.yml
```
3. Run and inspect:
```bash
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
```
Confirm every intended field is present with the right value.
**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):
1. Repo rules file — `wc -c AGENTS.md` (baseline 2026-10-05: 72,179 B, ~18k
tokens — historically the largest block).
2. Skill index — only names+descriptions load; bodies are on-demand. Sum
description bytes across all SKILL.md frontmatter:
```bash
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)
EOF
```
Baseline 2026-10-05: 171 managed skills / ~38 KB descriptions + 9 user
skills.
3. Memory lessons — `find ~/.omp/agent/memories -name 'MEMORY.md' -o -name
'memory_summary.md' | xargs wc -c`. The injected block ≈ the largest
MEMORY.md.
4. 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 |
Audit procedure:
1. Build an inventory: per skill, name, mtime, body word count, description,
first 12 headings (one pass, out to a file; read in pages).
2. 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.
3. Read full bodies of every merge candidate before proposing a merge;
description alone proves overlap only for exact dupes.
4. Present A/B/C/D verdicts for user approval. NEVER execute before the
discussion concludes — the user gates execution explicitly.
5. On approval: stage everything to trash first
(`~/.AGENTTRASH/YYYYMMDD-<topic>/`), never rm. After merging: recreate
the surviving skill via `manage_skill` update 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 `~/.omp` repo 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