Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Architect solves this with a grid view that keeps all your agents visible, with
- **Recent folders** (⌘O) — quickly `cd` into recently visited directories with instant search filtering (start typing to narrow the list), substring highlighting, arrow key navigation, and ⌘1–⌘9 quick selection
- **Diff review comments** — click diff lines in the ⌘D overlay to leave inline comments with multiline wrapping, then send them all to a running agent (or start one) with the "Send to agent" button
- **Story viewer** — run `architect story <filename>` to open a scrollable overlay that renders PR story files with prose text and diff-colored code blocks
- **MCP session spawning** — run `architect-mcp` from an MCP client to ask the running Architect app to create a terminal session in a requested working directory
- **MCP session control** — run `architect-mcp` from an MCP client to ask the running Architect app to create a terminal session in a requested working directory (`spawn_session`) or close one and reclaim its slot (`close_session`)
- **Reader mode** (⌘R) — open a centered markdown reader for the selected terminal's history (works in full view and grid) with live updates, bottom pinning, incremental search (⌘F, Enter/Shift+Enter), markdown tables with inline cell styling (bold/italic/code/links/strikethrough), task checkboxes (emoji), clickable links, shared draggable scrollbar, and left-to-right gradient separators before command prompts (OSC 133 + fallback heuristics)

### Terminal Essentials
Expand Down Expand Up @@ -129,7 +129,7 @@ architect hook gemini

## MCP

`architect-mcp` is a stdio MCP server for local clients. It exposes one tool, `spawn_session`, which forwards the request to the running Architect app. It does not launch Architect by itself.
`architect-mcp` is a stdio MCP server for local clients. It exposes two tools, `spawn_session` and `close_session`, which forward the request to the running Architect app. It does not launch Architect by itself.

