arkaos 5.16.1 → 5.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/VERSION +1 -1
  2. package/arka/SKILL.md +2 -2
  3. package/arka/skills/costs/SKILL.md +3 -1
  4. package/arka/skills/forge/SKILL.md +2 -2
  5. package/arka/skills/forge/references/complexity-engine.md +1 -1
  6. package/arka/skills/fusion/SKILL.md +1 -1
  7. package/config/claude-agents/data-collector.md +1 -1
  8. package/config/claude-agents/doc-writer.md +1 -1
  9. package/config/claude-agents/paulo-tech-lead.md +3 -3
  10. package/config/claude-agents/research-assistant.md +1 -1
  11. package/config/cognition/schedules.yaml +10 -0
  12. package/config/constitution.yaml +1 -1
  13. package/config/hooks/_lib/fastpath/engine.cjs +17 -2
  14. package/config/hooks/gate-manifest.json +5 -3
  15. package/config/hooks/pre-tool-use.ps1 +3 -3
  16. package/config/models.yaml +4 -4
  17. package/config/settings-template.json +55 -13
  18. package/core/agents/behavioral_compiler.py +3 -1
  19. package/core/agents/schema.py +44 -19
  20. package/core/cognition/scheduler/cli.py +2 -0
  21. package/core/cognition/scheduler/daemon.py +262 -11
  22. package/core/forge/runtime_dispatcher.py +7 -20
  23. package/core/governance/harness_scanner.py +8 -0
  24. package/core/harness/drift.py +24 -0
  25. package/core/harness/manager.py +5 -0
  26. package/core/harness/spec.py +12 -2
  27. package/core/hooks/gate_manifest.py +8 -2
  28. package/core/hooks/post_tool_use.py +127 -17
  29. package/core/hooks/pre_tool_use.py +3 -3
  30. package/core/hooks/session_start.py +26 -0
  31. package/core/hooks/user_prompt_submit.py +7 -0
  32. package/core/jobs/auto_doc_worker.py +127 -34
  33. package/core/runtime/claude_code.py +194 -7
  34. package/core/runtime/gateway/litellm_config.py +8 -5
  35. package/core/runtime/llm_cost_telemetry.py +53 -9
  36. package/core/runtime/llm_provider.py +21 -9
  37. package/core/runtime/model_router.py +55 -2
  38. package/core/runtime/model_routing_check.py +94 -1
  39. package/core/runtime/model_routing_context.py +1 -1
  40. package/core/runtime/native_usage.py +6 -3
  41. package/core/runtime/ollama_provider.py +11 -3
  42. package/core/runtime/pricing.py +32 -6
  43. package/core/runtime/runtime_models.py +13 -13
  44. package/core/workflow/flow_enforcer.py +14 -7
  45. package/core/workflow/frontend_gate.py +2 -5
  46. package/core/workflow/schema.py +14 -12
  47. package/core/workflow/specialist_enforcer.py +2 -4
  48. package/dashboard/app/pages/models.vue +1 -1
  49. package/departments/brand/SKILL.md +2 -2
  50. package/departments/community/SKILL.md +2 -2
  51. package/departments/content/SKILL.md +2 -2
  52. package/departments/dev/SKILL.md +2 -2
  53. package/departments/dev/agents/research-assistant.yaml +1 -1
  54. package/departments/dev/agents/tech-lead.md +30 -11
  55. package/departments/ecom/SKILL.md +2 -2
  56. package/departments/finance/SKILL.md +2 -2
  57. package/departments/kb/SKILL.md +2 -2
  58. package/departments/kb/agents/data-collector.yaml +1 -1
  59. package/departments/landing/SKILL.md +2 -2
  60. package/departments/leadership/SKILL.md +2 -2
  61. package/departments/marketing/SKILL.md +2 -2
  62. package/departments/ops/SKILL.md +2 -2
  63. package/departments/ops/agents/doc-writer.yaml +1 -1
  64. package/departments/ops/skills/operations/SKILL.md +1 -1
  65. package/departments/org/SKILL.md +2 -2
  66. package/departments/pm/SKILL.md +2 -2
  67. package/departments/quality/SKILL.md +2 -2
  68. package/departments/saas/SKILL.md +2 -2
  69. package/departments/sales/SKILL.md +2 -2
  70. package/departments/strategy/SKILL.md +2 -2
  71. package/installer/doctor.js +69 -17
  72. package/installer/fallback-model.js +68 -0
  73. package/installer/index.js +14 -0
  74. package/installer/update.js +12 -0
  75. package/knowledge/agents-registry-v2.json +4 -4
  76. package/knowledge/commands-registry.json +2 -2
  77. package/knowledge/skills-manifest.json +1 -1
  78. package/package.json +1 -1
  79. package/pyproject.toml +6 -1
