# How it works

Pneuma is four layers with clear contract boundaries. The agent edits files, the server watches for changes, and the browser renders the result — a continuous loop of creation.

## Architecture layers

Layer 4 Mode Protocol — ModeManifest declares the skill, viewer config, agent preferences, and init parameters
Layer 3 Content Viewer — ViewerContract defines how to render, select elements, and extract context for the agent
Layer 2 Agent Bridge — AgentBackend handles launch, resume, kill, and capability declaration
Layer 1 Runtime Shell — HTTP server, dual WebSocket, file watcher, PTY terminal, and frontend

## Session lifecycle

From `bunx pneuma-skills slide` to a live preview loop — eight steps, fully automated.

1

### Resolve mode

The CLI resolves the mode specifier — builtin name, local path, GitHub repo, or URL — to a directory on disk containing `manifest.ts`.

2

### Load manifest

The manifest is dynamically imported, providing skill config, viewer setup, agent preferences, and init parameters as a typed `ModeManifest` object.

3

### Session setup

A session is created or resumed from `.pneuma/session.json` in the workspace. Message history, config, and agent state persist across runs.

4

### Install skill

Skill files are copied to the workspace and template parameters applied. A `claudeMdSection` is injected into `CLAUDE.md` so the agent discovers its capabilities natively.

5

### Start server

The Hono server starts with dual WebSocket channels — one for the browser (JSON), one for the CLI (NDJSON) — plus REST APIs for files, git, and system ops.

6

### Launch agent

Claude Code is spawned via `Bun.spawn` with the `--sdk-url` flag pointing to the CLI WebSocket endpoint. The agent connects and begins its session.

claude --sdk-url ws://localhost:17996/ws/cli/SESSION --print --output-format stream-json
7

### Load viewer

The frontend dynamically imports the mode's viewer component. External modes are compiled at runtime via `Bun.build()` and loaded through an import map.

8

### Preview loop

The agent edits files. Chokidar detects changes and pushes updates via WebSocket. The browser re-renders instantly. The user selects, guides, and the agent responds — a continuous loop.

## Core contracts

Three typed interfaces define the extension points. Implement one to add a new mode, renderer, or agent backend.

Contract

### ModeManifest

Declares what a mode is — its skill prompt, viewer configuration, agent preferences, init parameters, and evolution directive.

Extend to → add new modes (canvas, mindmap, diagram…)
Contract

### ViewerContract

Defines how content is rendered, how elements are selected, and how context is extracted for the agent. Includes the workspace model and action protocol.

Extend to → custom renderers, viewports, action protocols
Contract

### AgentBackend

Handles agent lifecycle — launch, resume, kill — and declares capabilities. Currently implemented for Claude Code; designed for other backends.

Extend to → Codex CLI, Aider, custom agents

## Communication channels

The server maintains three real-time channels connecting the browser, the agent, and the terminal.

#### Browser channel

JSON messages for the React UI — chat messages, file updates, viewer actions, permission requests, and task progress.

/ws/browser/:sessionId

#### CLI channel

NDJSON messages for Claude Code's `--sdk-url` protocol — user messages enriched with viewer context, tool permissions, and agent responses.

/ws/cli/:sessionId

#### Terminal channel

Binary PTY stream for the integrated xterm.js terminal — full shell access within the workspace context.

/ws/terminal/:terminalId