`spawn_session` arguments:
```json
Expand All @@ -142,6 +142,12 @@ architect hook gemini

`cwd` is required. `command` and `display_name` are optional. On success, the tool returns structured content with `status`, `session_id`, and `slot_index`. If Architect is not running, the grid is full, `cwd` is invalid, or spawning fails, the tool returns an MCP tool error with a stable `code` and `message`.

`close_session` is the inverse: it closes a terminal session and reclaims its grid slot (the same path as the close-pane keybinding, so the pane is removed rather than left dead). Pass exactly one identifier — the `session_id` returned by `spawn_session`, or a `slot_index`:
```json
{ "session_id": 12 }
```
On success it returns structured content with `status: "closed"` and the `session_id`. An unknown identifier returns an MCP tool error with code `not_found`.

For release downloads, use:
```bash
./Architect.app/Contents/MacOS/architect-mcp
Expand Down
22 changes: 12 additions & 10 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,31 +310,33 @@ Story notifications -> StoryOverlay opens with file content
Renderer draws attention border / story overlay
```

### External MCP Spawn Path
### External MCP Spawn / Close Path

```
MCP client
| launches architect-mcp over stdio
v
src/mcp/main.zig
| JSON-RPC initialize/tools/list/tools/call
| validates spawn_session arguments
| validates spawn_session / close_session arguments
v
app/control.zig
| scans per-instance discovery files in XDG_RUNTIME_DIR or stable per-user runtime dir
| connects to architect_control_<pid>.sock
| spawn requests omit "op"; close requests carry "op":"close"
v
Control socket listener thread in the running app
| parses request and queues PendingSpawn
| parses request and queues PendingSpawn or PendingClose
| posts SDL wake event
v
app/runtime.zig main loop
| validates cwd, chooses or expands a grid slot
| calls SessionState.ensureSpawnedWithDir()
| queues optional command into pending_write
| spawn: validates cwd, chooses or expands a grid slot, ensureSpawnedWithDir()
| close: resolves the session by id/slot, then despawnSessionAtIndex()
| (same close + relayout path as the close-pane keybinding)
v
Control response
| status + session_id + slot_index, or stable error code
| spawn: status + session_id + slot_index, or stable error code
| close: status + session_id, or stable error code (e.g. not_found)
v
architect-mcp MCP tool result
```
Expand Down Expand Up @@ -364,7 +366,7 @@ Rotate: rename active file to architect-<UTC timestamp>.log and continue in new
| SDL event queue | Keyboard, mouse, window events | Primary user interaction |
| PTY read | Shell process stdout/stderr | Terminal content updates |
| Unix domain socket | External AI tools | Status notifications (JSON) |
| Unix domain socket | `architect-mcp` | Local `spawn_session` control requests |
| Unix domain socket | `architect-mcp` | Local `spawn_session` / `close_session` control requests |
| Config files | `~/.config/architect/` | Startup configuration and persistence |

### Storage
Expand Down Expand Up @@ -395,9 +397,9 @@ Rotate: rename active file to architect-<UTC timestamp>.log and continue in new
| Module | Responsibility | Public API (key functions/types) | Dependencies |
|--------|---------------|----------------------------------|--------------|
| `main.zig` | Thin entrypoint + global logging hook registration | `main()`, `std_options.logFn` | `app/runtime`, `logging` |
| `mcp/main.zig` | Separate `architect-mcp` stdio MCP server. Handles JSON-RPC lifecycle methods and exposes the single `spawn_session` tool. | `main()`, `run()` | `app/control` module import, std |
| `mcp/main.zig` | Separate `architect-mcp` stdio MCP server. Handles JSON-RPC lifecycle methods and exposes the `spawn_session` and `close_session` tools. | `main()`, `run()` | `app/control` module import, std |
| `app/runtime.zig` | Application lifetime, frame loop, session spawning, config persistence, logging lifecycle/view-transition markers | `run()`, frame loop internals | `platform/sdl`, `session/state`, `render/renderer`, `ui/root`, `config`, `logging`, all `app/*` modules |
| `app/control.zig` | Local control channel shared by the app and `architect-mcp`: spawn request schema, discovery file, Unix socket listener, request queue, and response serialization | `SpawnRequest`, `SpawnResponse`, `SpawnQueue`, `startControlThread()`, `connectAndSendSpawnRequest()` | std (socket, thread, JSON) |
| `app/control.zig` | Local control channel shared by the app and `architect-mcp`: spawn/close request schemas, discovery file, Unix socket listener, request queues, and response serialization. Close requests are discriminated on the wire by `"op":"close"`. | `SpawnRequest`, `SpawnResponse`, `SpawnQueue`, `CloseRequest`, `CloseResponse`, `CloseQueue`, `startControlThread()`, `connectAndSendSpawnRequest()`, `connectAndSendCloseRequest()` | std (socket, thread, JSON) |
| `app/terminal_history.zig` | Extract focused terminal scrollback + viewport text, strip ANSI escape sequences, convert OSC 133 prompt markers into reader-friendly prompt marker lines, and extract agent session IDs from PTY output for resumption | `extractSessionText()`, `extractTerminalText()`, `stripAnsiAlloc()`, `extractAgentSessionId()`, `buildResumeCommand()` | `session/state`, `ghostty-vt`, std |
| `app/*` (app_state, layout, ui_host, grid_nav, grid_layout, input_keys, input_text, terminal_actions, worktree) | Application logic decomposed by concern: state enums, grid sizing, UI snapshot building, navigation, input encoding, clipboard, worktree commands (with configurable external directory and post-create init) | `ViewMode`, `AnimationState`, `SessionStatus`, `buildUiHost()`, `applyTerminalResize()`, `encodeKey()`, `paste()`, `clear()`, `resolveWorktreeDir()` | `geom`, `anim/easing`, `ui/types`, `ui/session_view_state`, `colors`, `input/mapper`, `session/state`, `c` |
| `platform/sdl.zig` | SDL3 initialization, window management, HiDPI | `init()`, `createWindow()`, `createRenderer()` | `c` |
Expand Down
51 changes: 49 additions & 2 deletions docs/ai-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Architect exposes a Unix domain socket to let external tools (Claude Code, Codex, Gemini CLI, etc.) signal UI states.

Architect also ships `architect-mcp`, a separate stdio MCP helper that lets local MCP clients ask the running app to create new terminal sessions.
Architect also ships `architect-mcp`, a separate stdio MCP helper that lets local MCP clients ask the running app to create new terminal sessions and close existing ones.

## Socket Protocol

Expand All @@ -17,9 +17,12 @@ Examples:
{"session": 0, "state": "done"}
```

## MCP tools

`architect-mcp` is launched by an MCP client as a stdio server. It exposes two tools, `spawn_session` and `close_session`, and forwards each call to the running Architect app through a local Unix-domain control socket. The helper is not a daemon and does not launch the GUI app if Architect is not already running.

## MCP `spawn_session`

`architect-mcp` is launched by an MCP client as a stdio server. It exposes exactly one tool, `spawn_session`, and forwards each call to the running Architect app through a local Unix-domain control socket. The helper is not a daemon and does not launch the GUI app if Architect is not already running.

The running app writes a per-instance discovery file named `architect_control_<uid>_<pid>.json` under `XDG_RUNTIME_DIR` when that is set. Otherwise it uses a stable per-user runtime directory: `~/Library/Caches/Architect/runtime` on macOS, or `~/.cache/architect/runtime` on other platforms. The app logs the full discovery file path together with the socket path. When several Architect instances are running, `architect-mcp` tries the newest reachable discovery entry.

Expand Down Expand Up @@ -81,6 +84,50 @@ Tool errors use stable codes:
- `invalid_cwd`: `cwd` is not an absolute existing directory
- `spawn_failed`: Architect accepted the request but could not create or initialize the terminal session

## MCP `close_session`

The inverse of `spawn_session`: it asks the running app to close a terminal session and reclaim its grid slot, driving the same close/relayout path as the close-pane keybinding (the shell is terminated and the pane is removed — not left as a dead, unresponsive pane). Provide exactly one identifier.

Input schema:

```json
{
"type": "object",
"additionalProperties": false,
"properties": {
"session_id": {
"type": "integer",
"description": "The session id returned by spawn_session. Provide this or slot_index."
},
"slot_index": {
"type": "integer",
"description": "The grid slot index to close. Provide this or session_id."
}
}
}
```

Example tool arguments:

```json
{ "session_id": 12 }
```

Successful calls return MCP structured content like:

```json
{
"status": "closed",
"session_id": 12
}
```

Tool errors use the same stable codes, plus:

- `invalid_request`: the MCP arguments do not match the schema (e.g. no identifier was provided)
- `not_found`: no session matches the requested `session_id` / `slot_index`
- `app_not_running`: no running Architect app accepted the local control request

## Built-in Command (inside Architect terminals)

Architect injects a small `architect` command into each shell's `PATH`. It reads the
Expand Down
Loading