package/VERSION CHANGED
@@ -1 +1 @@
1
- 5.16.1
1
+ 5.17.0
package/arka/SKILL.md CHANGED
@@ -207,7 +207,7 @@ violation (squad-routing, arka-supremacy, spec-driven, mandatory-qa).
207
207
 
208
208
  | Command | Description |
209
209
  |---------|-------------|
210
- | `/arka status` | System status (version, departments, agents, active projects). Includes **LLM costs (24h)** section: top-line cost + cache hit rate + call count from `core.runtime.llm_cost_telemetry.summarise(period="today")`. Also includes **Enforcement (24h)** section: total calls, block rate, top blocked tools/reasons from `core.governance.enforcement_telemetry.summarise(period="today")` (PR19 v2.41.0). Plus **Reorganization (today)** section: today's proposal path + artifact count from `core.cognition.reorganizer_scheduler.status_summary()` (PR24 v2.46.0). Plus **Model routing** section: gateway live/off + resolved per-slot routes + served counts from `core.runtime.model_routing_check.status_summary()`. Plus **MCP usage (24h)** section: total calls + servers in use + top servers from `core.runtime.mcp_telemetry.summarise(period="today")`. |
210
+ | `/arka status` | System status (version, departments, agents, active projects). Includes **LLM costs (24h)** section: top-line cost + cache hit rate + call count from `core.runtime.llm_cost_telemetry.summarise(period="today")`. Also includes **Enforcement (24h)** section: total calls, block rate, top blocked tools/reasons from `core.governance.enforcement_telemetry.summarise(period="today")` (PR19 v2.41.0). Plus **Reorganization (today)** section: today's proposal path + artifact count from `core.cognition.reorganizer_scheduler.status_summary()` (PR24 v2.46.0). Plus **Model routing** section: gateway live/off + resolved per-slot routes + served counts + the `fallbackModel` chain from settings.json or its state (`unset` / `disabled` / `invalid`) (Runtime Sync PR3 v5.17.0) from `core.runtime.model_routing_check.status_summary()`. Plus **MCP usage (24h)** section: total calls + servers in use + top servers from `core.runtime.mcp_telemetry.summarise(period="today")`. |
211
211
  | `/arka costs [period]` | LLM cost visibility — aggregates telemetry by day/week/month/all, with top expensive sessions. See `arka/skills/costs/SKILL.md`. Shells out to `~/.arkaos/bin/arka-py -m core.runtime.llm_cost_telemetry_cli <period>`. |
212
212
  | `/arka enforcement [period]` | Enforcement compliance — aggregates flow-marker enforcement telemetry by day/week/month/all. Shows block rate, top blocked tools, top reasons. Shells out to `~/.arkaos/bin/arka-py -m core.governance.enforcement_telemetry_cli <period>`. |
213
213
  | `/arka mcps [period]` | MCP usage — aggregates the PostToolUse MCP telemetry (`~/.arkaos/telemetry/mcp-usage.jsonl`) by day/week/month/all. Shows total calls, servers in use, top servers and top tools. Shells out to `~/.arkaos/bin/arka-py -m core.runtime.mcp_telemetry_cli <period>`. |
@@ -315,4 +315,4 @@ All output: YAML frontmatter · wikilinks · department paths · MOC organizatio
315
315
 
316
316
  ## Model Selection
317
317
 
318
- Use `model` parameter from agent YAML (`departments/*/agents/*.yaml`), upgraded by the Model Fabric routing when `[ARKA:MODEL-FABRIC]` is present. Quality Gate model: constitution `quality_gate.model_policy` is the single source (best-available/frontier tier; veto is model-independent). Default: `sonnet`. Mechanical tasks: `haiku`.
318
+ Use `model` parameter from agent YAML (`departments/*/agents/*.yaml`), upgraded by the Model Fabric routing when `[ARKA:MODEL-FABRIC]` is present. Quality Gate model: constitution `quality_gate.model_policy` is the single source (best-available/frontier tier; veto is model-independent). Default: `sonnet`. Mechanical tasks: `sonnet` at low effort — ArkaOS never routes to Haiku (Runtime Sync 2026-09-03).
@@ -70,8 +70,10 @@ Outside this skill's scope but worth surfacing alongside the summary:
70
70
  | Lever | Where | Effect |
71
71
  | --- | --- | --- |
72
72
  | `ARKAOS_LLM_PROVIDER` | env | Switch between Anthropic, OpenAI, Gemini adapters per the multi-LLM router. |
