# Technique inventory — Axium and Orange

Phase 1, 6 August 2026. Everything below was read from source. File paths and line numbers are given so the paper can cite its own tree.

- **Axium** — `C:\xampp\htdocs\axium`, Rust, 28 `.rs` files
- **Orange** — `C:\xampp\htdocs\orange`, Python, 166 `.py` files

---

## 1. Routing and classification

### Axium — three-stage hybrid, mostly local

`src/agent/classifier.rs` (947 lines). Four output classes, `classifier.rs:8-19`:

| Class | Behaviour |
|---|---|
| `Trivial(String)` | Answered **by the cheap classifier model itself**. The primary model is never called |
| `Simple` | Passed through to primary unchanged |
| `Medium` | Primary model, but **skips quality review and code review** |
| `Complex(String)` | The classifier's **enhanced prompt replaces the original** before it reaches the primary |

The entry point is `quick_classify`, `classifier.rs:917-947`, with the stages documented in the code:

1. **Stage 1 — deterministic patterns.** `quick_classify_trivial` (`:877`) catches greetings, acknowledgements and identity questions with no model call.
2. **Stage 2 — a local weighted scorer.** `score_prompt` (`:769`) computes a score from **ten weighted dimensions**: reasoning markers 0.18, code presence 0.15, multi-step patterns 0.12, technical terms 0.10, token-count proxy 0.08, simple indicators **−0.08**, agentic markers 0.06, creative markers 0.05, constraint indicators 0.04, structured-output request 0.03. Two hard overrides short-circuit it: more than 500 words returns score 0.5 at confidence 0.95, and three or more reasoning keywords returns 0.5 at confidence 0.90.
   If `confidence >= 0.75`, the decision is made **locally with no API call**: `score < -0.02` → `Simple`, `score < 0.25` → `Medium`, otherwise fall through so the LLM can enhance.
3. **Stage 3 — LLM classifier**, only for low-confidence cases.

The code comment at `classifier.rs:918` makes a **testable claim**: *"The scorer handles 60-70% of requests locally; the LLM handles ambiguous cases."*

The classifier's own system prompt (`:60`) carries explicit negative guards — never classify as TRIVIAL if the user asks about the assistant's capabilities, memory or identity, asks it to remember something, or references prior conversation. That is a deliberate defence against the cheap path answering a question that needs state.

### Orange — a single LLM router

`evals/pipeline.py:23-37`. One model call, strict-JSON output, three routes:

```
{"route": "direct" | "conversation" | "coding", "answer": "<short answer ONLY if route is direct...>"}
```

`direct` covers time/date, agenda, locating a project, counting unread mail, trivial facts. `conversation` is reasoning, judgement, drafting, summarising, multi-step non-programming. `coding` is writing, fixing, refactoring, testing or explaining software.

Like Axium's `Trivial`, the `direct` route can carry the answer inline, so the expensive layers are skipped.

### The divergence, and it is measurable

**Axium decides most turns without an API call. Orange always spends one.** Axium's is deterministic and free but hand-tuned; Orange's is adaptive but costs latency and money on every single turn.

This is the sharpest testable difference between the two harnesses and Phase 3 should measure it directly: classification accuracy against a labelled set, cost per decision, and latency per decision.

---

## 2. Planning

### Orange — a separate planner role, prompted not to code

`evals/pipeline.py:39-44`:

> *"You are a senior software engineer acting as the PLANNER (not the coder)... produce a concise, concrete implementation PLAN: numbered steps naming the function/signature, the algorithm, and the edge cases to handle. Do NOT write the full code — a separate coder will implement your plan. Keep it tight (4-8 steps)."*

And the coder is prompted to obey it, `pipeline.py:53-58`:

> *"Implement the TASK by following the provided PLAN exactly — do not re-plan, second-guess, or redesign it."*

That pairing — a planner forbidden to code and a coder forbidden to re-plan — is the clearest piece of deliberate prompt engineering in either codebase.

### Axium — planning as a tool plus a confirmation gate

Axium has a `plan_file_changes` tool in its registry and emits a `Plan(String)` event (`router.rs:33`). At `router.rs:1931` the plan is presented with an explicit confirmation:

> `"\nProceed with these changes? (yes/no)"`

So Orange separates planning by **model role**; Axium separates it by **user consent**.

### What the existing evidence says about planning

Phase 0 measured `with_plan` combined with `with_brain` and found **no gain** — but on a saturated suite where the bare configuration already scored 16/16, so the test could not show one. This remains open.

---

## 3. Context and memory

### Axium

- `src/memory/store.rs` — persistent memory, exposed to the model as `update_memory` and `update_user_model` tools.
- `src/agent/compactor.rs` (157 lines) — a **dedicated summarisation model** with its own domain-specific system prompt (`compactor.rs:6-20`). It is told to preserve file paths and what was done to them, commands and their outcomes **especially errors**, decisions and stated preferences, task status, and `<tool_trace>` blocks verbatim. It is told to omit pleasantries, verbose explanation, **plans that were already executed** ("keep the result, drop the plan"), and redundant file contents.
- Input is capped at ~100,000 characters before compaction (`compactor.rs:57`).

### Orange

- `src/orange/brain.py` — the repo-map preload, the `with_brain` switch in the benchmark.
- `.orange_knowledge.md` and `save_knowledge` / `load_knowledge` tools — persisted facts.
- `src/orange/convstore.py`, `trajectory.py` — conversation and trajectory storage.

### Convergence worth reporting

