# Cold-Start Framework — unified first-run UX for every Axiom-portfolio CLI

**Status:** Working / proposal — Ben to review before any implementation
**Authored:** 2026-05-04
**Pairs with:** [cold-start-audit.md](cold-start-audit.md) (which surfaces the problem)

---

## Goals

1. **Every command has an opinionated, friendly first-run UX** — never a stack trace, never a silent empty result, never a "run X first" wall when the system could just do X.
2. **Extension builders declare the pattern, not the prose.** The framework owns voice + agent hand-off + telemetry; the extension just says "I want pattern N for this verb."
3. **Voice is shared across all extensions.** Axiom builtins, Keplo classroom, NeutronOS, future third-parties all sound like the same product.
4. **Agents (D-FIB, M-O, BURN-E, V-EGA, CHALK-E) plug into cold-start hooks** — when a prereq is missing, an agent can offer to fix it.
5. **Migration is opportunistic, not big-bang.** Existing commands keep working unchanged; declaring the new field is purely additive.

Aligns with `feedback_proactive_ux_minimize_cognitive_load.md`, `feedback_drive_dont_enumerate.md`, `feedback_auto_generated_ids.md`, `feedback_standalone_first_lms_optional.md`.

---

## High-level architecture

```mermaid
flowchart TD
    U[User runs axi cmd] --> CLI[axi CLI dispatcher]
    CLI --> CSR[ColdStartResolver]
    CSR --> M[Read manifest cold_start declaration]
    CSR --> P{Pattern selected}
    P -->|auto_init| AI[AutoInit handler]
    P -->|wizard| WZ[Wizard handler]
    P -->|empty_state| ES[EmptyState handler]
    P -->|lazy_resource| LR[LazyResource handler]
    P -->|prereq_check| PC[PrereqCheck handler]
    P -->|robust_readout| RR[RobustReadout handler]
    P -->|nudge_default| ND[NudgeDefault fallback]

    AI --> AGT[Agent hooks D-FIB M-O BURN-E]
    WZ --> AGT
    PC --> AGT

    AI --> EXEC[Run command]
    WZ --> EXEC
    ES --> EXEC
    LR --> EXEC
    PC --> EXEC
    RR --> EXEC
    ND --> EXEC

    EXEC --> OUT[Output to user with WALL-E voice]

    classDef user fill:#1e3a8a,color:#dbeafe,stroke:#3b82f6
    classDef cli fill:#374151,color:#f3f4f6,stroke:#9ca3af
    classDef pattern fill:#065f46,color:#ecfdf5,stroke:#10b981
    classDef agent fill:#581c87,color:#f3e8ff,stroke:#a855f7
    classDef exec fill:#78350f,color:#fef3c7,stroke:#f59e0b

    class U user
    class CLI,CSR cli
    class P,AI,WZ,ES,LR,PC,RR,ND pattern
    class AGT agent
    class EXEC,OUT exec
    class M cli
```

The resolver is one shared component in `axiom/infra/cold_start/`. Extensions never construct it; they just declare what pattern fits each verb in `axiom-extension.toml`.

---

## The seven named patterns

```mermaid
flowchart TD
    Root[Cold-start patterns] --> P1[1 auto_init]
    Root --> P2[2 wizard]
    Root --> P3[3 empty_state]
    Root --> P4[4 lazy_resource]
    Root --> P5[5 prereq_check]
    Root --> P6[6 robust_readout]
    Root --> P7[7 nudge_default - fallback]

    P1 --> P1d[Detect missing prereq fix it narrate one line continue]
    P2 --> P2d[User-driven multi-step setup explicit confirm at gates]
    P3 --> P3d[No data yet show suggested next-step verb optional sample]
    P4 --> P4d[Resource is created on first write narrated once]
    P5 --> P5d[Hard external prereq missing offer agent remediation]
    P6 --> P6d[Always succeeds reports each subsystem state]
    P7 --> P7d[Default if extension declares nothing show help-with-context]

    classDef root fill:#1f2937,color:#f9fafb,stroke:#6b7280
    classDef pat fill:#065f46,color:#ecfdf5,stroke:#10b981
    classDef desc fill:#374151,color:#f3f4f6,stroke:#9ca3af
    class Root root
    class P1,P2,P3,P4,P5,P6,P7 pat
    class P1d,P2d,P3d,P4d,P5d,P6d,P7d desc
```

### 1. `auto_init`

**When:** A prereq is missing but the system has everything it needs to create it without asking.

**Behavior:** On first run, detect the missing prereq, announce one line ("First time — generating identity for `<user>`…"), execute, continue with the user's command.