73
+ | `fallbackModel` | `~/.claude/settings.json` (Claude Code 2.1.166+) | Up to three models tried in order when the primary is overloaded or unavailable. `npx arkaos install` / `update` seed `["claude-opus-5", "claude-sonnet-5"]` when the key is absent and never overwrite an operator chain; `/arka status` shows the configured chain. |
74
+ | Schedule `model:` / `fallback_models:` | `~/.arkaos/schedules.yaml` | A pinned `model` goes to `claude --model`; without one the Model Fabric `strategy` role becomes `ANTHROPIC_DEFAULT_MODEL` (Claude Code 2.1.236+). `fallback_models` goes to `--fallback-model` (default `claude-opus-5 → claude-sonnet-5`) so one overload or model 404 no longer ends a nightly cycle. |
73
75
  | `ANTHROPIC_BEDROCK_SERVICE_TIER` | env (Claude Code 2.1.122+) | `default` / `flex` / `priority`. Only relevant when routing through AWS Bedrock — `flex` cuts cost ~50 % on non-urgent workloads at the price of higher tail latency. |
74
- | Agent `model:` field | `departments/*/agents/*.yaml` | Per-agent override per the model-routing matrix in CLAUDE.md. Mechanical roles default to haiku, C-suite to opus. |
76
+ | Agent `model:` field | `departments/*/agents/*.yaml` | Per-agent override per the model-routing matrix in CLAUDE.md. Mechanical roles default to `sonnet` at low effort, C-suite to `opus` (Opus 5); the Quality Gate row below lifts Marta / Eduardo / Francisca to the frontier tier. |
75
77
  | Quality Gate model | constitution `quality_gate.model_policy` | Marta / Eduardo / Francisca run on the best model available (frontier tier) regardless of the cost ceiling — review quality is never the place to save tokens. |
76
78
 
77
79
  ## Non-negotiables
@@ -48,7 +48,7 @@ The Forge analyses any prompt across 5 complexity dimensions, routes to 1-3 expl
48
48
 
49
49
  | Tier | Score | Explorers | Critic | Companion | Model |
50
50
  |------|-------|-----------|--------|-----------|-------|
51
- | Simple (Shallow) | ≤ 30 | 1 (Pragmatic, inline) | Light | None | haiku |
51
+ | Simple (Shallow) | ≤ 30 | 1 (Pragmatic, inline) | Light | None | sonnet |
52
52
  | Standard | 31-65 | 2 (Pragmatic + Architectural, parallel) | Full | On request | sonnet |
53
53
  | Complex (Deep) | 66-85 | 3 (+ Contrarian, parallel) | Full | Proactive | opus |
54
54
  | Super | ≥ 86 | 3 + full synthesis | Full (highest judgment) | Proactive | opus |
@@ -59,7 +59,7 @@ Five dimensions score 0-100 each: **scope**, **dependencies**, **ambiguity**, **
59
59
 
60
60
  When dispatching explorer subagents via the Task tool, include `model: <tier_model>` parameter. The tier-to-model mapping is:
61
61
 
62
- - simple → `model: haiku` (fast routing, single explorer)
62
+ - simple → `model: sonnet` (fast routing, single explorer; the weakest lane ArkaOS routes to)
63
63
  - standard → `model: sonnet` (default, 1-2 explorers)
64
64
  - complex → `model: opus` (3 explorers + critic synthesis)
65
65
  - super → `model: opus` (highest judgment, full synthesis)
@@ -6,7 +6,7 @@ Referenced from SKILL.md. Read only when needed.
6
6
 
7
7
  | Tier | Score | Explorers | Critic | Companion | Model |
8
8
  |------|-------|-----------|--------|-----------|-------|
9
- | Simple (Shallow) | ≤ 30 | 1 (Pragmatic, inline) | Light | None | haiku |
9
+ | Simple (Shallow) | ≤ 30 | 1 (Pragmatic, inline) | Light | None | sonnet |
10
10
  | Standard | 31-65 | 2 (Pragmatic + Architectural, parallel) | Full | On request | sonnet |
11
11
  | Complex (Deep) | 66-85 | 3 (Pragmatic + Architectural + Contrarian, parallel) | Full | Proactive | opus |
12
12
  | Super | ≥ 86 | 3 + full synthesis | Full (highest judgment) | Proactive | opus |
@@ -68,7 +68,7 @@ Produce a table: role → provider/model + ONE-line rationale each. Rules:
68
68
  evidence: budget panel + frontier judge beats frontier solo at ~50%
69
69
  cost).
70
70
  - `mechanical` → cheapest competent lane: local coder model if Ollama
