# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Status

Pre-implementation. The repo currently contains **only the spec** — `DOCS/MAIN.md` (spacesh tech spec v0.1, in Russian). No source code, no `Cargo.toml`, no git history yet. Read `DOCS/MAIN.md` first; it is the single source of truth for what to build and why. When writing code, follow the crate layout, protocol, and milestones it fixes.

## What spacesh is

A terminal-workspace for running multiple AI agents (Claude Code, Codex, Gemini, opencode, shell) in parallel on macOS. Architecture: a **backend daemon (`spaceshd`) owns the live PTY sessions**; the Tauri GUI and the `spacesh` CLI are thin clients that talk to it over one Unix-domain socket (`~/.spacesh/sock`). The daemon outliving the GUI is the core design bet — killing/updating the GUI must not kill a running agent.

## Architecture invariants

These are load-bearing decisions from the spec — do not violate them when implementing:

- **Daemon is the single source of truth.** GUI and CLI hold no state; they only send commands and subscribe to events. A click in the GUI and `spacesh focus s_8f3` from a script are the *same* `focus` command — never duplicate operational logic between GUI and CLI.
- **One socket, one protocol.** Length-prefixed (`u32` BE + payload) JSON frames over async UDS (tokio). Envelope has three kinds: `req` (client→daemon, correlated by `id`), `res` (daemon→client, by `id`), `evt` (daemon→subscribers, push, no id). Serialization is isolated in `spacesh-proto` so JSON→MessagePack is a localized swap.
- **Hybrid terminal parsing.** One PTY byte stream fans out to: (1) GUI `output` event → xterm.js renders; (2) `alacritty_terminal` grid in the daemon = authoritative screen model, used for status detection, scrollback search, OSC 133 last-command extraction, and reattach snapshots. The grid IS the snapshot source — no separate ring buffer. Display (xterm.js) and analysis (alacritty grid) are deliberately split.
- **Reattach via snapshot.** On `attach`, daemon serializes the current grid → ANSI dump → GUI writes it into a fresh xterm.js instance for instant repaint, then live `output` follows. This is how the daemon architecture solves screen restoration.
- **Status is pushed, not guessed.** State arrives as a `set_state` command (from agent hooks calling `spacesh notify`, OSC 133 for shells, pattern-matching fallback last). States: `work | wait | done | error | idle`. `$SPACESH_SURFACE_ID` is injected into each panel's env at spawn so hooks know which surface they report on.
- **Extend through the bus.** New features = new commands/events/subscribers (e.g. Telegram/MAX notifications are a subscriber *inside* `spaceshd` listening to `state`/`exit`). The spine does not move.

## Planned code structure

Cargo workspace + Tauri app (per spec §10):

```
crates/
  spacesh-proto/   # protocol types, serde, length-prefix framing — shared by all
  spacesh-core/    # workspace/split model, alacritty_terminal grid, status engine — NO I/O, unit-testable
  spacesh-pty/     # PTY spawn/io (portable-pty), reader-loop, batching, resize, backpressure
  spaceshd/        # daemon: owns sessions, hosts socket, event fan-out, layout persist, launchd, notification subscribers
  spacesh-cli/     # thin socket client (clap)
app/
  src-tauri/       # Rust: socket client + bridge into webview (tauri 2)
  src/             # React/TS front (TerminalView, LayoutEngine, Sidebar, EventCenter, Wizard, Settings, socketBridge)
```

`spacesh-core` is deliberately I/O-free so the domain model and status engine are unit-testable in isolation.

## Build / run (once the workspace exists)

No build files exist yet. After scaffolding, the conventional commands will be:

```bash
cargo build                      # build all crates
cargo test                       # run all Rust tests
cargo test -p spacesh-core       # test one crate
cargo test -p spacesh-core <name># run a single test by name filter
cargo run -p spaceshd            # start the daemon
cargo run -p spacesh-cli -- status --json
cd app && npm install && npm run tauri dev   # GUI dev (Tauri 2)
```

Verify the actual scripts against `Cargo.toml` / `app/package.json` once they are created — do not assume.

## Performance budgets (enforce in PTY/render paths)

- Keypress → echo: < 16 ms under normal load.
- PTY output batching: coalesce ~4–8 ms **or** ~16 KB, whichever first — never emit `output` per byte (a 50k-line build log must not yield 50k events).
- Backpressure: bounded per-subscriber channel; on overflow drop/coalesce frames for that client, but always keep the authoritative daemon grid up to date.
- Reattach repaint: < 100 ms on a typical grid.

## Implementation order (spec §12)

M0 live terminal through socket (vertical slice) → M1 persistence + reattach + launchd → M2 layouts/workspaces/presets → M3 statuses (hooks, OSC 133, fallback, notifications UI) → M4 CLI → M5 features (zoom, Telegram/MAX notifications, scrollback search, CodeMirror 6 diff view) → M6 (post-v1) remote via SSH-tunneled socket.

## Explicitly out of v1 scope

Token/limit accounting, legal/auth layer, embedded browser, full Monaco-class editor, agent-command guardrails. "Modifications" = external notifications (Telegram + MAX) only. Don't build these unless the scope decision is revisited.

## Conventions

Per the user's global rules: English for all code, comments, and docs; camelCase vars/functions, PascalCase types, snake_case files/dirs, UPPER_CASE env vars. No hard-coded values — use env/config (`~/.spacesh/config.toml`); tokens via `env:VAR` references, never plaintext. Spec prose and the docs in `DOCS/` are Russian; keep that, but code stays English.