Both keep durable state **outside** the conversation and both compress rather than truncate. Neither relies on the context window as memory.

---

## 4. Prompt construction and caching

**Both harnesses independently split the system prompt into a static cached block and a dynamic uncached block.** This is the strongest convergence in the inventory.

### Axium

`src/agent/sonnet.rs:522-541`. The system prompt is assembled as a **static `soul` block plus a dynamic block** carrying memory and tasks. Both are tagged:

```rust
{"type": "text", "text": soul,    "cache_control": {"type": "ephemeral", "ttl": "1h"}},
{"type": "text", "text": dynamic, "cache_control": {"type": "ephemeral", "ttl": "1h"}}
```

Caching is applied in three further places: the **tools array** has `cache_control` on its last element so the whole array caches (`sonnet.rs:28-36`, `:69-77`), and the **last conversation message** is tagged so the whole conversation caches (`sonnet.rs:567`, `:988`).

### Orange

`src/orange/agent.py`. `_stable_system_prompt()` (`:115`) is assembled from the soul file plus the project listing and is **cached at module level**, with the comment at `:89` explaining why: `build_system_prompt()` runs on every turn. `_live_context(active_project)` (`:217-221`) is appended per turn and not cached.

`_load_soul()` (`:76`) reads an external soul file with a `_FALLBACK_SOUL` constant (`:64`) if it fails — the personality is configuration, not code, in both harnesses (Axium ships `soul.example.md`).

---

## 5. Tool design

| | Axium | Orange |
|---|---|---|
| Tools exposed | **31** | **69** |
| Reduced set | **Yes — 18 tools in "simple" mode** | No |
| Parallel execution | Claimed in README | — |

Axium's `MINIMAL_TOOL_NAMES` (`sonnet.rs:52-66`) is a hand-picked allowlist of 18, and the comment states the exclusion rule: *"Excludes heavy scaffolding tools (subagents, task queuing, code intelligence, destructive ops)."* Simple-classified turns therefore see **42% fewer tools**, which cuts both prompt tokens and the model's opportunity to wander.

Axium's full set: `append_file, ask_user, browse_url, delete_file, find_references, get_dependency_graph, get_diagnostics, git_command, list_directory, move_file, patch_file, plan_file_changes, queue_task, read_file, rename_symbol, rollback_changes, run_command, run_subagent, scan_project, search_files, search_history, send_email, send_file, set_autonomous, spawn_background, task_manage, update_memory, update_project_knowledge, update_user_model, web_search, write_file`.

Orange exposes 69 unique tool names across `src/orange/*.py`, spanning code editing, project management, email, calendar, deployment, notes, skills, TTS and web.

**The divergence is a genuine design disagreement**: Axium narrows the surface per turn; Orange presents everything and relies on the model to choose. Both are defensible and the trade is measurable.

---

## 6. Steering interventions — the part most harnesses do not document

Axium's `router.rs` carries a set of explicit mid-turn corrections injected as `[SYSTEM]` messages. These are prompt engineering in the operational sense and are worth quoting in the paper:

| Line | Intervention |
|---|---|
| `:901` | *"Your response was cut off by the token limit."* — continuation handling |
| `:980` | *"You have not finished the user's request."* — incompleteness nudge |
| `:987` | *"You described what you will do but did not call any tools."* — the classic say-don't-do failure, caught explicitly |
| `:1208` | *"You have {} iteration(s) remaining before the hard limit."* — budget disclosure to the model |

Plus compression: `<tool_log>` (`:1278-1283`) and `<tool_trace>` (`:2659-2683`) blocks, and an automatic test-run with repair loop emitting `[TESTS PASSED]` and `[TESTS PASSED after repair]` (`:457`, `:505`).

The `AgentEvent::Retry` variant (`router.rs`) exists because *"Heartbeat decided the response was incomplete — text is being discarded and retried"* — an automatic quality gate that discards already-streamed output.

Orange's equivalents are lighter: a `finish` tool, `todo_write`, `run_tests`.

---

## 7. Safety and limits

- **Axium**: `ask_user` tool, the plan confirmation gate at `router.rs:1931`, and a hard iteration limit surfaced to the model.
- **Orange**: `src/orange/safeexec.py` — a command deny-list whose own docstring (`:7`) is admirably blunt: *"This is NOT a sandbox — it is a deny-list of clearly [dangerous commands]"*. Blocked commands are logged (`:51`). Also `secretscan.py`.

Neither harness sandboxes. Both should say so in the paper.

---

## What this inventory makes testable

Phase 3 should build measurements for these, in this order of value:

1. **Axium's "60-70% handled locally" claim** — directly checkable against a labelled prompt set, deterministic, **zero API cost**. It is the most falsifiable claim in either codebase.
2. **Local scorer vs LLM router**: accuracy, cost per decision, latency per decision, on the same labelled set. This is the two harnesses' central disagreement.
3. **Tool-set narrowing**: token cost of 31 tools vs 18, and whether the reduced set changes task success.
4. **Planner-forbidden-to-code vs no planner** — on a suite hard enough to show a difference, which the current one is not.
5. **Compaction quality**: does Axium's compactor preserve what its prompt claims to preserve?

## Not established

- Axium has **no test suite and no benchmark harness** of any kind. Everything above is read from source, not measured.
- Axium's README makes cost-comparison claims against other tools. Nothing in the repository substantiates them. They remain the author's marketing copy until measured.
- Neither harness has been run head-to-head on anything.