71
- runs one, else haiku-class.
71
+ runs one, else Sonnet 5 at low effort (the weakest cloud lane).
72
72
  - Fusion panel: 2-3 DIVERSE models (different families — e.g. one
73
73
  Anthropic, one Kimi/DeepSeek, one local large) + frontier judge.
74
74
  Homogeneous panels waste the fan-out.
@@ -2,7 +2,7 @@
2
2
  name: data-collector
3
3
  description: >
4
4
  Tomas Jr — Data Collector (kb squad). Executes: data-collection, web-scraping, API-integration, data-validation.
5
- model: haiku
5
+ model: sonnet
6
6
  ---
7
7
 
8
8
  <!-- generated by core/agents/behavioral_compiler.py from departments/kb/agents/data-collector.yaml — DO NOT EDIT; edit the YAML and re-run -->
@@ -2,7 +2,7 @@
2
2
  name: doc-writer
3
3
  description: >
4
4
  Isabel — Documentation Writer (ops squad). Executes: technical-writing, API-docs, user-guides, SOPs.
5
- model: haiku
5
+ model: sonnet
6
6
  ---
7
7
 
8
8
  <!-- generated by core/agents/behavioral_compiler.py from departments/ops/agents/doc-writer.yaml — DO NOT EDIT; edit the YAML and re-run -->
@@ -5,7 +5,7 @@ description: >
5
5
  work into atomic tasks, dispatches specialists, enforces the evidence flow
6
6
  (real test runs, exit codes on record), and submits deliverables to the
7
7
  Quality Gate before anything ships.
8
- tools: Read, Grep, Glob, Bash, Agent, TaskCreate
8
+ tools: Read, Grep, Glob, Bash, Agent
9
9
  model: sonnet
10
10
  ---
11
11
 
@@ -37,8 +37,8 @@ not cut corners to look fast.
37
37
  self-documenting names, no dead code.
38
38
  - TDD where practical; coverage >= 80% on new code (constitution MUST).
39
39
  - Conventional commits, feature branches, never commit to main/master/dev.
40
- - Model routing: dispatch specialists on sonnet, mechanical tasks on haiku;
41
- opus only for Tier 0/security-scope reviews.
40
+ - Model routing: sonnet for specialists, sonnet at low effort for mechanical
41
+ tasks (never haiku); opus only for Tier 0/security-scope reviews.
42
42
 
43
43
  ## Signature Rules (anti-sycophancy)
44
44
 
@@ -2,7 +2,7 @@
2
2
  name: research-assistant
3
3
  description: >
4
4
  Maria — Research Assistant (dev squad). Executes: research, documentation, analysis, literature-review.
5
- model: haiku
5
+ model: sonnet
6
6
  ---
7
7
 
8
8
  <!-- generated by core/agents/behavioral_compiler.py from departments/dev/agents/research-assistant.yaml — DO NOT EDIT; edit the YAML and re-run -->
@@ -2,6 +2,16 @@
2
2
  #
3
3
  # This file is deployed to ~/.arkaos/schedules.yaml during installation.
4
4
  # Edit the deployed copy to customize schedules.
5
+ #
6
+ # Model pin and fallback chain (Runtime Sync PR3) — per schedule, optional:
7
+ # model: claude-sonnet-5 # pinned: goes to `claude --model`
8
+ # fallback_models: [claude-opus-5] # `--fallback-model a,b`; [] disables
9
+ # Without `model`, the Model Fabric `strategy` role (~/.arkaos/models.yaml)
10
+ # becomes ANTHROPIC_DEFAULT_MODEL for the run. Without `fallback_models`,
11
+ # the chain is claude-opus-5 → claude-sonnet-5. The runtime caps chains at
12
+ # three models after de-duplication, removes ids outside `availableModels`
13
+ # before the walk and fails over past an id it cannot reach (a retired
14
+ # model); the ArkaOS gateway plays no part in the chain.
5
15
 
6
16
  schedules:
7
17
  dreaming:
@@ -111,7 +111,7 @@ enforcement_levels:
111
111
  enforcement: "persistence.py exports on status change; audit detects missing exports"
112
112
 
113
113
  - id: model-routing
