Skip to content

Cartridge Lifecycle

How the nOSh runtime detects, mounts, registers, hot-swaps, and unmounts a cartridge. Single source for the complete lifecycle — referenced by orchestration.md (mission flow), deck-state.md (which fields get touched on each event), and cipher-voice.md (grammar merge on insertion).


A cartridge moves through five states:

ABSENT → MOUNTED → REGISTERED → ACTIVE → UNMOUNTING → ABSENT
StateTriggerRuntime action
ABSENTNo cart present in the slotMission board generates contracts from cartridge_history alone (no cart-specific templates available).
MOUNTEDudev add event from the SD-via-USB-MSC bridgeFilesystem mounted; .kn86 header read; runtime decides if header is valid and capability bits are recognized.
REGISTEREDHeader valid + capability bits parsedTemplates parsed; cipher-grammar merged into the active grammar tables; phase handlers entered into dispatch table; cartridge_history bit set in deck state.
ACTIVEFirst mission contract using this cart’s capability beginsCart program code (Fe Lisp, ADR-0001) handles cell events; cart contributes events to the Cipher event ring; cart save file is opened for read/write.
UNMOUNTINGudev remove event OR Hot Swap initiatedPhase chain serialized to deck-state SRAM (then flash); cart save file flushed and closed; grammar overlay rolled back; phase handlers unregistered; coprocessor session closed (if any).

Transitions are runtime-driven; cartridges never observe state changes directly — they see only their own handler invocations.


Insertion (ABSENT → MOUNTED → REGISTERED)

Section titled “Insertion (ABSENT → MOUNTED → REGISTERED)”
  1. Operator inserts the SD-card cartridge sled into the slot. The push-push socket engages the SD card’s contacts. (Per ADR-0019: the card-detect switch fires the lifecycle event.)
  2. The internal USB hub’s SD bridge IC enumerates the card as a USB mass-storage device.
  3. The Pi’s kernel emits a udev add event. The nOSh runtime subscribes to this event.
  4. The runtime mounts the filesystem read-only at a known mount point (e.g., /mnt/cart).
  5. The runtime opens the .kn86 container per ADR-0006. Header validation:
    • Magic bytes
    • Format version
    • capability_bits (which capabilities this cart provides)
    • Manifest checksums
  6. If the header is invalid, the runtime surfaces an in-fiction error on the bare-deck terminal (> CARTRIDGE FORMAT NOT RECOGNIZED) and remains in MOUNTED state until the cart is removed.
  7. If the header is valid, registration proceeds:
    • Mission template structures are parsed from the cart’s template region.
    • The cart’s cipher-grammar block is merged into the active CIPHER-LINE grammar tables. See cipher-voice.md for merge rules.
    • Phase handlers are registered with the runtime’s dispatch table.
    • cartridge_history bit is set in Universal Deck State if not already set.
    • Mission board regenerates with the expanded template pool.

The runtime never auto-launches a contract on insertion — the operator chooses what to do next from the mission board.


A cart becomes ACTIVE the first time a mission contract requiring its capability begins:

  1. Operator selects a contract from the mission board.
  2. Runtime resolves the first phase’s required capability against the loaded carts.
  3. If the required cart is REGISTERED, runtime calls its phase handler with the deserialized phase chain context.
  4. Cart’s program code begins executing in the cell runtime (Fe VM). Cart’s per-save file at /save/<cart_id>.sav on the cart’s SD is opened for read/write.
  5. Cart contributes events to the Cipher event ring via cipher-push-event (ADR-0015).

Multiple carts can be REGISTERED simultaneously (rare in practice — the slot holds one cart at a time, but a recently-removed cart’s templates can stay parsed transiently). Only one cart is ACTIVE at any moment.


Hot Swap (ACTIVE → UNMOUNTING → MOUNTED → REGISTERED → ACTIVE)

Section titled “Hot Swap (ACTIVE → UNMOUNTING → MOUNTED → REGISTERED → ACTIVE)”

Multi-phase missions that span capabilities require physical cartridge swaps. The runtime formalizes this as Hot Swap — a tactical pause where the operator exchanges modules to pick up new capabilities. Hot Swap mechanics are detailed in software/cartridges/modules/ice-breaker.md where they serve as a core decision framework.