**Examples in current code:**
- `axi note` auto-creates the daily note file (already does this)
- `axi memory show` auto-builds the default composition (already does this)
- `axi federation status` should auto-init identity (currently walls — fix candidate)

**Manifest:** `cold_start = "auto_init"` with optional `auto_init_ref` pointing at a function.

### 2. `wizard`

**When:** Multi-step setup that the user must drive (gives credentials, picks options, confirms destructive action).

**Behavior:** Walk through steps; each step is reversible; final step writes config; show summary + next-verb suggestion.

**Examples:**
- `axi connect <name>` (already wizard-style — best in class)
- `axi install` (steps with state tracking)
- `axi classroom prep init` (auto-generates ids, then walks remaining setup)

### 3. `empty_state`

**When:** Read-only verb on a collection that is currently empty. Don't fail; show a meaningful empty state with the verb that fills it.

**Behavior:** Print one-line "no X yet" + the exact next-step verb the user should run.

**Examples needed:**
- `axi search` empty corpus
- `axi note --list` (already does this — copy the pattern)
- `axi nodes` no peers
- `axi classroom me --memory` no fragments

### 4. `lazy_resource`

**When:** First write to a sub-resource (file, dir, table, queue) that doesn't exist yet. The system should create it without asking and tell the user it did.

**Behavior:** Create the resource with safe defaults; emit one-line narration; continue.

**Examples:**
- `axi log tail` should auto-create `runtime/logs/` (currently walls)
- `axi signal voice` should auto-create `runtime/inbox/raw/voice/` (currently walls)
- `axi rag index` should auto-init local SQLite store if no `rag.database_url` set

### 5. `prereq_check`

**When:** A truly external prereq is missing (git not on PATH, K3D not installed, Docker Desktop not running) — system *cannot* fix it without user action, but an agent might.

**Behavior:** Detect; offer remediation (install command, link, agent hand-off); allow `--no-remediate` opt-out; exit 1 with structured failure if user declines.

**Examples:**
- `axi release` git missing
- `axi db init` K3D missing — propose install via Docker Desktop one-liner per `feedback_docker_desktop_preferred.md`
- `axi mo diagnose` LLM gateway missing — offer `axi connect anthropic`

**Agent hand-off:** This pattern is the natural injection point for D-FIB ("I can install K3D for you — proceed?") and M-O ("I'll provision the cluster"). See §Agent hooks.

### 6. `robust_readout`

**When:** Status / dashboard / list commands that read across many subsystems. Must never fail; always report each piece's state honestly.

**Behavior:** Try each subsystem in isolation; report "configured / not configured / unknown / unhealthy" without raising.

**Examples:**
- `axi status` (already best-in-class)
- `axi connect --check`
- `axi mo vitals`
- `axi federation status` (after auto-init, the read itself is robust_readout)

### 7. `nudge_default` (fallback)

**When:** Extension declares no pattern, OR `axi <ext>` was run with no sub-verb.

**Behavior:** Show:
1. The extension's one-line description (from manifest)
2. Three-to-five top sub-verbs grouped by intent
3. The single most useful starter verb (highlighted)
4. WALL-E voice closer ("Pick one — I'll handle the rest.")

This is what `axi memory` (no args), `axi classroom` (no args), `axi commands` (no args) etc. should show *instead of* `parser.print_help(); return 1`.

---

## Manifest declaration syntax

AEOS extends the `[[extension.provides]]` block with an optional `cold_start` field:

```toml
[[extension.provides]]
kind = "cmd"
noun = "memory"
entry = "axiom.extensions.builtins.memory.cli:main"
description = "Inspect a principal's prior session fragments."
tier = "core"
intent_groups = ["start"]

# NEW: cold-start declaration
cold_start = "nudge_default"

[[extension.provides.cold_start_subverbs]]
verb = "show"
pattern = "auto_init"
auto_init_ref = "axiom.extensions.builtins.memory.cli:_build_default_composition"
empty_message = "No prior fragments. Once this principal starts chatting, session events will accumulate here."

[[extension.provides.cold_start_subverbs]]
verb = "migrate"
pattern = "wizard"
wizard_ref = "axiom.extensions.builtins.memory.cli:_migration_wizard"
```

For commands without sub-verbs, just the top-level `cold_start` field is enough:

```toml
[[extension.provides]]
kind = "cmd"
noun = "search"
entry = "..."
cold_start = "empty_state"
empty_state_message = "Your corpus is empty — nothing to search yet. Try `axi note 'something'` (auto-indexes) or `axi rag index <path>`."
empty_state_next_verbs = ["axi note", "axi rag index", "axi connect rag"]
```