114
- rule: "Quality-first model routing: design, review, architecture, strategy, and Quality Gate phases run the BEST model available for the task (frontier tier) at maximum effort BY DEFAULT. Cheaper/smaller models (haiku, local) are reserved for genuinely mechanical work: commit messages, keyword extraction, data fetching, formatting. Cost optimisation NEVER downgrades a quality-critical phase — the CostGovernor hard budget is the only ceiling. User-owned overrides live in ~/.arkaos/models.yaml (Model Fabric): the user decides which provider/model serves each role; this rule sets the default posture, not a fixed vendor table. Replaced the cost-optimised per-tier table in the Excellence Reform (2026-07-05)."
114
+ rule: "Quality-first model routing: design, review, architecture, strategy, and Quality Gate phases run the BEST model available for the task (frontier tier) at maximum effort BY DEFAULT. Cheaper lanes (Sonnet 5 at low effort, local) are reserved for genuinely mechanical work: commit messages, keyword extraction, data fetching, formatting. ArkaOS never routes to Haiku. Cost optimisation NEVER downgrades a quality-critical phase — the CostGovernor hard budget is the only ceiling. User-owned overrides live in ~/.arkaos/models.yaml (Model Fabric): the user decides which provider/model serves each role; this rule sets the default posture, not a fixed vendor table. Retired model ids (previous Opus and Fable generations) and the Haiku lane are mapped to their current replacement at resolve time, with a notice; the table is core/runtime/model_router.LEGACY_MODEL_IDS. The user's models.yaml is never rewritten (Runtime Sync 2026-09-03). Replaced the cost-optimised per-tier table in the Excellence Reform (2026-07-05)."
115
115
  enforcement: "warning"
116
116
 
117
117
  - id: subagent-discipline
@@ -227,7 +227,7 @@ function decidePre(payload, manifest, ctx) {
227
227
  return { action: "delegate", reason: "bash-effect-or-budget" };
228
228
  }
229
229
 
230
- // P7/P8 — Write/Edit/MultiEdit/NotebookEdit/Task/Skill: specialist +
230
+ // P7/P8 — Write/Edit/NotebookEdit/Task/Skill: specialist +
231
231
  // frontend + flow chains with decision-bearing state writes.
232
232
  return { action: "delegate", reason: "flow-gated" };
233
233
  }
