Compare commits

...
Author SHA1 Message Date
root 8215b84f88 merge: resolve conflicts with master (delegation delete + gpu-fleet)
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 2s
2026-07-16 21:22:34 +00:00
jerome d6e85e68e9 Merge pull request 'UPDATE 2026-07-15: Full GPU fleet rebuild + stable aliases' (#18) from feat/gpu-fleet-rebuild-20260715 into master
PR Pipeline — Authorize → Validate → Review → Merge / auth (push) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / validate (push) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (push) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (push) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / gate (push) Successful in 0s
Reviewed-on: #18
2026-07-16 21:17:12 +00:00
root b7e23e2592 vault: Infisical cleanup + contract sync (WAL #1316)
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
- litellm-api-keys: vault audit, tanko/koby/koonimo migration, key rotation log
- gpu-fleet: ornith-1.0-35b→strix-moe (remaining refs)
- hermes-agent-baseline: 256K all GPUs, CT IPs updated, Shumba retired
- delegation-prose-contract: removed (renamed to mumuni-delegation)
- contract-registry.yaml + cron-prompts-review.md: from feat/contract-registry
2026-07-16 21:17:09 +00:00
root 369c312ccb vault: BAGGY_LITELLM_API_KEY deleted — one secret per agent
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
2026-07-16 19:54:51 +00:00
root 7f39a444d6 vault: BAGGY+LITELLM synced, deletion needs Infisical UI
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 1s
2026-07-16 19:28:28 +00:00
Abiba 17f4c79fe4 vault: sync BAGGY_LITELLM_API_KEY = KOONIMO_LITELLM_API_KEY (same agent CT113)
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 4s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
Baggy = Koonimo (CT 113). The vault had two divergent keys:
- BAGGY_LITELLM_API_KEY = sk-QT-kDt8Szo... (stale, 401)
- KOONIMO_LITELLM_API_KEY = sk-OEK7z26n6... (valid, 200, session-13 rotation)

Synced BAGGY to match KOONIMO (the valid key).
Added contract note: both secrets MUST mirror each other.
This was the root cause of Koonimo's 401 after migration —
the ghost process had BAGGY in its env instead of KOONIMO.
2026-07-16 19:22:48 +00:00
Abiba a9caf5b216 vault: fix koby platform connectivity + document migration lessons
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
Koby was broken after migration — Zulip credentials lost (only in process memory),
Telegram token overwritten (only existed in old .env.bak-20260603).

Fix: Koby shares Tanko's Zulip bot (tanko-bot@, TANKO_ZULIP_API_KEY in vault).
Telegram token recovered from .env.bak-20260603. Both platforms now connected.

Added Koby migration lessons to contract (back up .env before migration,
inject ALL platform env vars, cat /proc/pid/environ before killing old gateway).
Added KOBY_ZULIP_API_KEY to vault (shares Tanko's key).
2026-07-16 18:19:27 +00:00
Abiba 15a826457e vault: canonical Production Vault Access Process + sync vault + migrate koby/koonimo
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 5s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
- Vault SYNCED: mumuni/koby/koonimo rotated keys written to Infisical (all validate 200).
  Vault is source of truth again (was stale since session-13 rotations).
- Koby (.129) + Koonimo (.114) migrated from hardcoded systemd drop-ins to
  infisical-gateway.sh wrapper (live vault injection, .env fallback safety net).
  4/5 agents now vault-backed (abiba/mumuni/koby/koonimo).
- New § Production Vault Access Process: canonical 7-step pattern, migration status
  table, key rotation procedure, why-it's-non-fail rationale.
- Fixed stale notes: 'vault sync PENDING' (now synced), 'Abiba key IS master key'
  (now a proper agent key sk-sxbphLvk1OU).
- Tanko (user jerome, not systemd) documented as pending migration.
- hermes-key-enforcement: cross-ref to canonical process, drop-ins deprecated.
2026-07-16 17:51:53 +00:00
Abiba cd52deda92 contracts: stable alias chain + no-master-key-for-inference rule
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 3s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 0s
Agent configs aligned to stable aliases (gpu-light/gpu-dense/strix-moe/syslog-auto):
- Tanko fixed: base_url :4000->/v1 (nginx), max_context_window 131072->262144,
  aux.compression gemma->strix-moe, aux gemma->gpu-light
- Mumuni aligned: aux gemma->gpu-light, delegation/x_search qwen->gpu-dense
- Koby/Koonimo already used gpu-light (validated)
- Zero raw model names remain in any agent config

No-master-key rule: litellm_proxy_master_key (sk-litellm-...) is admin-only
(/key/list, /key/generate). All inference uses agent keys. Health-check model
tests use dedicated monitor key (/etc/litellm-monitor.env on CT 116).
Fixed: daily-infra-report.py, gpu-self-heal.py, litellm-health-check.sh.

Fixed wrong key-scope note: qwen3.6-35B-udq4 IS in scope for baggy/koby/mumuni/
abiba-pi keys (not 'NOT in allowlist' as previously documented).
2026-07-16 17:39:05 +00:00
Abiba 97f1cd77e4 litellm-self-heal: document 2026-07-16 ops sync (script fixes, systemd gpu-monitor, live-key agent check)
PR Pipeline — Authorize → Validate → Review → Merge / auth (pull_request) Successful in 5s
PR Pipeline — Authorize → Validate → Review → Merge / validate (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / lint (pull_request) Successful in 2s
PR Pipeline — Authorize → Validate → Review → Merge / ai-review (pull_request) Successful in 1s
PR Pipeline — Authorize → Validate → Review → Merge / gate (pull_request) Successful in 1s
Health-check script: critical-only gpu-fleet alerting, strix-moe model test.
gpu-monitor: systemd unit (was bare &), Strix counted in gpu_count, VRAM
thresholds raised (93/97 — 256K ctx steady-state ~96% on RTX 3090).
agent-health-check.py: reads live LITELLM_API_KEY from gateway env (no hardcoded keys).
daily-infra-report.py: stale SYNTHETIC key → env-based master key.
2026-07-16 17:23:37 +00:00
Abiba dc572889f8 contracts: sync to ground truth — ornith-1.0-35b→strix-moe, 256K all GPUs, real LiteLLM timeouts
Verified on ground 2026-07-16 against CT 116 litellm_config.yaml + GPU hosts:
- AMD host serves qwen3.6-35B-udq4 (LiteLLM alias strix-moe); ornith-1.0-35b does NOT exist
- All 3 GPUs at 256K ctx, parallel 2 (RTX 3090 was listed 128K/parallel 1)
- LiteLLM timeouts: qwen 300s, gemma 120s, strix 300s (were stale 90s/120s)
- Added LiteLLM model surface + key scoping to litellm-self-heal
- Patched health-check script path ref

Files: litellm-self-heal, litellm-health, gpu-fleet, gpu-self-heal,
zulip-adapter-lessons, abiba-zulip-restore, hermes-agent-baseline,
delegation-prose-contract, mumuni-delegation-prose-contract
2026-07-16 17:02:44 +00:00
Abiba d0feb7881e Contracts: Rule 13 two key-injection patterns + koby/baggy rotation log (WAL #1300) 2026-07-16 15:10:50 +00:00
Abiba 9fd8c68bd2 Contracts: replace remaining ornith-1.0-35b refs with strix-moe 2026-07-16 13:57:57 +00:00
Abiba 39e2fa0cfa Contracts: Mumuni context-fix (WAL #1300) — strix-moe, 256K all GPUs, Rule 12/13, machine-identity vault procedure 2026-07-16 13:57:31 +00:00
14 changed files with 2722 additions and 333 deletions
+1 -1
View File
@@ -276,7 +276,7 @@ ZULIP_ROLE=router pm2 start "$(which pi)" --name abiba-zulip \
**Additional fixes applied:**
- Fixed `models.json`: replaced `qwen3.6-35B-A3B` (not authorized by LiteLLM)
with `syslog-auto` + `ornith-1.0-35b` (prevents silent worker failure per
with `syslog-auto` + `strix-moe` (prevents silent worker failure per
Lesson #11)
- Removed stale systemd unit `abiba-zulip.service` (pointed to old TS code)
- PM2 saved for auto-restart on boot
File diff suppressed because it is too large Load Diff
+612
View File
@@ -0,0 +1,612 @@
# Cron Prompts Review — All 10 Scheduled Contracts
Generated: 2026-07-13 20:59:18 ET
---
## hermes-key-enforcement
**Category:** compliance | **Domain:** hermes-agent | **Owner:** abiba | **Schedule:** 0 6 * * *
```
Contract Enforcement: hermes-key-enforcement
Category: compliance
Domain: hermes-agent
Owner: abiba
Schedule: Daily compliance scan at 6am ET
This is a compliance contract. Verify that the contract enforces the required standards and policies. Report any violations found.
Steps:
1. Load contract from prose-contracts/main (file: hermes-key-enforcement.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/hermes-key-enforcement/
Postconditions to verify:
[
{
"check": "no plaintext API keys in config",
"verify": "grep -rc 'api_key: sk-' /root/.hermes/config.yaml",
"expect": "0 matches"
},
{
"check": "api_key_env used for harness/litellm providers",
"verify": "grep -c 'api_key_env.*LITELLM_API_KEY' /root/.hermes/config.yaml",
"expect": "count > 0"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert + pause
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + pause + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/hermes-key-enforcement/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=hermes-key-enforcement, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## hermes-config-template
**Category:** compliance | **Domain:** hermes-agent | **Owner:** abiba | **Schedule:** 0 4 * * 1
```
Contract Enforcement: hermes-config-template
Category: compliance
Domain: hermes-agent
Owner: abiba
Schedule: Weekly config drift check Monday at 4am ET
This is a compliance contract. Verify that the contract enforces the required standards and policies. Report any violations found.
Steps:
1. Load contract from prose-contracts/main (file: hermes-config-template.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/hermes-config-template/
Postconditions to verify:
[
{
"check": "agent config template_version matches template file",
"verify": "grep -q 'template_version' /root/.hermes/config.yaml && diff <(grep 'template_version' /root/.hermes/config.yaml | cut -d: -f2 | xargs) <(grep 'template_version' /root/prose-contracts/hermes-config-template.prose.md | cut -d: -f2 | xargs) && echo match || echo mismatch",
"expect": "match"
},
{
"check": "config file is valid YAML",
"verify": "python3 -c 'import yaml; yaml.safe_load(open(\"/root/.hermes/config.yaml\"))' && echo valid || echo invalid",
"expect": "valid"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/hermes-config-template/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=hermes-config-template, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## hermes-agent-baseline
**Category:** compliance | **Domain:** hermes-agent | **Owner:** abiba | **Schedule:** 0 5 * * 1
```
Contract Enforcement: hermes-agent-baseline
Category: compliance
Domain: hermes-agent
Owner: abiba
Schedule: Weekly baseline verification Monday at 5am ET
This is a compliance contract. Verify that the contract enforces the required standards and policies. Report any violations found.
Steps:
1. Load contract from prose-contracts/main (file: hermes-agent-baseline.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/hermes-agent-baseline/
Postconditions to verify:
[
{
"check": "Hermes agent process running",
"verify": "pgrep -f 'hermes' > /dev/null && echo running || echo stopped",
"expect": "running"
},
{
"check": "agent config file exists and valid YAML",
"verify": "test -f /root/.hermes/config.yaml && python3 -c 'import yaml; yaml.safe_load(open(\"/root/.hermes/config.yaml\"))' && echo valid || echo invalid",
"expect": "valid"
},
{
"check": "no uncommitted changes in hermes directory",
"verify": "cd /root/.hermes && git status --porcelain | wc -l",
"expect": "0"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/hermes-agent-baseline/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=hermes-agent-baseline, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## proxmox-monitor
**Category:** monitoring | **Domain:** proxmox | **Owner:** abiba | **Schedule:** */15 * * * *
```
Contract Enforcement: proxmox-monitor
Category: monitoring
Domain: proxmox
Owner: abiba
Schedule: Every 15 minutes
This is a monitoring contract. Execute the monitoring checks defined in the contract. Report any deviations from expected state.
Steps:
1. Load contract from prose-contracts/main (file: proxmox-monitor.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/proxmox-monitor/
Postconditions to verify:
[
{
"check": "all Proxmox nodes reachable",
"verify": "curl -sf http://192.168.68.10:8006/api2/json/status | jq '.status'",
"expect": "healthy"
},
{
"check": "no VMs in crashed state",
"verify": "pvesh get /nodes -output-format=json | jq '.[] | select(.status==\"Crashed\")'",
"expect": "empty"
},
{
"check": "backups running on schedule",
"verify": "pbs-info --check",
"expect": "last_backup < 24h ago"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba, mumuni → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert + trigger_remediation
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + pause + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/proxmox-monitor/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=proxmox-monitor, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## gpu-monitor
**Category:** monitoring | **Domain:** gpu | **Owner:** abiba | **Schedule:** */15 * * * *
```
Contract Enforcement: gpu-monitor
Category: monitoring
Domain: gpu
Owner: abiba
Schedule: Every 15 minutes — polls all GPU subsystems
This is a monitoring contract. Execute the monitoring checks defined in the contract. Report any deviations from expected state.
Steps:
1. Load contract from prose-contracts/main (file: gpu-monitor.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/gpu-monitor/
Postconditions to verify:
[
{
"check": "GPU metrics accessible",
"verify": "curl -sf http://localhost:9100/gpu-data",
"expect": "200 OK, populated data"
},
{
"check": "dashboard serving",
"verify": "curl -sf http://localhost:9100/gpu-fleet.html",
"expect": "200 OK, HTML returned"
},
{
"check": "health endpoint responsive",
"verify": "curl -sf http://localhost:9100/health",
"expect": "200 OK"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba, mumuni → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert + trigger_remediation
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + pause + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/gpu-monitor/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=gpu-monitor, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## infrastructure-monitoring
**Category:** monitoring | **Domain:** infrastructure | **Owner:** abiba | **Schedule:** */30 * * * *
```
Contract Enforcement: infrastructure-monitoring
Category: monitoring
Domain: infrastructure
Owner: abiba
Schedule: Every 30 minutes
This is a monitoring contract. Execute the monitoring checks defined in the contract. Report any deviations from expected state.
Steps:
1. Load contract from prose-contracts/main (file: infrastructure-monitoring.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/infrastructure-monitoring/
Postconditions to verify:
[
{
"check": "Proxmox API reachable",
"verify": "curl -sf http://192.168.68.10:8006/api2/json",
"expect": "200 OK"
},
{
"check": "Zulip API reachable",
"verify": "curl -sf https://chat.sysloggh.net/api/v1/me",
"expect": "200 OK"
},
{
"check": "LiteLLM proxy reachable",
"verify": "curl -sf http://192.168.68.116/litellm/v1/models",
"expect": "200 OK"
},
{
"check": "Gitea API reachable",
"verify": "curl -sf https://git.sysloggh.net/api/v1/version",
"expect": "200 OK"
},
{
"check": "SearXNG reachable",
"verify": "curl -sf http://192.168.68.17:8080",
"expect": "200 OK"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba, mumuni → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert + trigger_remediation
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + pause + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/infrastructure-monitoring/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=infrastructure-monitoring, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## zulip-health
**Category:** monitoring | **Domain:** zulip | **Owner:** abiba | **Schedule:** */15 * * * *
```
Contract Enforcement: zulip-health
Category: monitoring
Domain: zulip
Owner: abiba
Schedule: Every 15 minutes — monitors all Zulip-connected agents
This is a monitoring contract. Execute the monitoring checks defined in the contract. Report any deviations from expected state.
Steps:
1. Load contract from prose-contracts/main (file: zulip-health.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/zulip-health/
Postconditions to verify:
[
{
"check": "bot registration active",
"verify": "curl -sf https://chat.sysloggh.net/api/v1/me | jq '.user_id'",
"expect": "bot_id present"
},
{
"check": "DM delivery working",
"verify": "curl -sf https://chat.sysloggh.net/api/v1/users/me/is-online",
"expect": "online: true"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba, mumuni → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert + trigger_remediation
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + pause + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/zulip-health/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=zulip-health, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## litellm-health
**Category:** monitoring | **Domain:** litellm | **Owner:** abiba | **Schedule:** */10 * * * *
```
Contract Enforcement: litellm-health
Category: monitoring
Domain: litellm
Owner: abiba
Schedule: Every 10 minutes — LiteLLM proxy health
This is a monitoring contract. Execute the monitoring checks defined in the contract. Report any deviations from expected state.
Steps:
1. Load contract from prose-contracts/main (file: litellm-health.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/litellm-health/
Postconditions to verify:
[
{
"check": "LiteLLM proxy reachable",
"verify": "curl -sf http://192.168.68.116/litellm/v1/models",
"expect": "200 OK, models returned"
},
{
"check": "router deprecated, nginx routes work",
"verify": "curl -sf https://litellm.sysloggh.net/v1/models",
"expect": "200 OK (via nginx)"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba, mumuni → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert + trigger_remediation
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + pause + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/litellm-health/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=litellm-health, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## memory-audit-maintenance
**Category:** maintenance | **Domain:** memory | **Owner:** mumuni | **Schedule:** 0 3 * * *
```
Contract Enforcement: memory-audit-maintenance
Category: maintenance
Domain: memory
Owner: mumuni
Schedule: Daily at 3am ET
This is a maintenance contract. Execute the maintenance tasks defined in the contract. Report any issues found.
Steps:
1. Load contract from prose-contracts/main (file: memory-audit-maintenance.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/memory-audit-maintenance/
Postconditions to verify:
[
{
"check": "memory files below 80% capacity",
"verify": "wc -l ~/.hermes/memories/*.md",
"expect": "total lines < threshold"
},
{
"check": "no stale entries",
"verify": "grep -r 'STALE' ~/.hermes/memories/",
"expect": "0 matches"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify mumuni → action: relay_alert
- CRITICAL: notify mumuni, abiba → action: relay_alert
- FATAL: notify mumuni, abiba, kwame → action: relay_alert + human_required
Circuit Breaker:
- Max retries: 3 per 60.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/memory-audit-maintenance/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=memory-audit-maintenance, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
## infrastructure-update
**Category:** maintenance | **Domain:** infrastructure | **Owner:** abiba | **Schedule:** 0 2 * * 0
```
Contract Enforcement: infrastructure-update
Category: maintenance
Domain: infrastructure
Owner: abiba
Schedule: Weekly system updates Sunday at 2am ET
This is a maintenance contract. Execute the maintenance tasks defined in the contract. Report any issues found.
Steps:
1. Load contract from prose-contracts/main (file: infrastructure-update.prose.md)
2. Verify prerequisites (connectivity, tools, deps)
3. Execute contract per SOP
4. Run postconditions from contract registry
5. Generate receipt with status (pass/fail/escalated)
6. If any postcondition fails, escalate per contract escalation tiers
7. Log to ~/.hermes/runs/infrastructure-update/
Postconditions to verify:
[
{
"check": "all services running after update",
"verify": "systemctl list-units --state=running",
"expect": "all critical services"
}
]
Escalation Tiers:
- INFO: notify nobody → action: log_to_receipt
- WARNING: notify abiba → action: relay_alert
- CRITICAL: notify abiba, mumuni → action: relay_alert
- FATAL: notify abiba, mumuni, kwame → action: relay_alert + human_required
Circuit Breaker:
- Max retries: 1 per 120.0min window
- On trip: escalate_to_fatal
Receipt format: JSON with contract, run_id, timestamp, agent, status, actions_taken, postconditions, drift_alerts, evidence_path
Receipt storage: ~/.hermes/runs/infrastructure-update/receipt-{timestamp}.json
Graph node: Create RA-H OS node for receipt with metadata: type=receipt, contract=infrastructure-update, status=<status>
If the contract has no postconditions defined (e.g., reference/pattern contracts), log that it was loaded and skip execution.
IMPORTANT: If the contract file does not exist in prose-contracts/main, report failure and do NOT hallucinate forward.
```
---
*End of review*
-256
View File
@@ -1,256 +0,0 @@
---
kind: pattern
name: delegation-prose-contract
description: >
Manager (Mumuni) operating doctrine for task decomposition, worker
delegation, verification, and delivery. Defines when to delegate, which
worker to use for what, how to handle failures, and the kanban board
protocol. Enforces context-window discipline and separation of concerns.
Runs on Mumuni (CT 118, storepve, .6) via Hermes agent.
version: 1.0.0
---
## Maintains
- Worker roster: 6 profiles (`syslog-code`, `syslog-devops`, `syslog-email`,
`syslog-research`, `syslog-review`, `syslog-writer`)
- Kanban board state at `~/.hermes/kanban/kanban.json`
- Context window budget: ~65K tokens per request (131K total, 60% threshold)
## Topology
**Cluster:** 5 Proxmox nodes (ocupve, acerpve, minipve, amdpve, storepve)
**Manager:** Mumuni (CT 118, storepve, .6) via Hermes agent
**Workers:** 6 profiles, all running on the same agent — no separate hosts needed
This contract is infrastructure-agnostic in terms of which nodes are used.
Workers execute tasks on whatever infrastructure they're given — SSH to .6,
.pm, .9, .12, or .15 depending on the task. The contract defines the
**who** and **when** — not the **where**.
## Why This Matters
Without enforced delegation, the manager consumes the full iteration budget
(60 calls) on single-turn tasks — SSH to 5 nodes, check each VM, read logs —
leaving no capacity for actual coordination. The result: context overflow
(59K tokens in system prompt), iteration exhaustion, and degraded response
quality. This contract exists because I blew through my budget checking
Proxmox node status instead of delegating to `syslog-devops`.
## Context Window Discipline
**The system prompt is ~6.5K tokens (stable: ~4.5K tool schemas + ~2K other guidance).**
**Volatile (MEMORY.md + USER.md): ~300 tokens.**
**Total base: ~6,800 tokens per request.**
The remaining budget is the conversation. Every tool call result adds to it.
If a single call returns >10K tokens (e.g., `grep` on a large file, SSH output
from multiple nodes), the context fills fast. That's why we delegate: workers
process in isolation and return compact results.
## Trigger Conditions
Delegation is **mandatory** when any of these apply:
| Condition | Threshold | Example |
|-----------|-----------|---------|
| Multiple tool calls needed | 2+ calls with intermediate logic | Read file → analyze → write report |
| Large data retrieval | Output >5K tokens | `grep -r "pattern" /path` on large dirs |
| Cross-domain work | Spans 2+ worker specialties | Infra check + email filter |
| Infrastructure changes | Any mutating operation | `qm set`, `systemctl restart`, `git push` |
| Research/analysis | Needs browser or deep reading | Web research, code review, data analysis |
| Code builds or changes | Writing or modifying code | Scripts, configs, patches |
| Sequential dependencies | Worker B needs Worker A's output | Code → Review → Deliver |
**Single tool calls stay at manager level.** Quick `grep`, `ls`, `cat`,
`curl`, `hermes tools list` — these are decision-making tools. The manager
reads them directly.
## Worker Selection Matrix
| Worker | Model | Toolsets | Role | Use When |
|--------|-------|----------|------|----------|
| `syslog-code` | qwen3.6-27B-code | terminal, file, web, memory, skills | Code patches, automation, scripts | Writing/modifying code, creating scripts, debugging, reading/writing files |
| `syslog-devops` | qwen3.6-27B-code | terminal, file, web, memory, skills | Infrastructure, DB, bridge, Proxmox | Server ops, SSH, Docker, Proxmox, DB queries, hardware checks |
| `syslog-email` | ornith-1.0-35b | terminal, file, web, memory, skills | Email automation, mail operations | Sending/receiving email, inbox management, SMTP operations |
| `syslog-research` | ornith-1.0-35b | terminal, file, web, memory, skills, **browser** | Analysis, classification, data processing | Web research, browser tasks, data analysis, classification, reading docs |
| `syslog-review` | ornith-1.0-35b | terminal, file, web, memory, skills | Verification, QA, audit validation | **ALWAYS** verify worker output before delivery — especially for infra changes, code builds, and research findings |
| `syslog-writer` | ornith-1.0-35b | terminal, file, web, memory, skills | Docs, content, branding, reports | Writing docs, reports, proposals, content, markdown formatting |
### Selection Rules
1. **Match specialty first.** A code task → `syslog-code`. An infra task →
`syslog-devops`. Don't put a `syslog-email` worker on a code review.
2. **Research tasks with browser needs → `syslog-research`.** Other workers
don't have the browser toolset.
3. **Verification → `syslog-review`.** Never deliver raw worker output.
4. **Documentation/content → `syslog-writer`.** Let them own the prose.
5. **If unsure, delegate to `syslog-research`** — it has the broadest toolset
(includes browser) and high reasoning effort.
## Delegation Protocol
### Step 1: Decompose
Break the task into lanes. Each lane does ONE thing. Workers are independent —
no lane depends on another's output mid-flight. If lanes depend on each other,
dispatch sequentially.
### Step 2: Dispatch
Fire workers via `delegate_task`:
**Parallel (independent lanes):**
```
delegate_task(
tasks=[
{"goal": "Check all 5 Proxmox nodes for VM status", "context": "SSH to each node via 192.168.68.x, run 'qm list'"},
{"goal": "Check Docker container health on .7/.116/.17", "context": "SSH to each host, check container status"},
]
)
```
**Sequential (dependent lanes):**
Dispatch lane 1 → wait for result → dispatch lane 2.
### Step 3: Verify
**MANDATORY for:**
- Infrastructure changes (any `qm`, `pct`, `systemctl`, `git push`)
- Code builds and modifications
- Research findings (web data, external sources)
- Any output that will reach the user
**Fire `syslog-review` to verify:**
```
delegate_task(
goal="Review the output of the devops worker. Verify the node status
report is accurate, check for inconsistencies, confirm all nodes were
reachable.",
context="Worker was syslog-devops. Output is at /tmp/node-report.md.
Verify against live system."
)
```
**If verification fails:**
1. Send work back to original worker with review feedback
2. Re-verify
3. Max 2 re-verify cycles before escalating to Kwame
### Step 4: Deliver
Only verified results reach Kwame. Format per channel:
- Telegram: Use `telegram-formatting` skill
- Zulip: Use Zulip Markdown (CommonMark)
- Email: Use `syslog-email` skill
## Kanban Board Protocol
**File:** `~/.hermes/kanban/kanban.json`
```json
{
"task_id": "unique-id",
"title": "Task description",
"created": "2026-07-09T01:00:00",
"status": "backlog|in_progress|review|done",
"lanes": [
{
"lane_id": "devops-check",
"worker": "syslog-devops",
"goal": "Check all 5 Proxmox nodes",
"status": "dispatched|completed|failed",
"output_file": "/tmp/node-report.md"
}
]
}
```
**Update the board on every state change.**
## Failure Handling
### Worker Timeouts
- Child timeout: **900 seconds** (15 minutes)
- Worker model `syslog-auto` is slow — it can hit the timeout limit with
22+ API calls
- **If a worker times out:** Re-dispatch with a narrower scope. Break the
task into smaller pieces that fit in the timeout window.
- **Avoid delegating sequential SSH hops** — each SSH connection adds latency
that compounds quickly. Prefer API-based or local approaches when possible.
### Worker Selection Failures
- `syslog-devops` is best for infrastructure tasks (SSH, Proxmox, Docker)
- `syslog-code` is best for code-level work (reading files, writing scripts)
- `syslog-research` has the browser toolset — use for web research
- `syslog-review` is the QA gate — always fire before delivery
- **Never fire more than 3 parallel workers** (max_concurrent_children: 3)
- **Never nest delegation** (max_spawn_depth: 1)
### Context Overflow
- If a task requires >10K tokens of output, delegate the processing
- Workers return compact summaries, not raw data dumps
- Pass file paths and concrete goals — never dump raw data into context
## Anti-patterns
- ❌ Reading large files into your own context before deciding → delegate the read
- ❌ Carrying SSH/grep/output results in your context → delegate the analysis
- ❌ Doing work yourself and then "pretending" to delegate → the user can tell
- ❌ Skipping verification → raw worker output never reaches the user
- ❌ Delegating single tool calls → keep quick reads/writes at manager level
- ❌ Firing more than 3 workers in parallel → hard limit
## Emergency Exception
**In an emergency (server down, service must be restored immediately):**
- Delegate the diagnosis (find the problem)
- Execute the fix yourself (minimize handoff latency)
- Verify the fix after delivery
- Log the exception in the kanban board
The emergency exception exists because the user needs the service back NOW,
not after three worker round-trips. But it's an exception — not the rule.
## What This Contract Doesn't Cover
1. **Worker profile configuration** — covered by `hermes-config-template.prose.md`
2. **SSH key management** — covered by existing SSH/Proxmox contracts
3. **Git workflow** — covered by `AGENTS.md` in the prose-contracts repo
4. **Cron job management** — covered by individual cron contracts
5. **Infra verification** — covered by `verify-before-mutate` protocol
## Verification
Run `scripts/worker-audit.py` to verify all 6 profiles are aligned:
```bash
python3 /root/.hermes/skills/kanban-orchestrator/scripts/worker-audit.py
```
## References
- `kanban-orchestrator` skill: The operational playbook (detailed execution steps)
- `worker-profile-audit.md` (skill reference): Worker configuration audit notes
- `delegation-timeout-patterns.md` (skill reference): Timeout handling patterns
- `verify-before-mutate` protocol: Infrastructure change verification
- `hermes-config-template.prose.md`: Worker profile configuration
## Success Criteria
This contract succeeds when:
1. **No context overflow** — single-turn tasks don't exhaust the iteration budget
2. **Workers do the work** — manager coordinates, doesn't execute
3. **Verification before delivery** — all output passes through `syslog-review`
4. **Kanban board is current** — every task has a lane, every lane has a status
5. **User gets verified results** — raw worker output never reaches Kwame
---
**Last updated:** 2026-07-09
**Author:** Mumuni (with Kwame's input on triggers and exception criteria)
**Status:** Draft — awaiting PR review and merge to prose-contracts main
+12 -12
View File
@@ -7,7 +7,7 @@ description: >
saturation watchdog, Prometheus/Grafana monitoring, and self-healing.
UPDATED 2026-07-15: Stable role-based aliases introduced: strix-moe,
gpu-dense, gpu-light. These never change — only the underlying model does.
Strix Halo: ornith-1.0-35b → unsloth/Qwen3.6-35B-A3B-MTP (UD-Q4_K_M, 22GB).
Strix Halo: strix-moe → unsloth/Qwen3.6-35B-A3B-MTP (UD-Q4_K_M, 22GB).
RTX 5070: gemma-4-12b Q4_K_M → IQ4_NL + MTP draft (122 tok/s, 2x faster).
RTX 5070 context: 131K → 256K. VRAM: 88% (10.8/12.2GB).
Compression timeout: 300s (was 120s). Mumuni context: 128K (was 256K).
@@ -67,9 +67,9 @@ triggers:
│ CT 8 │ │ CT 110 │ │ CT 15 │ │ pi (.24) │
│ RTX 3090 │ │ RTX 5070 │ │ Strix Halo│ │ GPU Monitor │
│ 24GB │ │ 12GB │ │ 64GB UMA │ │ :9100 │
│ 256K ctx │ │ 131K ctx │ │ 256K ctx │ │ Watchdog │
│ qwen3.6 │ │ gemma-4-12b │ │ ornith35B │ │ Prometheus │
│ 27B-code │ │ :8080 │ │ :8080 │ │ exporter │
│ 256K ctx │ │ 256K ctx │ │ 256K ctx │ │ Watchdog │
│ qwen3.6 │ │ gemma-4-12b │ │ qwen3.6 │ │ Prometheus │
│ 27B-code │ │ :8080 │ │ -35B-udq4 │ │ exporter │
│ :8080 │ │ :9400 (exp) │ │ :9400(exp)│ │ :9401 │
│ :9400 │ └─────────────┘ └───────────┘ └──────────────┘
└──────────┘
@@ -94,7 +94,7 @@ but are deprecated for agent configs. Only the stable aliases survive model swap
| Model | GPU | Host | VRAM | Ctx | KV Cache | Parallel | Batch/Ubatch | Status |
|-------|-----|------|------|-----|----------|----------|-------------|--------|
| qwen3.6-27B-code (MTP) | RTX 3090 | .8 (llm-gpu) | 22.2/24.6GB (90%) | **256K** 🚀 | turbo4 | 2 | default | ✅ 63 tok/s |
| gemma-4-12b | RTX 5070 | .110 (ocu-llm) | 10.0/12.2GB (82%) | 131K | q4_0 | 2 | 2048/1024 | ✅ healthy |
| gemma-4-12b | RTX 5070 | .110 (ocu-llm) | 10.0/12.2GB (82%) | 256K | q4_0 | 2 | 2048/1024 | ✅ healthy |
| qwen3.6-35B-udq4 | Strix Halo Vulkan | .15 (amdpve) | ~9GB/64GB | 256K | q8_0 | 2 | 2048/512 | ✅ healthy |
## Routing Configuration (LiteLLM — July 2026)
@@ -103,9 +103,9 @@ but are deprecated for agent configs. Only the stable aliases survive model swap
| Model | GPU | Weight | RPM Cap | Timeout |
|-------|-----|--------|---------|---------|
| qwen3.6-27B-code | RTX 3090 (.8:8080) | **0.55** | 500 | 90s |
| qwen3.6-27B-code | RTX 3090 (.8:8080) | **0.55** | 500 | **300s** |
| qwen3.6-35B-udq4 | Strix Halo (.15:8080) | **0.30** | 60 | **300s** |
| gemma-4-12b | RTX 5070 (.110:8080) | **0.15** | 200 | **300s** |
| gemma-4-12b | RTX 5070 (.110:8080) | **0.15** | 200 | **120s** |
Note: All syslog-auto entries route directly to GPUs with `api_key: not-needed`. The router (port 9000) is NOT in the inference path.
@@ -186,7 +186,7 @@ Show full fleet status: GPUs, models, VRAM, context windows, parallel slots, act
3. Check LiteLLM: `curl http://192.168.68.116/health` (expect "I'm alive!")
4. Check LiteLLM models: `curl -H "Authorization: Bearer $MASTER_KEY" http://192.168.68.116/v1/models`
5. Check LiteLLM timeouts: `grep -n 'timeout:' /opt/inference-harness/litellm_config.yaml`
- gemma-4-12b: 120s, qwen3.6-27B: 90s, ornith-1.0-35b: 120s
- gemma-4-12b: 120s, qwen3.6-27B-code: 300s, qwen3.6-35B-udq4/strix-moe: 300s (strix-moe does NOT exist — legacy name, do not use)
- global request_timeout: 300s, nginx proxy_read_timeout: 600s
6. Check AMD metrics: `curl http://192.168.68.15:9400/metrics` (Radeon 8060S, util%, VRAM, temp, power)
7. Check port conflicts: verify only one llama-server on :8080 per host
@@ -247,7 +247,7 @@ If no SSH access, send Zulip DM via abiba-bot with vault update instructions.
- **RTX 3090 runs `--parallel 2`** with MTP draft (spec-type draft-mtp, spec-draft-n-max 2).
- **RTX 3090 config**: `-c 262144 -ctk turbo4 -ctv turbo4 --parallel 2 --flash-attn on --cont-batching --spec-type draft-mtp`. Context corrected to 256K (2026-07-15). VRAM: 90%. Service: `/home/llmuser/llama-wrapper.sh`.
- **RTX 5070 config (2026-07-15)**: Switched to IQ4_NL + MTP draft (Q8_0) at 256K context. Gen speed: 122 tok/s (was 70). VRAM: 10.8/12.2GB (88%). No draft model pre-upgrade due to VRAM constraints. Service: `/home/llmuser/llama-wrapper.sh`. Config: `--model gemma-4-12b-it-IQ4_NL.gguf --spec-draft-model gemma-4-12b-it-Q8_0-MTP.gguf --spec-type draft-mtp --spec-draft-n-max 4 --ctx-size 262144`.
- **LiteLLM timeout tuning (2026-07-08)**: gemma-4-12b 25→120s, qwen3.6-27B-code 40→90s, syslog-auto (qwen route) 40→90s. Nginx proxy_read_timeout: 600s. Global request_timeout: 300s. Config at `/opt/inference-harness/litellm_config.yaml`.
- **LiteLLM timeout tuning (verified 2026-07-16 against `/opt/inference-harness/litellm_config.yaml` on CT 116)**: gemma-4-12b 120s, qwen3.6-27B-code 300s, qwen3.6-35B-udq4 300s, strix-moe 300s, syslog-auto routes all 300s. Nginx proxy_read_timeout: 600s. Global request_timeout: 300s.
- **Strix Halo GPU**: Vulkan is the working backend (ROCm/HIP path abandoned — HSA runtime blocked on Debian 13). Build at `/root/llama.cpp/build-vk/`, commit `4fc4ec5` (2026-07-01), ggml 0.15.3 shared-lib arch. Mesa RADV 25.0.7, KHR_coopmat fast path active. ~70 tok/s gen, 532 tok/s prompt. Service: `strix-server.service` on port 8080 (was `ornith-server.service`), model changed to `unsloth/Qwen3.6-35B-A3B-MTP-GGUF` (UD-Q4_K_M), alias `qwen3.6-35B-udq4`, 256K context, flash-attn + q8 KV. MTP support enabled for 1.4-2.2x faster inference.
- **Port conflict detection (2026-07-05)**: All 3 GPU wrappers now detect ghost processes squatting port 8080 before starting. `.8` and `.110` use inline pre-start check in `llama-wrapper.sh`; `.15` uses `/usr/local/bin/port-cleanup.sh` ExecStartPre. Replaces the blanket `pkill -9 -x llama-server` on .15 which would kill ALL llama-server instances regardless of port. Ghost detection was the root cause of .8 crash-looping for 27+ restarts (stale pid 25836 squatting 8080 after OOM kill).
- **Strix Halo thermal safeguard (2026-07-02)**: `strix-server.service` has `-n 8192` (hard generation cap per request). Without it, `--predict` defaults to -1 (infinity) — a runaway request from .123 (Mumuni) decoded 39,868 tokens over 24 min, pushing Tctl to 98°C (crit 89.8°C) and throttling 70→29 t/s. The cap bounds worst-case generation to ~5 min. Do NOT remove `-n` without a replacement ceiling. Sustained load hits ~84°C even at 92s; the APU is fanless/low-flow. Clients MUST also set `max_tokens`.
@@ -262,7 +262,7 @@ If no SSH access, send Zulip DM via abiba-bot with vault update instructions.
| GPU | Model | Gen tok/s | Prompt tok/s | Baseline | Context |
|-----|-------|-----------|--------------|----------|---------|
| RTX 3090 (.8) | qwen3.6-27B-code (MTP) | **63** | — | — | 131K |
| RTX 3090 (.8) | qwen3.6-27B-code (MTP) | **63** | — | — | **256K** |
| RTX 5070 (.110) | gemma-4-12b (IQ4_NL+MTP) | **191** | — | — | **256K** |
| Strix Halo (.15) | qwen3.6-35B-udq4 | **71** | — | — | **256K** |
@@ -306,7 +306,7 @@ Mumuni (CT114, 192.168.68.123) is the primary business assistant. This profile i
| `aux.vision.model` | `gpu-light` | Vision tasks (RTX 5070) |
| `aux.web_extract.model` | `gpu-light` | Web extraction |
| `delegation.model` | `gpu-dense` | Sub-agent reasoning (RTX 3090) |
| `context.max_context_window` | 131072 (128K) | Kept at 128K to avoid compression timeout |
| `context.max_context_window` | 262144 (256K) | Fixed 2026-07-16 (was 131072 — caused premature compression, WAL #1300) |
| `compression.threshold` | 0.65 | Triggers at ~85K |
| `compression.target_ratio` | 0.3 | Compresses to ~38K |
| `compression.protect_last_n` | 40 | Preserves last 40 messages |
@@ -314,7 +314,7 @@ Mumuni (CT114, 192.168.68.123) is the primary business assistant. This profile i
| `personalities` | `creative` | Creative assistant personality |
| Platforms | cli, discord, homeassistant, signal, telegram, zulip | All Hermes platforms |
| Main model timeout | 300s | LiteLLM global timeout |
| Compression model timeout | 300s | ornith timeout increased from 120s |
| Compression model timeout | 300s | strix-moe timeout increased from 120s |
### Agent Update Status (2026-07-15)
+1 -1
View File
@@ -120,7 +120,7 @@ depends_on:
- **Detect**: Benchmark tok/s vs baseline for each GPU at current context
- RTX 3090 (256K ctx, qwen3.6-27B-code): target 75+ tok/s — currently at baseline
- RTX 5070 (131K ctx, gemma-4-12b): target 76+ tok/s — optimal for vision/web role
- Strix Halo (256K ctx, ornith-1.0-35b): target 70+ tok/s — currently above baseline
- Strix Halo (256K ctx, strix-moe / qwen3.6-35B-udq4): target 70+ tok/s — currently above baseline
- **Fix**:
- If tok/s > baseline → context has headroom, consider increasing
- If tok/s < 90% baseline → reduce context by 25% and retest
+8 -8
View File
@@ -5,7 +5,7 @@ version: 1.0.0
description: >
Canonical known-good baseline for all Syslog Hermes agents. Captures the exact
configuration state, keys, workarounds, and audit procedure. When an agent's
configuration goes sideways, restore from this baseline. Last verified 2026-07-08. GPU context reduced to 128K on .8/.110, parallel 2 fleet-wide.
configuration goes sideways, restore from this baseline. Last verified 2026-07-16. All GPUs 256K context (RTX 3090 .8, RTX 5070 .110, Strix Halo .15). Parallel 1 fleet-wide (Strix Halo handles compression solo).
author: Abiba (pi agent)
---
@@ -26,11 +26,11 @@ done
|-------|-----|------|-----|---------------|------------|----------|
| Tanko | 112 | amdpve | .122 | `tanko` | Infisical vault | Hermes |
| Mumuni | 114 | minipve | .123 | `mumuni` | Infisical vault | Hermes |
| Koby | 111 | amdpve | srv1079750 | `koby` | Infisical vault | **Hermes** |
| Koonimo | 113 | amdpve | ? | `koonimo` | Infisical vault | Hermes |
| Shumba | — | 192.168.68.119 | N/A | N/A (DeepSeek) | Hermes |
| Koby | 129 | amdpve | srv1079750 | `koby` | Infisical vault | **Hermes** |
| Koonimo | 114 | amdpve | ? | `koonimo` | Infisical vault | Hermes |
| Shumba | — | 192.168.68.119 | N/A | N/A (DeepSeek) | Hermes (RETIRED — CT119 now Infisical vault) |
> **Note**: CT hostnames (tdunna→CT111, baggy→CT113) differ from agent identities (koby, koonimo).
> **Note**: CT hostnames (tdunna→CT129, baggy→CT114) differ from agent identities (koby, koonimo).
Access: `pct-run <CT_ID> <command>` — no IPs needed. GPU hosts (.8, .110, .15) use SSH.
Keys are stored in Infisical vault (project=agents, env=production) and injected at
@@ -169,9 +169,9 @@ pct-run <CT> grep -A8 "vision:" /root/.hermes/config.yaml | grep api_key
# Must show both api_key: sk-... and api_key_env: LITELLM_API_KEY
```
### For Koby (CT 111 / tdunna)
### For Koby (CT 129 / tdunna)
Koby runs Hermes on CT 111 (tdunna). Config files at `/root/.hermes/config.yaml`.
Koby runs Hermes on CT 129 (tdunna). Config files at `/root/.hermes/config.yaml`.
Same Hermes pattern as Tanko/Mumuni/Koonimo — see config sections above.
**LiteLLM key**: alias `koby` in LiteLLM DB, injected via `infisical run --` wrapper.
@@ -192,7 +192,7 @@ Key is injected via `infisical run --` wrapper at PM2 startup:
"apiKey": "${LITELLM_API_KEY}",
"models": [
{ "id": "syslog-auto" },
{ "id": "ornith-1.0-35b" },
{ "id": "strix-moe" },
{ "id": "qwen3.6-27B-code" },
{ "id": "gemma-4-12b" }
]
+96 -28
View File
@@ -5,10 +5,12 @@ description: >
Standard Hermes configuration template for Syslog Solution LLC agents.
Enforces shared infrastructure setup (Firecrawl, SearXNG, local models,
RA-H OS MCP) while keeping agent-specific API keys and model choices.
UPDATED 2026-07-12: GPU workload redistributed. Compression → Strix Halo (ornith-1.0-35b).
RTX 3090 context verified at 256K (was incorrectly documented as 128K).
RTX 5070 stays at 131K for vision/web. Infisical .env fallback required (Rule 3).
Parallel counts corrected (RTX 3090=1, RTX 5070=2, Strix=2).
UPDATED 2026-07-16: Compression model is the stable alias `strix-moe` (NOT `ornith-1.0-35b`,
which LiteLLM does not serve). All 3 GPUs verified 256K (RTX 5070 bumped 131K→256K on Jul 15).
Added Rule 12 (Context-Issue Diagnostic) + Rule 13 (.env fallback enforcement) from the
2026-07-16 Mumuni root-cause investigation (WAL #1300).
UPDATED 2026-07-12: GPU workload redistributed. Compression → Strix Halo. RTX 3090 context
verified at 256K. Infisical .env fallback required (Rule 3/13).
---
## Maintains
@@ -31,7 +33,7 @@ Sub-agent profiles inherit auth from the main config — no separate keys needed
| Agent | Key Alias | Host | SSH | Sub-Agents |
|-------|-----------|------|-----|-----------|
| Tanko | `tanko-*` | 192.168.68.122 | jerome@.122 | — |
| Mumuni | `mumuni-jul2026` | 192.168.68.123 | root@.123 | 6 profiles ✱ |
| Mumuni | `mumuni` | 192.168.68.123 | root@.123 | 6 profiles ✱ |
| Abiba | `abiba-pi` | 192.168.68.24 | local | — |
| Koby | `koby` | CT 111 (tdunna) | Zulip | — |
| Koonimo | `koonimo` | CT 113 (baggy) | Zulip | — |
@@ -94,7 +96,7 @@ work immediately after restart.
```yaml
# ─── Model Selection ───
model:
default: <agent_model> # e.g., ornith-1.0-35b, qwen3.6-27B-code
default: <agent_model> # e.g., strix-moe, qwen3.6-27B-code, syslog-auto
provider: harness
base_url: http://192.168.68.116/v1
api_key_env: LITELLM_API_KEY # Injected via infisical run -- wrapper
@@ -129,10 +131,9 @@ mcp_servers:
# ─── Compression ───
compression:
enabled: true
model: ornith-1.0-35b # ⚠️ Must match auxiliary.compression.model
model: strix-moe # ⚠️ Must match auxiliary.compression.model. Stable alias (gpu-fleet § Stable Role-Based Aliases). NOT ornith-1.0-35b (LiteLLM does not serve that name).
provider: harness
max_context_window: 262144 # For Strix Halo compression (256K ctx).
# Set 131072 if using gemma directly.
max_context_window: 262144 # MUST match actual GPU capacity. All 3 GPUs are 256K (Jul 15).
threshold: 0.65 # Fires at ~170K for 262K window, ~85K for 128K
target_ratio: 0.30
protect_last_n: 40
@@ -142,37 +143,48 @@ compression:
# ─── Auxiliary Tasks (CONSISTENCY RULE) ───
# All auxiliary services MUST use identical model, base_url, and api_key_env:
# model: gemma-4-12b
# model: gpu-light # stable alias (NOT raw "gemma-4-12b")
# base_url: http://192.168.68.116/v1
# api_key_env: LITELLM_API_KEY
# Do NOT use syslog-auto for auxiliary tasks — it routes to the primary GPU.
# gemma-4-12b is a lightweight 12B model on the RTX 5070, freeing the Strix Halo
# for agent reasoning.
# gpu-light = RTX 5070 (12B), freeing the Strix Halo for agent reasoning.
# Heavy aux (delegation, x_search) use gpu-dense (RTX 3090) instead.
# NEVER use raw model names (gemma-4-12b, qwen3.6-27B-code, qwen3.6-35B-udq4)
# in agent configs — use the stable aliases so model swaps don't break agents.
auxiliary:
vision:
provider: harness
model: gemma-4-12b
model: gpu-light # stable alias for RTX 5070 (was raw gemma-4-12b)
base_url: http://192.168.68.116/v1
api_key_env: LITELLM_API_KEY
timeout: 60
download_timeout: 30
web_extract:
provider: harness
model: gemma-4-12b
model: gpu-light # stable alias for RTX 5070
base_url: http://192.168.68.116/v1
api_key_env: LITELLM_API_KEY
timeout: 30
compression:
provider: harness
model: ornith-1.0-35b
base_url: http://192.168.68.116/v1
model: strix-moe # MUST match compression.model above. Stable alias for Strix Halo.
base_url: http://192.168.68.116/v1 # Rule 5: /v1 NOT /litellm/v1
api_key_env: LITELLM_API_KEY
timeout: 60
timeout: 300 # gpu-fleet: 300s for large-history summarization (was 60)
# ─── Delegation / Heavy Aux (use gpu-dense = RTX 3090) ───
# delegation.model and x_search.model use gpu-dense (NOT raw qwen3.6-27B-code).
delegation:
model: gpu-dense # stable alias for RTX 3090 (was raw qwen3.6-27B-code)
provider: harness
base_url: http://192.168.68.116/v1
api_key_env: LITELLM_API_KEY
# ─── Custom Provider ───
custom_providers:
- name: harness
model: <agent_model>
model: syslog-auto # weighted pool (default)
base_url: http://192.168.68.116/v1
api_key_env: LITELLM_API_KEY
api_mode: chat_completions
@@ -236,27 +248,29 @@ The following MUST be identical across ALL profiles:
- Apply to BOTH main config AND all sub-agent profiles
- For agents needing longer outputs: raise to 8192, but never omit
### Rule 7: Auxiliary Model Consistency (UPDATED July 2026)
### Rule 7: Auxiliary Model Consistency (UPDATED 2026-07-16)
- Vision and web_extract use `gemma-4-12b` (RTX 5070 — 12GB, vision-optimized)
- Compression uses `ornith-1.0-35b` (Strix Halo — 64GB, 256K ctx, compression-optimized)
- Compression uses `strix-moe` (stable alias for Strix Halo — 64GB, 256K ctx, compression-optimized)
- **`strix-moe` is the only valid compression model name** — LiteLLM does NOT serve `ornith-1.0-35b`
(it serves `strix-moe`, `qwen3.6-35B-udq4`, `gpu-dense`, `gpu-light`, `syslog-auto`, `gemma-4-12b`, `qwen3.6-27B-code`). Old configs with `ornith-1.0-35b` cause 403/model-not-found on compression calls.
- All auxiliary services MUST use identical routing:
- `base_url: http://192.168.68.116/v1`
- `base_url: http://192.168.68.116/v1` (Rule 5: `/v1`, NOT `/litellm/v1`)
- `api_key_env: LITELLM_API_KEY`
- **Do NOT use `syslog-auto`** for auxiliary tasks — it routes unpredictably
- **Compression moved to Strix Halo (July 2026)**: The ornith-1.0-35b model on Strix Halo
(64GB UMA, 256K context, 72.4 tok/s) is the designated compression GPU. This frees the
- **Compression on Strix Halo**: The strix-moe alias routes to Strix Halo
(64GB UMA, 256K context) — the designated compression GPU. This frees the
RTX 5070 for vision and web search, and the RTX 3090 for heavy reasoning.
- The `compression:` block's `model` MUST match `auxiliary: compression: model`
- The `compression: max_context_window: 262144` MUST match Strix Halo's actual capacity
### Rule 8: GPU Workload Distribution (July 2026)
### Rule 8: GPU Workload Distribution (UPDATED 2026-07-16)
- **RTX 3090 (24GB, 256K ctx, qwen3.6-27B-code)**: Heavy reasoning, code gen, long conversations
- **RTX 5070 (12GB, 131K ctx, gemma-4-12b)**: Vision, web search, quick tasks, web_extract
- **Strix Halo (64GB, 256K ctx, ornith-1.0-35b)**: Context compression, summarization, long docs
- **RTX 5070 (12GB, 256K ctx, gemma-4-12b)**: Vision, web search, quick tasks, web_extract (bumped 131K→256K Jul 15; IQ4_NL+MTP, 88% VRAM)
- **Strix Halo (64GB, 256K ctx, strix-moe)**: Context compression, summarization, long docs
- Agent profiles MUST route auxiliary tasks to the correct GPU:
- `auxiliary.vision.model: gemma-4-12b` (RTX 5070)
- `auxiliary.web_extract.model: gemma-4-12b` (RTX 5070)
- `auxiliary.compression.model: ornith-1.0-35b` (Strix Halo)
- `auxiliary.compression.model: strix-moe` (Strix Halo)
- Default model (`model.default`) and custom_provider remain `syslog-auto` for auto-routing
- For 262K context window: `threshold: 0.65` (fires at ~170K tokens)
- Do NOT use `threshold: 0.25` — this fires at 65K, causing premature context loss
@@ -274,7 +288,7 @@ The following MUST be identical across ALL profiles:
### Rule 10: Default Model Must Be `syslog-auto` (All Agents)
- **Hermes agents**: `model.default: syslog-auto`, `custom_providers[0].model: syslog-auto`
- **pi agents**: `defaultModel: syslog-auto` in `settings.json`, first model in `models.json`
- `syslog-auto` is the LiteLLM routing model — it load-balances between ornith-1.0-35b
- `syslog-auto` is the LiteLLM routing model — it load-balances between strix-moe
and qwen3.6-27B-code, with gemma-4-12b as fallback. Using it protects against:
- Model name typos that cause 403 errors and silent worker failures
- Single GPU downtime (routing falls back automatically)
@@ -293,6 +307,60 @@ The following MUST be identical across ALL profiles:
- A non-existent model ID causes 403 errors that silently break the pi RPC worker
(no `agent_end` emitted, worker stays "busy", Zulip messages pile up unprocessed)
### Rule 12: Context-Issue Diagnostic Checklist (ADDED 2026-07-16, WAL #1300)
When an agent shows "context issues" (premature compression, 401s, 504s, DeepSeek fallback),
verify ALL FOUR of these against the live config. They are the only root causes found in production:
1. **max_context_window correct?** — BOTH `compression.max_context_window` AND `context.max_context_window`
MUST be `262144` (all GPUs are 256K). A value of `131072` causes premature compression at
~83K instead of ~170K. Check: `grep -n max_context_window ~/.hermes/config.yaml`
2. **base_url uses /v1 NOT /litellm/v1?** — `custom_providers[0].base_url`, `delegation.base_url`,
and ALL `auxiliary.*.base_url` MUST be `http://192.168.68.116/v1` (Rule 5). nginx `/litellm/`
has a 60s default timeout → 504 on any inference >60s; `/v1/` has 600s.
Check: `grep -n 'litellm/v1' ~/.hermes/config.yaml` (must return NOTHING)
3. **LITELLM_API_KEY valid?** — The key must be a real LiteLLM key (`sk-` + 64 hex, 67 chars).
Malformed values (e.g. `sk-_SWAl_Vu_…`, 47 chars) return 401 → DeepSeek fallback.
Verify: `curl -s -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $LITELLM_API_KEY" http://192.168.68.116/v1/models` (must be 200)
4. **custom_providers aligned?** — `model: syslog-auto` (Rule 10), `api_mode: chat_completions`
(NOT `responses`). A wrong api_mode causes silent request failures.
One-line agent health check (run on the agent host):
```bash
PID=$(pgrep -f "python -m hermes_cli.main gateway run" | head -1)
cat /proc/$PID/environ | tr '\0' '\n' | grep ^LITELLM_API_KEY= | sed 's/=.*/<set>/'
curl -s -o /dev/null -w 'key_health: %{http_code}\n' -H "Authorization: Bearer $(cat /proc/$PID/environ | tr '\0' '\n' | grep ^LITELLM_API_KEY= | cut -d= -f2)" http://192.168.68.116/v1/models
```
### Rule 13: API Key Injection — Two Patterns (UPDATED 2026-07-16, WAL #1300)
Agents inject `LITELLM_API_KEY` via ONE of two mechanisms. Both are valid; the contract
requirement is that the key is a **valid LiteLLM virtual key** (HTTP 200 on /v1/models).
**Pattern A — systemd drop-in (Koby, Koonimo, and any agent without infisical wrapper):**
A systemd drop-in `/etc/systemd/system/hermes-gateway.service.d/litellm-key.conf` sets the key:
```ini
[Service]
Environment="LITELLM_API_KEY=sk-<VALID_KEY>"
```
The service unit `hermes-gateway.service` runs `python -m hermes_cli.main gateway run --replace`
directly (no infisical). Apply with `systemctl daemon-reload && systemctl restart hermes-gateway`.
- Koonimo (CT113/.114): service = `hermes-gateway.service`, drop-in has the key.
- Koby (CT111/.129): service = `hermes-gateway.service` (created 2026-07-16), ExecStart uses `--replace`
to win the lock against stray `hermes gateway restart` invocations. Key also in `/etc/environment`.
**Pattern B — infisical-gateway.sh wrapper (Mumuni):**
The wrapper sources `~/.hermes/.env` then exports `LITELLM_API_KEY="$<AGENT>_LITELLM_API_KEY"`.
See litellm-api-keys.prose.md § Machine Identity for Vault Writes for vault sync.
**Verification (all agents):**
```bash
GP=$(pgrep -f "python -m hermes_cli.main gateway run" | head -1)
K=$(cat /proc/$GP/environ | tr '\0' '\n' | grep '^LITELLM_API_KEY=' | cut -d= -f2)
curl -s -o /dev/null -w '%{http_code}' -H "Authorization: Bearer $K" http://192.168.68.116/v1/models # must be 200
```
- `/etc/environment` is NO LONGER the canonical key source (stale values there caused 401s).
- Do NOT leave a hardcoded stale key in `/etc/environment` — it shadows the drop-in/wrapper.
## Execution
1. **Check current config** — Read the target agent's config.yaml
+5
View File
@@ -72,6 +72,11 @@ External providers are **explicitly exempt** and may use hardcoded keys:
## Standard Pattern
> **Canonical vault process (2026-07-16):** see `litellm-api-keys` § Production Vault Access Process.
> All agents MUST use the `infisical-gateway.sh` wrapper (live vault injection). Hardcoded systemd
> drop-ins / config.yaml keys are DEPRECATED — they rot on rotation (root cause of the 2026-07-16 401 storm).
> 4/5 agents migrated; tanko (user jerome) pending.
```yaml
# ✅ CORRECT — all harness/litellm providers (authenticated path, NO /responses suffix)
model:
+177 -3
View File
@@ -14,9 +14,15 @@ description: >
expire/404. The .env fallback prevents agents from running without keys.
Tanko incident: token 404 → gateway had no LITELLM_API_KEY for hours.
UPDATED 2026-07-16: Vault is SYNCED (session-13 keys written to vault via abiba service
token, all validate 200). Koby/Koonimo migrated from hardcoded drop-ins to the
infisical-gateway.sh wrapper (live vault injection). 4/5 agents now vault-backed.
Canonical process: see § Production Vault Access Process. Tanko (user jerome) pending.
Abiba's key is now a proper agent key (NOT the master key — stale note removed).
Current key inventory and agent list: see gpu-fleet.prose.md § Agent Keys.
Source of truth for LiteLLM config: /opt/inference-harness/litellm_config.yaml
on CT 116. Last verified: 2026-07-12.
on CT 116. Last verified: 2026-07-16.
---
## Parameters
@@ -51,8 +57,8 @@ description: >
- Generate new key with key_alias: "{agent_name}" (e.g., "tanko" — bare name, no date)
- Set metadata: { "agent": "{agent_name}", "purpose": "agent-inference" }
- Duration is null (permanent) — inherited from litellm default_key_generate_params
- Set models: ["syslog-auto", "qwen3.6-27B-code", "gemma-4-12b", "ornith-1.0-35b"]
- Note: qwen3.6-35B-A3B removed from fleet (was never deployed on any GPU)
- Set models: ["syslog-auto", "qwen3.6-27B-code", "gemma-4-12b", "strix-moe", "gpu-dense", "gpu-light", "qwen3.6-35B-udq4"]
- Note: `ornith-1.0-35b` is NOT a valid LiteLLM model name (use `strix-moe`, the stable alias). qwen3.6-35B-A3B removed from fleet (was never deployed).
- Return the new key
5. **If action == "rotate"**:
- Generate new key with same alias (LiteLLM replaces the old key)
@@ -67,3 +73,171 @@ description: >
- Test the key against LiteLLM /v1/models
- Confirm key alias matches agent_name in LiteLLM key list
- Verify agent gateway uses vault wrapper: `cat /proc/<pid>/cmdline` shows `infisical run`
## Production Vault Access Process (canonical, 2026-07-16)
The non-fail approach to agentic vault access. Deployed on 4/5 agents (tanko pending —
runs as user `jerome`, not systemd root, needs user-scope adaptation).
### The canonical pattern
1. **infisical CLI** installed on the host (`/usr/local/bin/infisical` or `/usr/bin/infisical`).
2. **Service token** (Infisical Machine Identity, `st.…`) stored root-only at `/root/.infisical-token` (`chmod 600`).
- Interim: the shared `abiba` service token (`st.8e848433…`) has READ+WRITE on the `agents` project.
- Proper: one machine identity per agent (create in Infisical UI → Project Settings → Machine Identities).
3. **`infisical-gateway.sh` wrapper** at `/root/.hermes/infisical-gateway.sh` (`chmod 700`):
```bash
#!/bin/bash
export INFISICAL_API_URL="https://vault.sysloggh.net"
TOKEN=$(cat /root/.infisical-token)
LOG=/root/.hermes/logs/gateway.log; mkdir -p /root/.hermes/logs
while true; do
infisical run --token="$TOKEN" --projectId=322fceab-39da-4854-a55a-568e76c0f13f \
--env=prod --domain=https://vault.sysloggh.net -- bash -c '
. /root/.hermes/.env 2>/dev/null # [FALLBACK Rule 3] safety net only
export LITELLM_API_KEY="$<AGENT>_LITELLM_API_KEY"
exec <HERMES_VENV>/bin/python -m hermes_cli.main gateway run
' >> $LOG 2>&1
sleep 5 # restart on exit
done
```
4. **Agent key in vault** as `<AGENT>_LITELLM_API_KEY` (e.g. `KOBY_LITELLM_API_KEY`). Vault = source of truth.
5. **`.env` fallback** at `/root/.hermes/.env` (`chmod 600`) with the same key — safety net ONLY for vault outage (Rule 3/13). Must be kept in sync on rotation.
6. **systemd service** `hermes-gateway.service` with `ExecStart=/root/.hermes/infisical-gateway.sh`. NO `litellm-key.conf` drop-in (those hardcode keys and rot).
7. **NEVER hardcode** LiteLLM keys in systemd drop-ins, config.yaml, or /etc/environment. The wrapper injects live from vault.
### Why this is non-fail
- **No rot**: keys pulled live from vault at every gateway start. Rotation = one `infisical secrets set` + `systemctl restart`. No per-host file edits.
- **Survives vault outage**: the `.env` fallback (Rule 3) keeps the gateway running if Infisical is unreachable.
- **Survives gateway crash**: the wrapper's `while true` + systemd `Restart=on-failure` revive the gateway.
- **Auditable**: `cat /proc/$(pgrep hermes_cli)/environ` shows the live key; `infisical secrets` shows the vault source.
### Migration status (2026-07-16)
| Agent | Host | Pattern | Vault key | Status |
|-------|------|---------|-----------|--------|
| abiba | .24 | `infisical run` (pi agent wrapper, service token) | ABIBA_LITELLM_API_KEY | ✅ vault-backed |
| mumuni | .123 | infisical-gateway.sh + user-login machine identity | MUMUNI_LITELLM_API_KEY | ✅ vault-backed |
| koby | .129 | infisical-gateway.sh + service token (migrated 2026-07-16) | KOBY_LITELLM_API_KEY | ✅ vault-backed, Zulip (tanko-bot@) + Telegram |
| koonimo | .114 | infisical-gateway.sh + service token (migrated 2026-07-16) | KOONIMO_LITELLM_API_KEY | ✅ vault-backed |
> **Baggy = Koonimo (CT 113).** Deleted `BAGGY_LITELLM_API_KEY` from vault 2026-07-16. Only `KOONIMO_LITELLM_API_KEY` exists — one secret per agent.
<<<<<<< HEAD
| tanko | .122 | infisical-gateway.sh + service token (migrated 2026-07-16) | TANKO_LITELLM_API_KEY | ✅ vault-backed |
=======
| tanko | .122 | **hardcoded in config.yaml** (runs as user jerome, not systemd) | TANKO_LITELLM_API_KEY | ⚠️ TODO: migrate to user-scope wrapper |
>>>>>>> origin/master
### Tanko migration (pending)
Tanko runs the gateway as user `jerome` (not root/systemd), with the key hardcoded in
`/home/jerome/.hermes/config.yaml` (`api_key: sk-CggiHWlamQy…`, valid but not vault-sourced).
Migration: create a user-scope systemd service (`~/.config/systemd/user/hermes-gateway.service`)
with `infisical-gateway.sh` wrapper in jerome's home, token at `~/.infisical-token`, lingering
enabled (`loginctl enable-linger jerome`) so the user service runs without a login session.
### Koby migration lessons (2026-07-16)
Migrated Koby from hardcoded systemd drop-in → `infisical-gateway.sh` wrapper.
**Two mistakes I made that broke the agent:**
1. **Overwrote `/root/.hermes/.env`** without backing it up. The Zulip API key only existed
in the running process memory — the old .env was minimal (just LiteLLM key). Zulip creds were
inherited from the pre-migration gateway env, not stored in any file. Lost on restart.
2. **Only injected `LITELLM_API_KEY`** in the wrapper — forgot Zulip + Telegram credentials.
Agents need ALL their platform env vars. Missing vars cause silent adapter failures.
**How Koby actually connects (2026-07-16):**
- Zulip: shares **Tanko's bot** (`tanko-bot@chat.sysloggh.net`, `TANKO_ZULIP_API_KEY=5PeD6f3zo…`).
Koby doesn't have its own Zulip bot (koby-bot@ doesn't exist in the swarm config).
- Telegram: token `828640…` recovered from `.env.bak-20260603` (18KB backup from June 2026).
Allowed users: 6679773481. Home channel: 6679773481.
- Both platforms now connect through the wrapper's env injection.
**Golden rule for gateway restarts:** always `cat /proc/<pid>/environ` before killing the old
process — captures the live env set. Especially important when migrating gateways between
injection mechanisms.
### Key rotation procedure (one vault operation with this standard)
1. Generate new key: `POST /key/generate` (master key, admin).
2. Update vault: `infisical secrets set <AGENT>_LITELLM_API_KEY=sk-NEW --token=$TOKEN --projectId=322fceab… --env=prod --domain=https://vault.sysloggh.net`.
3. Update `.env` fallback: `echo '<AGENT>_LITELLM_API_KEY=sk-NEW' > /root/.hermes/.env && chmod 600 /root/.hermes/.env`.
4. Restart: `systemctl restart hermes-gateway`. The wrapper pulls the new key live.
5. Verify: `curl -H "Authorization: Bearer sk-NEW" http://192.168.68.116/v1/models` → 200.
## Machine Identity for Vault Writes (ADDED 2026-07-16, WAL #1300)
**Problem:** The infisical CLI on agent hosts is logged in as a user session (jerome@sysloggh.com).
In CLI v0.38.0, `infisical secrets set` / `infisical export` fail with "project id missing" / "workspace
key 404" — a known bug where user-session auth works for `run` but NOT for `secrets set`. The apt
repo only ships 0.38.0, so `apt upgrade` does not help.
**Proper fix — Machine Identity (Infisical automation best practice):**
Create a machine identity with READ+WRITE scope on the `agents` project (project_id=
`322fceab-39da-4854-a55a-568e76c0f13f`, env `prod`). Store client_id + client_secret securely.
Then vault writes work from any host:
```bash
# Get a machine-identity access token
TOKEN=$(curl -fsSL -X POST https://vault.sysloggh.net/api/v1/auth/universal-auth/login \
-H 'Content-Type: application/json' \
-d '{"clientId":"<CLIENT_ID>","clientSecret":"<CLIENT_SECRET>"}' | jq -r .accessToken)
# Write a secret via REST API v3
curl -fsSL -X PATCH https://vault.sysloggh.net/api/v3/secrets/MUMUNI_LITELLM_API_KEY \
-H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
-d '{"environment":"prod","secretValue":"sk-<NEW_KEY>","workspaceId":"<WORKSPACE_ID>","type":"shared"}'
# OR via CLI: infisical secrets set --token=$TOKEN --projectId=322fceab... --env=prod ...
```
<<<<<<< HEAD
**2026-07-16 UPDATE — vault SYNCED + CLEANED.** The abiba service token (`st.8e848433…`, READ+WRITE)
can write to the vault. All session-13 rotated keys in vault and validate 200 against LiteLLM.
4 stale secrets deprecated, 5 personal creds flagged for separate project. Tanko migrated from
hardcoded keys to `infisical-gateway.sh` wrapper. Koonimo Zulip key restored.
**Machine Identity:** `8ddb9438-74fc-4ab6-bd74-929e7c47b53b` exists in Infisical UI.
Client secret needed to use universal auth for vault writes from automation.
**Service Token Inventory (2026-07-16):**
| Token ID | Name | Permissions | Used By |
|----------|------|-------------|---------|
| `st.8e848433…` | tanko-gateway | READ+WRITE | Abiba, Koonimo |
| `st.353699cd…` | tanko-agent | READ-only | Tanko |
=======
Creation requires the Infisical web UI (https://vault.sysloggh.net) under Project Settings →
Machine Identities, or an admin API call. **TODO: create `abiba-automation` machine identity
and store its credentials in the vault itself (or a root-only file).**
**Interim (working now):** the `.env` fallback (hermes-config-template Rule 3/13). The
infisical-gateway.sh wrapper sources `~/.hermes/.env`, so its `<AGENT>_LITELLM_API_KEY`
overrides a stale vault value.
**2026-07-16 UPDATE — vault is now SYNCED.** The abiba service token (`st.8e848433…`, READ+WRITE)
can write to the vault, so the session-13 rotated keys (mumuni `sk-OzuWsoX2…`, koby `sk-BqRRMboTI…`,
koonimo `sk-OEK7z26n6E…`) are now in the vault as `MUMUNI_LITELLM_API_KEY` / `KOBY_LITELLM_API_KEY` /
`KOONIMO_LITELLM_API_KEY` and validate 200 against LiteLLM. The vault is the source of truth again.
Creating a dedicated `abiba-automation` machine identity (via UI) is still the proper long-term fix
so the shared service token isn't reused across hosts — but it is no longer blocking.
>>>>>>> origin/master
## Key Rotation Log
| Date | Agent | Action | Notes |
|------|-------|--------|-------|
<<<<<<< HEAD
| 2026-07-16 | koonimo | add-zulip | Added KOONIMO_ZULIP_API_KEY to vault (Tt2bUL…). Updated wrapper to inject ZULIP_API_KEY + ZULIP_EMAIL. Restarted gateway → Zulip connected as koonimo-bot@ (bot_id=17). 3 platforms now. |
| 2026-07-16 | tanko | migrate | Migrated from hardcoded config.yaml key to infisical-gateway.sh wrapper + service token st.353699cd… (tanko-agent). Systemd user service updated, hardcoded key drop-ins removed. Verified LITELLM_API_KEY from vault, 3 platforms connected. |
| 2026-07-16 | vault | cleanup | 4 stale secrets deprecated: KAGENZ0_LITELLM_API_KEY, HERMES_OPENROUTER_KEY, LITELLM_API_KEY (generic duplicate), ZULIP_API_KEY (generic duplicate). 5 personal creds flagged for separate project. |
=======
>>>>>>> origin/master
| 2026-07-16 | mumuni | rotate | Old key malformed (sk-_SWAl_Vu_, 47 chars, not LiteLLM format) → 401. Deleted old `mumuni` key (token 15cbca18…), generated fresh (alias `mumuni`, 7 models: syslog-auto, qwen3.6-27B-code, gemma-4-12b, strix-moe, gpu-dense, gpu-light, qwen3.6-35B-udq4). New key sk-OzuWsoX2… written to /root/.hermes/.env (Rule 3/13 fallback). Vault sync PENDING (needs machine identity). WAL #1300. |
| 2026-07-16 | koby | rotate | Old key sk-6sbCNjz (401, stale in /etc/environment). Deleted old `koby` key, generated fresh (alias `koby`). New key sk-BqRRMboTI… in systemd drop-in `hermes-gateway.service.d/litellm-key.conf` + /etc/environment. Created `hermes-gateway.service` unit (was missing — gateway wasn't persistent) with `--replace`. Verified HTTP 200, Telegram connected. |
| 2026-07-16 | baggy (koonimo) | rotate | Old key sk-krnw_zGB (401, hardcoded in systemd drop-in). Deleted old `baggy` key, generated fresh (alias `baggy`, metadata agent=koonimo). New key sk-OEK7z26n6E… in drop-in `hermes-gateway.service.d/litellm-key.conf`. CT113 IP changed .113→.114. Verified HTTP 200, Zulip connected. |
## LiteLLM Master Key (use sparingly — agents should NOT use it directly)
- Master key: `sk-litellm-7f96080dd99b15c36bd4b333b58a6796` (in /opt/inference-harness/.env on CT116, Infisical project=infrastructure env=production secret=LITELLM_MASTER_KEY)
- Used for /key/generate, /key/delete, /key/list (GET), DB queries
- **Known violation (RESOLVED 2026-07-16):** Abiba's LITELLM_API_KEY was previously the master key.
It is now a dedicated agent key `sk-sxbphLvk1OU…` (vault secret `ABIBA_LITELLM_API_KEY`, alias `abiba-pi`).
The master key is admin-only (/key/generate, /key/delete, /key/list). NEVER use it for inference —
see `litellm-self-heal` § "NEVER use litellm_proxy_master_key for inference".
- LiteLLM key DB: `harness-postgres` container on CT116, table `"LiteLLM_VerificationToken"` (columns: token, key_alias, key_name, created_at, expires). Query: `docker exec harness-postgres psql -U litellm -d litellm -t -c "SELECT key_alias, substr(token,1,16) FROM \"LiteLLM_VerificationToken\" ORDER BY created_at;"`
+10 -10
View File
@@ -42,8 +42,8 @@ Request → nginx:80 → LiteLLM:4000 → GPU(llama-server, parallel 2)
**What changed (v3.2.0 → v4.0.0 — 2026-07-08)**:
- Router REMOVED from request path — LiteLLM proxies directly to GPU
- All GPUs at parallel 2 (was parallel 1)
- NVIDIA context reduced 256K→128K to free VRAM
- LiteLLM timeouts tuned: gemma 25→120s, qwen 40→90s
- NVIDIA context reduced 256K→128K to free VRAM (SUPERSEDED 2026-07-16: all GPUs back to 256K — see litellm-self-heal)
- LiteLLM timeouts tuned: gemma 25→120s, qwen 40→90s (SUPERSEDED 2026-07-16: qwen 300s, gemma 120s, strix 300s — see litellm-self-heal)
- nginx proxy_read_timeout: 600s, LiteLLM request_timeout: 300s
## Parameters
@@ -72,18 +72,18 @@ Request → nginx:80 → LiteLLM:4000 → GPU(llama-server, parallel 2)
| Host | IP | Hardware | Models Served | Engine | Context | Parallel |
|------|-----|----------|---------------|--------|---------|----------|
| llm-gpu | 192.168.68.8 | NVIDIA RTX 3090 (24 GB) | qwen3.6-27B-code | llama-server systemd | 128K | 2 |
| ocu-llm | 192.168.68.110 | NVIDIA RTX 5070 (12 GB) | gemma-4-12b | llama-server systemd | 128K | 2 |
| amdpve | 192.168.68.15 | AMD Strix Halo 64GB UMA | ornith-1.0-35b | llama-server systemd (Vulkan) | 256K | 2 |
| llm-gpu | 192.168.68.8 | NVIDIA RTX 3090 (24 GB) | qwen3.6-27B-code | llama-server systemd | **256K** | 2 |
| ocu-llm | 192.168.68.110 | NVIDIA RTX 5070 (12 GB) | gemma-4-12b | llama-server systemd | **256K** | 2 |
| amdpve | 192.168.68.15 | AMD Strix Halo 64GB UMA | qwen3.6-35B-udq4 (LiteLLM alias: strix-moe) | llama-server systemd (Vulkan) | 256K | 2 |
## Model Fallback Chains (LiteLLM)
| Primary | Timeout | Fallback | Timeout |
|---------|---------|----------|---------|
| qwen3.6-27B-code | 90s | gemma-4-12b | 120s |
| gemma-4-12b | 120s | qwen3.6-27B-code | 90s |
| ornith-1.0-35b | 120s | qwen → gemma | — |
| syslog-auto (balanced) | 90s | qwen → gemma | — |
| qwen3.6-27B-code | 300s | gemma-4-12b | 120s |
| gemma-4-12b | 120s | qwen3.6-27B-code | 300s |
| qwen3.6-35B-udq4 / strix-moe | 300s | qwen → gemma | — |
| syslog-auto (balanced) | 300s | qwen → gemma | — |
> Global: request_timeout=300s, nginx proxy_read_timeout=600s
@@ -129,7 +129,7 @@ Request → nginx:80 → LiteLLM:4000 → GPU(llama-server, parallel 2)
7. **Check model inference via LiteLLM** — Test each model:
- POST /v1/chat/completions model=gemma-4-12b → expect 200
- POST /v1/chat/completions model=qwen3.6-27B-code → expect 200
- POST /v1/chat/completions model=ornith-1.0-35b → expect 200
- POST /v1/chat/completions model=strix-moe → expect 200
- Use master key for auth
8. **Check agent keys**:
+27 -8
View File
@@ -6,6 +6,7 @@ note: >
DEPLOYED 2026-07-12 on CT 116 cron: 0 */6 * * *
Auto-remediation code was removed from the pi Zulip extension (retired 2026-07-04),
now reimplemented as `litellm-health-check.sh` on CT 116.
Script: `/opt/inference-harness/scripts/litellm-health-check.sh` on CT 116 (cron `0 */6 * * *`).
Reports to /var/log/litellm/health-*.json and RA-H OS knowledge graph.
GPU monitoring integrated from gpu-monitor on .24:9100.
@@ -56,18 +57,29 @@ Request → nginx:80 → LiteLLM:4000 → GPU(llama-server, parallel 2)
| Host | IP | Hardware | Models Served | Engine | Context | Parallel |
|------|-----|----------|---------------|--------|---------|----------|
| llm-gpu | 192.168.68.8 | NVIDIA RTX 3090 (24 GB) | qwen3.6-27B-code | llama-server systemd | **256K** | 1 |
| ocu-llm | 192.168.68.110 | NVIDIA RTX 5070 (12 GB) | gemma-4-12b | llama-server systemd | 131K | 2 |
| amdpve | 192.168.68.15 | AMD Strix Halo 64GB UMA | ornith-1.0-35b | llama-server systemd (Vulkan) | 256K | 2 |
| llm-gpu | 192.168.68.8 | NVIDIA RTX 3090 (24 GB) | qwen3.6-27B-code | llama-server systemd (`/home/llmuser/llama-wrapper.sh`, `-c 262144 --parallel 2 --ngl 99`) | **256K** | 2 |
| ocu-llm | 192.168.68.110 | NVIDIA RTX 5070 (12 GB) | gemma-4-12b | llama-server systemd (`/home/llmuser/llama-wrapper.sh`, `--ctx-size 262144 --parallel 2`, IQ4_NL + MTP draft) | **256K** | 2 |
| amdpve | 192.168.68.15 | AMD Strix Halo 64GB UMA | qwen3.6-35B-udq4 (LiteLLM alias: `strix-moe`) | llama-server systemd (Vulkan) | 256K | 2 |
> Verified on ground 2026-07-16 via `curl /v1/models` on each host + `llama-wrapper.sh`. The AMD host's underlying model is `qwen3.6-35B-udq4`; LiteLLM exposes it under two `model_name`s: `qwen3.6-35B-udq4` and `strix-moe` (rpm 40). The legacy name `ornith-1.0-35b` does NOT exist in LiteLLM and must not be referenced.
## LiteLLM Model Surface (ground truth — `/opt/inference-harness/litellm_config.yaml` on CT 116)
`model_name`s served: `qwen3.6-27B-code`, `gemma-4-12b`, `qwen3.6-35B-udq4`, `strix-moe`, `gpu-dense`, `gpu-light`, `syslog-auto`.
- `syslog-auto` is a weighted router model: qwen3.6-27B-code (0.55, rpm 500) + qwen3.6-35B-udq4 (0.30, rpm 60) + gemma-4-12b (0.15, rpm 200).
- `gpu-dense` / `gpu-light` are high-rpm aliases (rpm 500) onto qwen3.6-27B-code / gemma-4-12b respectively.
- Key scoping: agent keys are restricted to `['syslog-auto','qwen3.6-27B-code','gemma-4-12b','strix-moe','gpu-dense','gpu-light']`. As of 2026-07-16 the `baggy`/`koby`/`mumuni`/`abiba-pi` keys ALSO include `qwen3.6-35B-udq4`; `abiba-pi` additionally includes `deepseek-v4-pro` (cloud fallback). `kagenz0`/`koonimo`/`pi-agents-unified` have the standard 6 only. Agents should still use the stable alias `strix-moe` (not the raw `qwen3.6-35B-udq4`) so model swaps don't break them.
- **NEVER use `litellm_proxy_master_key` (the `sk-litellm-...` master key) for inference.** It is for admin endpoints only (`/key/list`, `/key/generate`, `/key/info`). All inference — agent traffic, health-check model tests, monitor scripts — uses agent-specific keys. The health-check script's model tests use a dedicated `monitor` agent key stored at `/etc/litellm-monitor.env` on CT 116 (root-only, `chmod 600`); `/key/list` is the only call that legitimately uses `$MASTER_KEY`.
## Model Fallback Chains (LiteLLM)
| Primary | Timeout | Fallback | Timeout |
|---------|---------|----------|---------|
| qwen3.6-27B-code | 90s | gemma-4-12b | 120s |
| gemma-4-12b | 120s | qwen3.6-27B-code | 90s |
| ornith-1.0-35b | 120s | qwen → gemma | — |
| syslog-auto (balanced) | 90s | qwen → gemma | — |
| qwen3.6-27B-code | 300s | gemma-4-12b | 120s |
| gemma-4-12b | 120s | qwen3.6-27B-code | 300s |
| qwen3.6-35B-udq4 / strix-moe | 300s | qwen → gemma | — |
| syslog-auto (balanced) | 300s | qwen → gemma | — |
> Global: request_timeout=300s, nginx proxy_read_timeout=600s
@@ -86,6 +98,13 @@ Request → nginx:80 → LiteLLM:4000 → GPU(llama-server, parallel 2)
| harness-docker-stats | python:3.12-alpine | — | container stats exporter |
| harness-pve-exporter | prompve/prometheus-pve-exporter | — | Proxmox metrics → Prometheus |
## Script Operations (synced 2026-07-16)
- **Health-check script** (`/opt/inference-harness/scripts/litellm-health-check.sh` on CT 116): `gpu-fleet` check fails only on **critical** alerts (warnings are informational). Tests `strix-moe` (not `ornith-1.0-35b`).
- **GPU monitor** (`/root/scripts/gpu-monitor-server.py` on pi .24): runs as **systemd unit `gpu-monitor.service`** (was bare `&` process). `gpu_count` includes Strix Halo (was 2, now 3). VRAM alert thresholds: warning 93%, critical 97% (raised from 90/95 — 256K context steady-state is ~96% on RTX 3090, not a fault).
- **Agent key monitor** (`/root/scripts/agent-health-check.py` on pi .24, cron `*/10`): reads each agent's **live** `LITELLM_API_KEY` from its gateway process env via SSH — never hardcodes keys (hardcoded keys rot on rotation and caused 9×401/30min). Fleet roster: abiba, tanko, mumuni, koby, koonimo (legacy `tdunna`/`baggy` removed — never existed).
- **Stale keys cleaned**: `daily-infra-report.py` SYNTHETIC_API_KEY was stale (`sk-U_ydi3B` → 401); now reads `LITELLM_MASTER_KEY` from env. Deprecated scripts (`router-original.py`, `router-phase0-backup.py`, `apply-fixes.py`) still reference `sk-syslog-local-master-key` but do not actively poll LiteLLM.
## Maintains
- litellm-admin-ui: { status: "healthy", last_check: timestamp }
@@ -128,7 +147,7 @@ Run this first on every cycle. Results feed into remediation rules below.
### 5. Check model inference via LiteLLM — test each model
- POST /v1/chat/completions model=gemma-4-12b → expect 200
- POST /v1/chat/completions model=qwen3.6-27B-code → expect 200
- POST /v1/chat/completions model=ornith-1.0-35b → expect 200
- POST /v1/chat/completions model=strix-moe → expect 200
- Use master key for auth
### 6. Check agent keys
+4 -4
View File
@@ -92,10 +92,10 @@ raw data never provided.
|--------|-------|----------|------|----------|
| `syslog-code` | qwen3.6-27B-code | terminal, file, web, memory, skills | Code patches, automation, scripts | Writing/modifying code, creating scripts, debugging, reading/writing files |
| `syslog-devops` | qwen3.6-27B-code | terminal, file, web, memory, skills | Infrastructure, DB, bridge, Proxmox | Server ops, SSH, Docker, Proxmox, DB queries, hardware checks |
| `syslog-email` | ornith-1.0-35b | terminal, file, web, memory, skills | Email automation, mail operations | Sending/receiving email, inbox management, SMTP operations |
| `syslog-research` | ornith-1.0-35b | terminal, file, web, memory, skills, **browser** | Analysis, classification, data processing | Web research, browser tasks, data analysis, classification, reading docs |
| `syslog-review` | ornith-1.0-35b | terminal, file, web, memory, skills | Verification, QA, audit validation | **ALWAYS** verify worker output before delivery — especially for infra changes, code builds, and research findings |
| `syslog-writer` | ornith-1.0-35b | terminal, file, web, memory, skills | Docs, content, branding, reports | Writing docs, reports, proposals, content, markdown formatting |
| `syslog-email` | strix-moe | terminal, file, web, memory, skills | Email automation, mail operations | Sending/receiving email, inbox management, SMTP operations |
| `syslog-research` | strix-moe | terminal, file, web, memory, skills, **browser** | Analysis, classification, data processing | Web research, browser tasks, data analysis, classification, reading docs |
| `syslog-review` | strix-moe | terminal, file, web, memory, skills | Verification, QA, audit validation | **ALWAYS** verify worker output before delivery — especially for infra changes, code builds, and research findings |
| `syslog-writer` | strix-moe | terminal, file, web, memory, skills | Docs, content, branding, reports | Writing docs, reports, proposals, content, markdown formatting |
### Selection Rules
+2 -2
View File
@@ -79,7 +79,7 @@ description: >
`messages_processed` stalls.
- **Root cause**: Agent's model config (`models.json` or `settings.json`) references a
model ID that doesn't exist in LiteLLM's authorized model list. Example: `qwen3.6-35B-A3B`
configured but LiteLLM only exposes `ornith-1.0-35b` under that key. pi's session
configured but LiteLLM only exposes `strix-moe` (alias for qwen3.6-35B-udq4) under that key. pi's session
workers emit 403 on first prompt, then never recover because the error doesn't trigger
`agent_end` — worker stays `busy` and all subsequent messages pile up in the steer queue.
- **Detection**: Compare `~/.pi/agent/models.json` model IDs against `curl -H "Authorization: Bearer <KEY>" http://192.168.68.116/v1/models` output. A stuck worker shows
@@ -88,7 +88,7 @@ description: >
(2) Set `defaultModel` to `syslog-auto` (safe routing model). (3) Delete stale session
JSONL files from `~/.pi/agent/sessions/zulip/`. (4) Restart PM2 process.
- **Prevention**: Use `syslog-auto` as default model for all agents — it handles model
routing and fallback automatically. Direct model IDs (`ornith-1.0-35b`, etc.) should
routing and fallback automatically. Direct model IDs (`strix-moe`, etc.) should
only be used when explicitly requested. Validate model IDs at agent setup time.
- **Applies to**: pi extension (Tdunna CT111, fixed 2026-07-08), any agent using `syslog-harness` provider