The framework reads these fields, applies the matching handler, and falls back to `nudge_default` if `cold_start` is absent (compatibility — every existing extension keeps working).

### AEOS spec change

Add §6.5 to `spec-aeos-0.1.md`:

> **Cold-start declaration (optional, recommended).** Every `kind = "cmd"` block MAY declare a `cold_start` pattern from the closed set `{auto_init, wizard, empty_state, lazy_resource, prereq_check, robust_readout, nudge_default}`. If absent, the runtime applies `nudge_default`. Sub-verbs MAY override the parent's pattern via `[[extension.provides.cold_start_subverbs]]` blocks. Patterns are non-normative for one release cycle (warn-only); become required-or-explicit-opt-out in AEOS 1.0.

---

## WALL-E voice — example messages

Every cold-start message goes through a shared formatter so voice stays uniform. The character is `axi --help`'s WALL-E persona: helpful, terse, slightly affectionate, "Directive: assist."

### `auto_init` voice

> First run on this node. Generating identity for `ben@axiom-mac`… done.
> (Tip: `axi federation invite` shares this with another node.)

> No daily note for today yet — created `runtime/knowledge/notes/2026-05-04.md`.
> Capturing your note now.

### `empty_state` voice

> No notes yet. Try `axi note "your first thought"` to start your daily log.

> Corpus is empty — nothing to search. Drop a file in `runtime/knowledge/`, or just `axi note "<text>"` (auto-indexes).

> 0 classrooms. `axi classroom prep init --instructor=<you>` makes one — I'll generate the ids.

### `lazy_resource` voice

> No log file yet — creating `runtime/logs/routing_events.jsonl` with mode 0600.
> Tail will follow as events arrive.

### `prereq_check` voice (with agent hand-off)

> `git` not on PATH. `axi release` needs it.
> Install: `xcode-select --install` (macOS) or `brew install git`.
> Re-run when ready.

> Postgres not running. D-FIB can spin up a local pgvector container via Docker Desktop — say `y` to proceed.
> [y/N]:

### `wizard` voice

> Setting up Anthropic. I'll need an API key (starts with `sk-ant-`).
> Get one at https://console.anthropic.com/account/keys
> Paste it here (will be stored in your OS keychain):

### `robust_readout` voice

```
  Federation
  ──────────────────────────────────────────────
  ✓ Identity         ben@axiom-mac (standard)
  ⚠ Peers            0 (run `axi federation invite`)
  ○ Inference        not configured
  ✗ Trust graph      unreachable: cannot connect to coordinator
```

### `nudge_default` voice (the new "no sub-verb" output)

```
  axi memory — your principal's session fragments
  ──────────────────────────────────────────────
  Most useful right now:
    axi memory show <principal>     Read prior fragments

  Other verbs:
    axi memory migrate              Backfill v2 schema (advanced)

  Don't know your principal? Try:
    axi settings get principal.id
```

This replaces `parser.print_help(); return 1` — same information, but framed as "here's what to do" rather than a usage screen + nonzero exit.

---

## Agent hooks

```mermaid
flowchart TD
    PC[prereq_check fires] --> EM[Emit cold_start.prereq_missing event]
    EM --> SUB[BaseAgent subscribers]
    SUB --> DFIB[D-FIB - I can patch this]
    SUB --> MO[M-O - I can provision this]
    SUB --> BURNE[BURN-E - I can rebuild this]
    SUB --> CHALKE[CHALK-E - classroom-aware fix]

    DFIB --> RACI[RACI-gated proposal]
    MO --> RACI
    BURNE --> RACI
    CHALKE --> RACI

    RACI --> APP{User approves?}
    APP -->|yes| FIX[Agent executes fix]
    APP -->|no| EXIT[Exit with structured failure]
    APP -->|3rd no| STOP[Stop asking - per RACI rules]

    FIX --> RETRY[Re-run original command]

    classDef event fill:#78350f,color:#fef3c7,stroke:#f59e0b
    classDef agent fill:#581c87,color:#f3e8ff,stroke:#a855f7
    classDef gate fill:#1e3a8a,color:#dbeafe,stroke:#3b82f6
    classDef out fill:#065f46,color:#ecfdf5,stroke:#10b981
    classDef bad fill:#7f1d1d,color:#fee2e2,stroke:#ef4444

    class PC,EM event
    class SUB,DFIB,MO,BURNE,CHALKE agent
    class RACI,APP gate
    class FIX,RETRY out
    class EXIT,STOP bad
```

