Files
serverAppConfigs/serverAppConfigs-docs/Agent/OMP Harness.md
T
Frank 33eae71d33 docs: distill the managed skill library into the vault (waves 1-7)
All ~173 managed skills read in full and merged, one polished reference
page per skill-cluster:

- LLM cross-cutting (17 pages): GGUF Compatibility, Llama Cpp Serving
  Sizing, Llama Cpp Multi-Device Splits, PCIe Link and Atomics, RDNA4
  Container Serving, RDNA4 MoE Expert Offload VRAM Budget, vLLM Boot
  Forensics, vLLM Porting and Compile Triage, LLM Bench Windows, LLM
  Performance Diagnosis, Model Swap and Rollback, Tcclaviger Fork Ops,
  Heterogeneous Split Triage, FreeToken Builds + deltas folded into the
  retired runbooks (GLM DFlash2 port laws, Lucebox dual-R9700, R9V
  qualification pipeline, FLM pack registration, ik hybrid envelope,
  frank-medium split rebalance, llama.cpp GGUF preflight, batch-ubatch
  split section, bench-window D-state/stale-read notes, second-endpoint
  bring-up).
- Architecture (3): Stale Signal Audit, Quadlet Lifecycle, Deploy State
  Triage.
- Operations (6 + index): Remote Job Runner, Payload and Disk Reclaim,
  Container Host Reachability, Fleet Ops Playbook, Fleet Audit and
  Posture, SSH and Remote Access.
- Infrastructure: Observability Provisioning + Homepage Status Probes;
  updates to Authentik, Anubis, LAN-DNS (per-client DoH bypass, Porkbun
  zone ops), Swap Configuration, OpenWebUI, Hermes (pre-existing page
  preserved and extended).
- FrankBook-Pro: ARR-Stack filled (API split, schema-first probing,
  auth-posture, auth-config trap); qBittorrent E2E verification.
- Desktop/Agent/Research: Noctalia and Niri, OMP Harness, Agent Docs and
  Edits, Command Center Dotfiles, PICO-8 Asset Standards.
- Indexes: LLM Cross-Cutting References section, Operations/ and Agent/
  index pages, root-index Skill Distillation section, AGENTS.md pointer.
- log.md carries the wave plan.

check-vault-links.py 0 unresolved (185 pages); ./tests/run.sh 366/366.
2026-10-05 21:19:15 -07:00

12 KiB
Raw Blame History

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.
omp
harness
compaction
models-yml
context
samplers
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.

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-primary on the current shape)
  2. Output budget = capped at the target model's maxTokens (32,768 for frank-small; 36,864 frank-primary; 57,344 frank-large — 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-primary); 140,490 + 57,344 = 197,834 ≤ 200,700 (frank-large); 140,492 + 32,768 = 173,260 ≤ 200,704 (frank-small).

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.

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-large) 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-primary'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-large'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:
    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:
    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:
    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).