Phase 1: ICE BREAKER (NETWORK INTRUSION)
↓ phase completes → runtime serializes intermediate state to phase_chain
↓ runtime displays: > PHASE 2 REQUIRES: FORENSIC ACCOUNTING
↓ > INSERT: BLACK LEDGER
↓ operator physically swaps cartridge
Phase 2: BLACK LEDGER (FORENSIC ACCOUNTING)
↓ runtime reads phase_chain, passes context to cartridge handler
↓ phase completes → runtime updates phase_chain
↓ runtime displays: > CONTRACT COMPLETE
↓ > PAYOUT: 4,800 ¤
↓ > REPUTATION: +12
Debrief: Cipher voice summary
  1. The active phase completes. The cart’s phase handler returns control to the runtime.
  2. The runtime writes the phase chain to deck state (SRAM). Includes: phase index, intermediate results (data extracted, evidence gathered, contacts mapped), accumulated threat modifiers, and partial payout accrued.
  3. The runtime displays the swap prompt with the next required capability.
  4. The operator physically removes the current cartridge. udev remove event fires; runtime executes the UNMOUNTING sequence (see below) and returns to ABSENT.
  5. The operator inserts the next cartridge. Runtime executes the insertion sequence; new cart reaches REGISTERED.
  6. Runtime verifies the new cart’s capability_bits include the required capability. If not, surfaces > CARTRIDGE DOES NOT PROVIDE: <CAPABILITY> / RE-INSERT: <expected_module>.
  7. Runtime calls the new cart’s phase handler with the deserialized phase chain context.
  8. Phase begins. Operator works in the new capability domain with full context from the previous phase.

If the operator does not insert a valid cartridge within 5 minutes, the runtime offers two options:

  • Suspend — phase chain preserved in flash; suspended missions can be resumed on next boot.
  • Abandon — reputation penalty, partial payout for completed phases.

The physical act of swapping a cartridge is a diegetic event, not a limitation to apologize for. The swap prompt is in-fiction:

> NETWORK TRACE RECOVERED
> FINANCIAL RECORDS IDENTIFIED IN EXTRACTED DATA
> ANALYSIS REQUIRES FORENSIC ACCOUNTING CAPABILITY
> INSERT MODULE: BLACK LEDGER
> PHASE CHAIN ACTIVE — DO NOT POWER DOWN

The display flickers briefly when the cartridge is removed (2–3 frames of noise, matching the original device’s behavior). The boot sequence for the new cartridge is abbreviated — no full splash screen, just: > MODULE LOADED: BLACK LEDGER / PHASE 2 OF 3 / RESUMING...


Removal (ACTIVE → UNMOUNTING → ABSENT)

Section titled “Removal (ACTIVE → UNMOUNTING → ABSENT)”

Whether triggered by Hot Swap or by the operator simply pulling the cart, removal follows the same sequence:

  1. udev remove event fires.
  2. Runtime serializes any in-flight phase chain state to the deck state (SRAM, then flash).
  3. Cart’s per-save file (/save/<cart_id>.sav on the cart’s SD) is flushed and closed. Save format continues to be ADR-0006 tagged static data; the storage backend is filesystem read/write per ADR-0019, replacing ADR-0013’s MBC5-SRAM model.
  4. The cart’s grammar overlay is rolled back from the CIPHER-LINE grammar tables.
  5. Phase handlers are unregistered from the dispatch table.
  6. Coprocessor session is closed (if the cart held one — see coprocessor-protocol.md session-control frames).
  7. Filesystem is unmounted.
  8. Runtime returns to ABSENT.

cartridge_history is never cleared — once a cart has been registered on this deck, the bit stays set for the deck’s lifetime.


Per ADR-0019, save state lives as a file on the cart’s own SD card filesystem:

  • Path: /save/<cart_id>.sav on the cart’s mounted volume
  • Format: ADR-0006 tagged static data (unchanged at the FFI surface from ADR-0013)
  • Lifecycle: opened for read/write at ACTIVE; flushed and closed at UNMOUNTING
  • Cross-cart fields (handle, credits, reputation) live on the device’s microSD per Universal Deck State, not on the cart

The cart_save / cart_load NoshAPI primitives are unchanged at the FFI surface; only the underlying storage moves from MBC5 SRAM bank-switching to filesystem read/write.


  • Cart removed mid-phase without a Hot Swap prompt. Runtime treats this as an unsafe removal; phase chain still serializes, but Cipher voice surfaces an :anomalous event (“the deck remembers the removal”). On re-insert, runtime offers Resume from saved phase chain.
  • Cart with corrupted save file. Runtime falls back to a fresh save; original is renamed to <cart_id>.sav.corrupt and a Cipher event fires.
  • Cart whose .kn86 header references a missing capability. Header rejected at registration; cart stays in MOUNTED state. Bare deck terminal shows the error.
  • Multiple inserts/removes in rapid succession. udev event coalescing in the runtime: each MOUNTED → UNMOUNTING transition must complete before the next event is processed.
  • Power-off during ACTIVE. Low-voltage interrupt drives the same UNMOUNTING sequence with a tightened budget. Phase chain preservation takes priority over save flushing.