The cold-start framework emits one event for each `prereq_check` miss:

```python
EventBus.publish(
    "cold_start.prereq_missing",
    {
        "command": "axi db init",
        "missing": "k3d",
        "remediation": [
            {"agent": "d-fib", "action": "install_k3d_via_docker_desktop"},
            {"agent": "manual", "instructions": "brew install k3d"},
        ],
    },
)
```

Existing agent subscribers (D-FIB hooks already declared in `diagnostics/axiom-extension.toml` for `cli.arg_error`, connection_health) extend to listen for `cold_start.prereq_missing`. Each agent decides whether it can help and proposes via the existing RACI ledger (`feedback_raci_automation_escalation.md`).

This is **purely additive** — no agent has to subscribe; cold-start works without any agents loaded.

---

## Telemetry

The framework emits one event per cold-start fire (regardless of pattern):

```json
{
  "event": "cold_start.fired",
  "command": "axi note",
  "pattern": "auto_init",
  "outcome": "auto_init_success",
  "duration_ms": 23,
  "user_authored_anything": false
}
```

Surfaces three useful signals:
1. Which commands hit cold-start the most → prioritize their UX investment.
2. Which patterns succeed vs abort → tune messages.
3. Per-user "first-run rate" → gate beta loops, retention metric.

Routes through the existing `axi log` substrate. Falls under `feedback_axiom_feedback_module.md` (feedback as first-class capability).

---

## Default fallback (`nudge_default`) — the one we get for free

The biggest single win in the audit: ~7 commands print help + exit 1 when run with no args. The fallback pattern alone, applied universally, fixes them all.

Implementation sketch:

1. CLI dispatcher detects "no sub-verb / no args provided" before calling extension's `main()`.
2. Reads manifest's `description`, `provides`, sub-verb help text.
3. Renders the WALL-E "no sub-verb" template above.
4. Returns 0 (informational, not error) — important for shell scripting.

This is implemented **in the dispatcher**, so an extension that declares `cold_start` does nothing — gets the right behavior automatically. An extension can opt out via `cold_start = "passthrough"` if it has special handling (e.g., `axi chat` enters REPL on no args, `axi note` opens editor).

---

## Migration plan — what to do now vs post-Prague

```mermaid
flowchart TD
    NOW[Now Prague runway] --> N1[Ship dispatcher-side nudge_default fallback]
    NOW --> N2[Ship one-line voice formatter]
    NOW --> N3[Backfill 5-8 most-used commands with explicit pattern - axi note search memory federation classroom prep status doctor mo signal]
    NOW --> N4[Add cold_start field to AEOS spec as optional warn-only]

    POST[Post-Prague] --> P1[Backfill remaining 60 commands]
    POST --> P2[Wire D-FIB and M-O subscribers to cold_start.prereq_missing]
    POST --> P3[Telemetry surface in feedback module]
    POST --> P4[AEOS 1.0 - cold_start required-or-explicit-opt-out]
    POST --> P5[Third-party extension docs - SKILL_COLDSTART.md template]

    NOW --> POST

    classDef now fill:#065f46,color:#ecfdf5,stroke:#10b981
    classDef post fill:#1e3a8a,color:#dbeafe,stroke:#3b82f6
    classDef item fill:#374151,color:#f3f4f6,stroke:#9ca3af
    class NOW now
    class POST post
    class N1,N2,N3,N4,P1,P2,P3,P4,P5 item
```

### Now (1-2 days, before Prague)

- **Dispatcher fallback** — single PR; replaces `parser.print_help(); return 1` everywhere; instant +7 commands fixed.
- **Voice formatter** — `axiom/infra/cold_start/voice.py` with one helper per pattern. Used by the new fallback today; available for opt-in upgrades.
- **5-8 highest-impact backfills** — sub-day each:
  - `axi memory` no-args → nudge_default (replace help dump)
  - `axi search` empty corpus → empty_state
  - `axi federation status` → auto_init (replace wall)
  - `axi classroom prep status` missing classroom → empty_state with fuzzy-match
  - `axi log tail` no log file → lazy_resource
  - `axi signal brief` "run ingest first" → auto_init that runs ingest if raw files exist
  - `axi rag index` no DB → lazy_resource (local SQLite default)
  - `axi doctor` already great — keep, document as exemplar

### Post-Prague

