Docs menu

Concepts

JoyMux architecture

JoyMux is a local execution runtime. Its canonical record is an append-only, per-session event stream plus normalized session state. Terminal rendering is an optional client concern and is never required for hidden sessions.

Boundaries

JoyMux owns process and PTY lifecycle, byte transport, event normalization, resource observation, persistence, replay, bounded retention, and local APIs. It does not plan agent work, select coding-agent models, verify missions, or import JoyMesh internals. A zero process exit code means only that the process exited normally.

JoyMux also owns a self-contained embedded intent layer that converts ordinary language into a validated ActionIntent before any JoyMesh call. That layer is not a coding harness and never executes shell commands. Production startup must not depend on Ollama. See embedded-inference.md.

Components

Adapters are intentionally below the daemon boundary. Future container and SSH adapters can implement the same lifecycle without changing the protocol.

Phase 2 harness boundary

Codex / any CLI harness
          |
vendor-neutral HarnessAdapter or Python SDK
          |
stable JoyMux v1 local API
          |
session actors -> subprocess / PTY adapters
          |
SQLite events + append-only raw evidence

Harness knowledge ends above the API. The runtime neither imports vendor packages nor branches on executable names.

State machine

created -> starting -> running <-> waiting_for_input
   |          |          |                |
   |          |          +-> cancelling <-+
   |          |          |       |
   |          |          |       +-> cancelled
   |          |          +-> completed
   |          |          +-> timed_out
   |          |          +-> failed
   |          +-> failed/timed_out/cancelling
   +-> cancelled

Every transition is validated. Terminal states are immutable. Exit/cancel races are serialized by the session actor; an observed natural exit wins if it is received before cancellation takes effect.

The exact transition table and recovery semantics are in state-machine.md.

Data flow and backpressure

Each session owns its process handles, sequence counter, bounded memory buffer, and broadcast channel. Process readers persist raw chunks before notifying subscribers. Slow subscribers may lag and must resume with ReadEvents after a known sequence. They never block process output. SQLite stores metadata and events; raw bytes are written to append-only per-session chunk files.

SQLite uses WAL mode, synchronous=FULL, a five-second busy timeout, and schema version validation. Each event and updated session sequence commit together. Restart recovery commits both terminal events and the failed state in one transaction. Raw bytes are fsynced before their chunk reference is inserted; a crash can leave unreferenced trailing bytes but not a reference to unwritten data.

Local security

The daemon binds only to a Unix socket created with owner-only permissions. Commands use direct exec by default; shell invocation is explicit. Working directories must exist and be directories. Environment names can be filtered, derived views can be redacted, and environment values are never persisted or logged. Raw evidence can contain secrets and must be protected accordingly.

Portability

The first implementation targets Linux and macOS-like Unix process semantics. Process groups and PTYs are adapter details. The only unsafe block is the Unix pre_exec hook that calls setsid() before direct execution so the daemon can signal the process group. Resource observation is best effort; observed_resource_usage is never represented as an enforced limit.