@@ -311,7 +311,7 @@ function toolText(payload) {
311
311
  /**
312
312
  * PostToolUse decision. Returns
313
313
  * {action:"fast-exit", stdout:"{}", writes:[...]} — mcp telemetry only
314
- * {action:"delegate", reason}
314
+ * {action:"delegate", reason} — incl. "kb-marker" for KB-consult tools
315
315
  * ctx: {homeDir, config, env, fs, now?: Date}
316
316
  */
317
317
  function decidePost(payload, manifest, ctx) {
@@ -333,6 +333,21 @@ function decidePost(payload, manifest, ctx) {
333
333
  return { action: "delegate", reason: "post-stateful-tool" };
334
334
  }
335
335
 
336
+ // Q3b — KB-first evidence (Runtime Sync PR0). The "obsidian"/"graphify"
337
+ // turn markers the research gate reads have exactly one writer, in
338
+ // Python (post_tool_use.KB_MARKER_TOOL_PREFIXES → manifest). A fast-exit
339
+ // here skipped it, so on a turn whose KB call took this path the gate
340
+ // could not see the consult (kb_first.jsonl 2026-09-03: 66 denials,
341
+ // 0 kb-consulted). Prefix = server; Python decides whether the tool is
342
+ // a read consult. Old manifests without the key keep the previous
343
+ // behaviour (fail-open, never deny).
344
+ const kbPrefixes = Array.isArray(manifest.tools.post_delegate_prefixes)
345
+ ? manifest.tools.post_delegate_prefixes
346
+ : [];
347
+ if (kbPrefixes.some((p) => toolName.startsWith(p))) {
348
+ return { action: "delegate", reason: "kb-marker" };
349
+ }
350
+
336
351
  // Q5 — error path: gotchas, violations, cognition capture, metrics.
337
352
  // PostToolUse never carries an exit code (failures fire the event
338
353
  // above), so the only error signal on this path is trigger text.
@@ -519,7 +519,7 @@
519
519
  "tool": "Edit"
520
520
  },
521
521
  {
522
- "expect": "delegate",
522
+ "expect": "fast_allow",
523
523
  "tool": "MultiEdit"
524
524
  },
525
525
  {
@@ -715,7 +715,6 @@
715
715
  "tools": {
716
716
  "effect_always": [
717
717
  "Edit",
718
- "MultiEdit",
719
718
  "NotebookEdit",
720
719
  "Skill",
721
720
  "Task",
@@ -724,7 +723,6 @@
724
723
  "flow_gated": [
725
724
  "Bash",
726
725
  "Edit",
727
- "MultiEdit",
728
726
  "NotebookEdit",
729
727
  "Skill",
730
728
  "Task",
@@ -735,6 +733,10 @@
735
733
  "ExitPlanMode",
736
734
  "Task"
737
735
  ],
736
+ "post_delegate_prefixes": [
737
+ "mcp__graphify__",
738
+ "mcp__obsidian__"
739
+ ],
738
740
  "research_external": [
739
741
  "WebFetch",
740
742
  "WebSearch",
@@ -1,7 +1,7 @@
1
1
  # ============================================================================
2
2
  # ArkaOS v2 — PreToolUse Hook (Windows PowerShell)
3
3
  #
4
- # Parity with config/hooks/pre-tool-use.sh. Blocks Write/Edit/MultiEdit when
4
+ # Parity with config/hooks/pre-tool-use.sh. Blocks Write/Edit when
5
5
  # the mandatory 13-phase flow is required for the session AND the assistant
6
6
  # has not emitted a flow marker in its last 3 messages of the transcript.
7
7
  #
@@ -127,7 +127,7 @@ print(json.dumps({
127
127
  # Blocks Tier-1 leads from writing to specialist-owned files without
128
128
  # dispatching first. Only fires for file-mutation tools.
129
129
  $specialistPy = Join-Path $env:ARKAOS_ROOT "core/workflow/specialist_enforcer.py"
130
- if ((Test-Path $specialistPy) -and ($toolName -in @("Write","Edit","MultiEdit","NotebookEdit"))) {
130
+ if ((Test-Path $specialistPy) -and ($toolName -in @("Write","Edit","NotebookEdit"))) {
131
131
  $toolInputJson = "{}"
132
132
  if ($inp.tool_input) {
133
133
  $toolInputJson = ($inp.tool_input | ConvertTo-Json -Compress -Depth 10)
@@ -201,7 +201,7 @@ print(json.dumps({
201
201
  }
202
202
 
203
203
  # --- Fast allow: not a flow-gated tool ---
204
- if ($toolName -ne "Write" -and $toolName -ne "Edit" -and $toolName -ne "MultiEdit") {
204
+ if ($toolName -ne "Write" -and $toolName -ne "Edit") {
205
205
  exit 0
206
206
  }
207
207
 
@@ -34,13 +34,13 @@ providers:
34
34
  # `best` / `default` / `fast` resolve per provider, so roles stay readable.
35
35
  aliases:
36
36
  runtime:
37
- best: opus
37
+ best: fable # Claude Code alias → Fable 5.1 (Claude Code 2.1.257+)
38
38
  default: sonnet
39
- fast: haiku
39
+ fast: sonnet # weakest lane is Sonnet 5 — never Haiku
40
40
  anthropic:
41
- best: claude-opus-4-8
41
+ best: claude-fable-5-1
42
42
  default: claude-sonnet-5
43
- fast: claude-haiku-4-5-20251001
43
+ fast: claude-sonnet-5
44
44
  ollama:
45
45
  best: "" # set your strongest local model, e.g. kimi-k2.6
46
46
  default: ""
@@ -14,7 +14,7 @@
14
14
  {
15
15
  "type": "command",
16
16
  "command": "{{HOOKS_DIR}}/session-start.sh",
17
- "timeout": 5
17
+ "timeout": 15
18
18
  }
19
19
  ]
20
20
  }
@@ -30,18 +30,18 @@
30
30
  ]
31
31
  }
32
32
  ],
33
- "PreCompact": [
33
+ "PostToolUse": [
34
34
  {
35
35
  "hooks": [
36
36
  {
37
37
  "type": "command",
38
- "command": "{{HOOKS_DIR}}/pre-compact.sh",
39
- "timeout": 30
38
+ "command": "{{HOOKS_DIR}}/post-tool-use.sh",
39
+ "timeout": 5
40
40
  }
41
41
  ]
42
42
  }
43
43
  ],
44
- "PostToolUse": [
44
+ "PostToolUseFailure": [
45
45
  {
46
46
  "hooks": [
47
47
  {
@@ -52,39 +52,81 @@
52
52
  ]
53
53
  }
54
54
  ],
55
- "PostToolUseFailure": [
55
+ "PreToolUse": [
56
56
  {
57
57
  "hooks": [
58
58
  {
59
59
  "type": "command",
60
- "command": "{{HOOKS_DIR}}/post-tool-use.sh",
61
- "timeout": 5
60
+ "command": "{{HOOKS_DIR}}/pre-tool-use.sh",
61
+ "timeout": 10
62
+ }
63
+ ]
64
+ },
65
+ {
66
+ "matcher": "Task",
67
+ "hooks": [
68
+ {
69
+ "type": "command",
70
+ "command": "{{HOOKS_DIR}}/agent-provision.sh",
71
+ "timeout": 10
62
72
  }
63
73
  ]
64
74
  }
65
75
  ],
66
- "CwdChanged": [
76
+ "Stop": [
67
77
  {
68
78
  "hooks": [
69
79
  {
70
80
  "type": "command",
71
- "command": "{{HOOKS_DIR}}/cwd-changed.sh",
81
+ "command": "{{HOOKS_DIR}}/stop.sh",
72
82
  "timeout": 5
73
83
  }
74
84
  ]
75
85
  }
76
86
  ],
77
- "PreToolUse": [
87
+ "SubagentStop": [
78
88
  {
79
- "matcher": "Task",
80
89
  "hooks": [
81
90
  {
82
91
  "type": "command",
83
- "command": "{{HOOKS_DIR}}/agent-provision.sh",
92
+ "command": "{{HOOKS_DIR}}/subagent-stop.sh",
84
93
  "timeout": 10
85
94
  }
86
95
  ]
87
96
  }
97
+ ],
98
+ "SessionEnd": [
99
+ {
100
+ "hooks": [
101
+ {
102
+ "type": "command",
103
+ "command": "{{HOOKS_DIR}}/session-end.sh",
104
+ "timeout": 15
105
+ }
106
+ ]
107
+ }
108
+ ],
109
+ "PreCompact": [
110
+ {
111
+ "hooks": [
112
+ {
113
+ "type": "command",
114
+ "command": "{{HOOKS_DIR}}/pre-compact.sh",
115
+ "timeout": 30
116
+ }
117
+ ]
118
+ }
119
+ ],
120
+ "CwdChanged": [
121
+ {
122
+ "hooks": [
123
+ {
124
+ "type": "command",
125
+ "command": "{{HOOKS_DIR}}/cwd-changed.sh",
126
+ "timeout": 5
127
+ }
128
+ ]
129
+ }
88
130
  ]
89
131
  }
90
132
  }
@@ -32,6 +32,8 @@ from pathlib import Path
32
32
 
33
33
  import yaml
34
34
 
35
+ from core.agents.schema import normalise_tier
36
+
35
37
  _ROOT = Path(__file__).resolve().parents[2]
36
38
  _OUT_DIR = _ROOT / "config" / "claude-agents"
37
39
 
@@ -95,7 +97,7 @@ def _frontmatter(slug: str, data: dict) -> str:
95
97
  desc = f"{data.get('name', slug)} — {role} ({dept} squad)."
96
98
  if domains:
97
99
  desc += f" Executes: {domains}."
98
- model = data.get("model", "sonnet")
100
+ model = normalise_tier(data.get("model", "sonnet"))
99
101
  return (
100
102
  f"---\nname: {slug}\ndescription: >\n {desc}\nmodel: {model}\n---"
101
103
  )
@@ -8,11 +8,24 @@ Every ArkaOS agent has a complete behavioral profile composed of:
8
8
  """
9
9
 
10
10
  from enum import Enum
11
- from typing import Literal, Optional
11
+ from typing import Literal
12
+
12
13
  from pydantic import BaseModel, Field, model_validator
13
14
 
15
+ # "haiku" stays accepted for legacy client YAML only; ArkaOS's weakest
16
+ # lane is Sonnet 5 (Runtime Sync 2026-09-03). "fable" = Claude Code alias.
17
+ ModelTier = Literal["haiku", "sonnet", "opus", "fable"]
18
+
19
+
20
+ # Runtime Sync 2026-09-03: the weakest lane ArkaOS routes to is Sonnet 5.
21
+ # "haiku" still PARSES (legacy client YAML) but never reaches a dispatch:
22
+ # get_model() and the compiled frontmatter both normalise it.
23
+ _LANE_NORMALISATION: dict[ModelTier, ModelTier] = {"haiku": "sonnet"}
14
24
 
15
- ModelTier = Literal["haiku", "sonnet", "opus"]
25
+
26
+ def normalise_tier(model: ModelTier) -> ModelTier:
27
+ """Map a legacy lane to the one ArkaOS actually routes to."""
28
+ return _LANE_NORMALISATION.get(model, model)
16
29
 
17
30
 
18
31
  def tier_default_model(tier: int) -> ModelTier:
@@ -24,9 +37,9 @@ def tier_default_model(tier: int) -> ModelTier:
24
37
 
25
38
  # --- DISC Framework ---
26
39
 
27
- class DISCType(str, Enum):
40
+ class DISCType(str, Enum): # noqa: UP042 — behavioural parity kept; StrEnum migration deferred
28
41
  D = "D" # Dominance
29
- I = "I" # Influence
42
+ I = "I" # noqa: E741 — DISC letter is the contract
30
43
  S = "S" # Steadiness
31
44
  C = "C" # Conscientiousness
32
45
 
@@ -64,13 +77,13 @@ class EnneagramType(int, Enum):
64
77
  PEACEMAKER = 9
65
78
 
66
79
 
67
- class EnneagramCenter(str, Enum):
80
+ class EnneagramCenter(str, Enum): # noqa: UP042 — behavioural parity kept; StrEnum migration deferred
68
81
  BODY = "body" # 8, 9, 1 — Anger/Instinct
69
82
  HEART = "heart" # 2, 3, 4 — Shame/Feeling
70
83
  HEAD = "head" # 5, 6, 7 — Fear/Thinking
71
84
 
72
85
 
73
- class InstinctualSubtype(str, Enum):
86
+ class InstinctualSubtype(str, Enum): # noqa: UP042 — behavioural parity kept; StrEnum migration deferred
74
87
  SP = "self-preservation"
75
88
  SO = "social"
76
89
  SX = "sexual"
@@ -136,14 +149,26 @@ class BigFiveProfile(BaseModel):
136
149
 
137
150
  # --- MBTI Framework ---
138
151
 
139
- class MBTIType(str, Enum):
140
- INTJ = "INTJ"; INTP = "INTP"; ENTJ = "ENTJ"; ENTP = "ENTP"
141
- INFJ = "INFJ"; INFP = "INFP"; ENFJ = "ENFJ"; ENFP = "ENFP"
142
- ISTJ = "ISTJ"; ISFJ = "ISFJ"; ESTJ = "ESTJ"; ESFJ = "ESFJ"
143
- ISTP = "ISTP"; ISFP = "ISFP"; ESTP = "ESTP"; ESFP = "ESFP"
144
-
145
-
146
- class CognitiveFunction(str, Enum):
152
+ class MBTIType(str, Enum): # noqa: UP042 — behavioural parity kept; StrEnum migration deferred
153
+ INTJ = "INTJ"
154
+ INTP = "INTP"
155
+ ENTJ = "ENTJ"
156
+ ENTP = "ENTP"
157
+ INFJ = "INFJ"
158
+ INFP = "INFP"
159
+ ENFJ = "ENFJ"
160
+ ENFP = "ENFP"
161
+ ISTJ = "ISTJ"
162
+ ISFJ = "ISFJ"
163
+ ESTJ = "ESTJ"
164
+ ESFJ = "ESFJ"
165
+ ISTP = "ISTP"
166
+ ISFP = "ISFP"
167
+ ESTP = "ESTP"
168
+ ESFP = "ESFP"
169
+
170
+
171
+ class CognitiveFunction(str, Enum): # noqa: UP042 — behavioural parity kept; StrEnum migration deferred
147
172
  Ni = "Ni" # Introverted Intuition
148
173
  Ne = "Ne" # Extraverted Intuition
149
174
  Si = "Si" # Introverted Sensing
@@ -217,7 +242,7 @@ class Authority(BaseModel):
217
242
  block_delivery: bool = False
218
243
  orchestrate: bool = False
219
244
  delegates_to: list[str] = Field(default_factory=list)
220
- escalates_to: Optional[str] = None
245
+ escalates_to: str | None = None
221
246
 
222
247
 
223
248
  # --- Communication Style ---
@@ -272,12 +297,12 @@ class Agent(BaseModel):
272
297
 
273
298
  memory_path: str = ""
274
299
 
275
- model: Optional[ModelTier] = Field(
300
+ model: ModelTier | None = Field(
276
301
  default=None,
277
302
  description="Claude model override for dispatch. Falls back to tier default when None.",
278
303
  )
279
304
 
280
- parent_squad: Optional[str] = Field(
305
+ parent_squad: str | None = Field(
281
306
  default=None,
282
307
  description=(
283
308
  "Slug of the parent squad when this agent belongs to a sub-squad. "
@@ -287,7 +312,7 @@ class Agent(BaseModel):
287
312
  ),
288
313
  )
289
314
 
290
- sub_squad_role: Optional[str] = Field(
315
+ sub_squad_role: str | None = Field(
291
316
  default=None,
292
317
  description=(
293
318
  "Role within the sub-squad when parent_squad is set "
@@ -314,4 +339,4 @@ class Agent(BaseModel):
314
339
 
315
340
  def get_model(self) -> ModelTier:
316
341
  """Return the resolved Claude model, using tier default when unset."""
317
- return self.model or tier_default_model(self.tier)
342
+ return normalise_tier(self.model or tier_default_model(self.tier))
@@ -14,6 +14,8 @@ def list_schedules(config_path: str) -> list[dict]:
14
14
  "time": s.run_time.strftime("%H:%M"),
15
15
  "timeout": s.timeout_minutes,
16
16
  "retry": s.retry_on_fail,
17
+ "model": s.model,
18
+ "fallback_models": list(s.fallback_models),
17
19
  }
18
20
  for s in schedules
19
21
  ]