- Remaining ~50 commands declare a pattern — one PR per extension is fine; can be done by D-FIB / M-O via the `cold_start.prereq_missing` event (agent eats its own dogfood).
- Wire D-FIB and M-O to `cold_start.prereq_missing` events for actual remediation (install K3D, generate identity, etc.).
- Surface telemetry in the feedback module.
- AEOS 1.0 makes `cold_start` either declared or `passthrough` (explicit opt-out only). Lint rule in `axi ext lint`.
- Publish `SKILL_COLDSTART.md` template in `docs/specs/` for third-party extension builders. Include voice guide + pattern selection tree.

### Not in scope

- No backwards-compat shims (per `feedback_no_backward_compat_shims.md`). Pre-public-launch — refactor cleanly. Update all call sites in one commit.
- No domain-specific cold-start prose in the framework itself (per `feedback_axiom_domain_agnostic.md`). Domain extensions like NeutronOS provide their own messages via the same hooks.
- No special "classroom-aware cold start" — CHALK-E participates via the standard agent-hook surface like every other agent.

---

## Reference card for extension builders

```mermaid
flowchart TD
    Q1{Does the verb need data the user creates?} -->|yes empty case| Q2{Can the system create it without asking?}
    Q2 -->|yes| AI[auto_init]
    Q2 -->|no - needs user input| Q3{Multi-step?}
    Q3 -->|yes| WZ[wizard]
    Q3 -->|no - just a missing dir or file| LR[lazy_resource]

    Q1 -->|no - read-only of empty collection| ES[empty_state]
    Q1 -->|reads many subsystems| RR[robust_readout]
    Q1 -->|hard external dep| PC[prereq_check]
    Q1 -->|no sub-verb given| ND[nudge_default fallback]

    classDef q fill:#1e3a8a,color:#dbeafe,stroke:#3b82f6
    classDef p fill:#065f46,color:#ecfdf5,stroke:#10b981
    class Q1,Q2,Q3 q
    class AI,WZ,ES,LR,PC,RR,ND p
```

Decision rule when in doubt:
1. **If the system can fix it silently → `auto_init` or `lazy_resource`**.
2. **If the user must drive but it's one-shot → `wizard`**.
3. **If you're listing something that's empty → `empty_state`**.
4. **If you're reading a dashboard → `robust_readout`**.
5. **If a hard external dep is missing → `prereq_check`** (and emit the event so D-FIB can help).
6. **Default → `nudge_default`** (the dispatcher does it for you).

---

## Open questions for Ben

1. **Voice ownership.** WALL-E is the chat agent's persona; should the cold-start voice formally belong to WALL-E, or is it "axi platform voice" with WALL-E as one stylistic source? (Affects copy ownership + future localization.)
2. **`cold_start` vs declaring per-verb pattern.** A single command with many sub-verbs (`axi classroom`, ~40 sub-verbs) gets verbose if every sub-verb declares. Should we allow a single `cold_start_default = "empty_state"` at the parent that all sub-verbs inherit unless they override?
3. **Localization horizon.** Voice messages are English-only today. Prague is US-only this round (per `project_prague_us_only_cohort.md`); but federation goes EU eventually. Do we centralize messages in a `cold_start.toml` per extension to make i18n a flag-flip later?
4. **Telemetry consent.** First-run is the *one* moment we'd love to capture telemetry to learn from, but it's also the one moment a user has zero trust built up. Default off until `axi connect` runs?
5. **Agent gating.** Should `prereq_check` always emit the agent event, or should it require an opt-in flag (`--let-agents-help`)? RACI says propose-then-ask, which suggests always emit but always confirm before executing.

---

## Appendix — pattern → existing code map (for backfill PRs)

| Pattern | Existing code that already implements it (lift to shared layer) |
|---|---|
| `auto_init` | `axi note` daily-file create; `axi memory show` `_build_default_composition`; `axi federation init` keypair gen |
| `wizard` | `axi connect <name>`; `axi install`; `axi classroom prep init` |
| `empty_state` | `axi note --list`; `axi memory show` zero-fragment branch; `axi directive list` |
| `lazy_resource` | `_notes_dir()` + `_inbox_dir()` in note/cli.py |
| `prereq_check` | `axi release` git-missing branch; `axi mo ci` no-remote branch; `axi db init` K3D check |
| `robust_readout` | `axi status`; `axi connect --check`; `axi mo vitals` |
| `nudge_default` | (new) — replace every `parser.print_help(); return 1` |

A first PR could literally be: extract these patterns into `axiom/infra/cold_start/{auto_init,wizard,empty_state,lazy_resource,prereq_check,robust_readout,nudge_default}.py`, then have the existing call sites import from there. Zero behavior change in the first commit; subsequent commits enable the manifest field.
