# elrincondeldev/perch architecture

> Architecture diagram of the GitHub repository elrincondeldev/perch, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-11-11). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/elrincondeldev/perch
- Repository: https://github.com/elrincondeldev/perch

## Overview

Perch turns Claude Code hook events and agent polling into persisted session state, sends updates over a token-protected WebSocket, and presents each session as an interactive creature in a macOS overlay. Users can browse the desktop session library, pin sessions, customize icons, and open sessions in Claude Desktop. The graph includes the documented optional LAN/Pi connection and focus tracking. Some module links rely on the README or SOURCE INDEX; unsampled implementation details are not inferred.

Main entry points: [`agent/src/server.ts`](https://github.com/elrincondeldev/perch/blob/main/agent/src/server.ts) (Hook and panel servers), [`Sources/PerchOverlay/StripController.swift`](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/StripController.swift) (Strip interaction), [`Sources/PerchOverlay/AgentLink.swift`](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/AgentLink.swift) (Agent WebSocket link), [`agent/src/hub.ts`](https://github.com/elrincondeldev/perch/blob/main/agent/src/hub.ts) (Session hub)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_agent["Agent runtime"]
  node_agent_entry["Agent startup<br/>[agent.ts]"]
  node_hook_server["Hook and panel servers<br/>[server.ts]"]
  node_session_state["Session state rules<br/>[state.ts]"]
  node_session_hub["Session hub<br/>[hub.ts]"]
  node_sqlite_store[("SQLite session store<br/>[store.ts]")]
  node_agent_poller["Claude agent poller<br/>[poller.ts]"]
  node_desktop_library["Desktop session library"]
  node_open_session["Open session<br/>[open-session.ts]"]
  node_focus_tracker["Desktop focus tracker<br/>[desktop-focus.ts]"]
  node_agent_config["Agent configuration<br/>[config.ts]"]
end

subgraph group_overlay["macOS overlay"]
  node_overlay_entry["Overlay startup<br/>[main.swift]"]
  node_agent_link["Agent WebSocket link<br/>[AgentLink.swift]"]
  node_strip_controller["Strip interaction"]
  node_strip_view["Creature strip view<br/>[StripView.swift]"]
  node_sprite_rendering["Sprite rendering<br/>[Sprite.swift]"]
  node_character_templates["Character templates"]
  node_strip_layout["Strip layout<br/>[StripLayout.swift]"]
  node_hover_label["Hover status label<br/>[HoverLabel.swift]"]
  node_creature_menu["Creature menu<br/>[CreatureMenu.swift]"]
  node_menu_bar["Menu bar controls<br/>[MenuBar.swift]"]
end

subgraph group_contract["Shared protocol"]
  node_protocol["Client-server contract<br/>[protocol.ts]"]
end

node_user(("Perch user"))
node_claude_code["Claude Code"]
node_desktop_app["Claude Desktop"]
node_pi_panel["Pi panel"]

node_user -->|"interacts with"| node_strip_controller
node_claude_code -->|"posts hook events"| node_hook_server
node_agent_entry -->|"starts"| node_hook_server
node_agent_entry -->|"starts"| node_agent_poller
node_hook_server -->|"handles events"| node_session_hub
node_agent_poller -->|"reconciles sessions"| node_session_hub
node_session_hub -->|"applies state rules"| node_session_state
node_session_hub -->|"persists state and pins"| node_sqlite_store
node_hook_server -->|"lists sessions"| node_desktop_library
node_hook_server -->|"opens requested session"| node_open_session
node_desktop_app -->|"provides session metadata"| node_desktop_library
node_agent_entry -->|"tracks focus"| node_focus_tracker
node_focus_tracker -->|"updates focused session"| node_session_hub
node_agent_config -.->|"configures agent endpoints"| node_hook_server
node_hook_server -->|"exchanges messages"| node_protocol
node_pi_panel -.->|"connects optionally"| node_hook_server
node_overlay_entry -->|"starts connection"| node_agent_link
node_agent_link -->|"exchanges WebSocket messages"| node_hook_server
node_agent_link -->|"parses and sends messages"| node_protocol
node_agent_link -->|"supplies session updates"| node_strip_controller
node_strip_controller -->|"renders appearances"| node_strip_view
node_strip_controller -->|"computes layout and hits"| node_strip_layout
node_strip_controller -->|"positions status label"| node_hover_label
node_strip_controller -->|"creates session menus"| node_creature_menu
node_strip_view -.->|"draws creatures"| node_sprite_rendering
node_sprite_rendering -.->|"uses templates"| node_character_templates
node_menu_bar -->|"reads agent status"| node_agent_link
node_menu_bar -->|"controls strip"| node_strip_controller

click node_agent_entry "https://github.com/elrincondeldev/perch/blob/main/agent/src/agent.ts"
click node_hook_server "https://github.com/elrincondeldev/perch/blob/main/agent/src/server.ts"
click node_session_state "https://github.com/elrincondeldev/perch/blob/main/agent/src/state.ts"
click node_session_hub "https://github.com/elrincondeldev/perch/blob/main/agent/src/hub.ts"
click node_sqlite_store "https://github.com/elrincondeldev/perch/blob/main/agent/src/store.ts"
click node_agent_poller "https://github.com/elrincondeldev/perch/blob/main/agent/src/poller.ts"
click node_desktop_library "https://github.com/elrincondeldev/perch/blob/main/agent/src/desktop-sessions.ts"
click node_open_session "https://github.com/elrincondeldev/perch/blob/main/agent/src/open-session.ts"
click node_focus_tracker "https://github.com/elrincondeldev/perch/blob/main/agent/src/desktop-focus.ts"
click node_agent_config "https://github.com/elrincondeldev/perch/blob/main/agent/src/config.ts"
click node_protocol "https://github.com/elrincondeldev/perch/blob/main/shared/protocol.ts"
click node_overlay_entry "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/main.swift"
click node_agent_link "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/AgentLink.swift"
click node_strip_controller "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/StripController.swift"
click node_strip_view "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/StripView.swift"
click node_sprite_rendering "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchCore/Sprites/Sprite.swift"
click node_character_templates "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchCore/Sprites/CharacterTemplate.swift"
click node_strip_layout "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchCore/StripLayout.swift"
click node_hover_label "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/HoverLabel.swift"
click node_creature_menu "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/CreatureMenu.swift"
click node_menu_bar "https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/MenuBar.swift"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_agent_entry,node_hook_server,node_session_state,node_session_hub,node_sqlite_store,node_agent_poller,node_desktop_library,node_open_session,node_focus_tracker,node_agent_config,node_user toneBlue
class node_overlay_entry,node_agent_link,node_strip_controller,node_strip_view,node_sprite_rendering,node_character_templates,node_strip_layout,node_hover_label,node_creature_menu,node_menu_bar toneAmber
class node_protocol toneMint
class node_claude_code,node_desktop_app,node_pi_panel toneIndigo
```

## Components

### Agent runtime

- [Agent startup](https://github.com/elrincondeldev/perch/blob/main/agent/src/agent.ts): `agent/src/agent.ts`
- [Hook and panel servers](https://github.com/elrincondeldev/perch/blob/main/agent/src/server.ts): `agent/src/server.ts`
- [Session state rules](https://github.com/elrincondeldev/perch/blob/main/agent/src/state.ts): `agent/src/state.ts`
- [Session hub](https://github.com/elrincondeldev/perch/blob/main/agent/src/hub.ts): `agent/src/hub.ts`
- [SQLite session store](https://github.com/elrincondeldev/perch/blob/main/agent/src/store.ts): `agent/src/store.ts`
- [Claude agent poller](https://github.com/elrincondeldev/perch/blob/main/agent/src/poller.ts): `agent/src/poller.ts`
- [Desktop session library](https://github.com/elrincondeldev/perch/blob/main/agent/src/desktop-sessions.ts): `agent/src/desktop-sessions.ts`
- [Open session](https://github.com/elrincondeldev/perch/blob/main/agent/src/open-session.ts): `agent/src/open-session.ts`
- [Desktop focus tracker](https://github.com/elrincondeldev/perch/blob/main/agent/src/desktop-focus.ts): `agent/src/desktop-focus.ts`
- [Agent configuration](https://github.com/elrincondeldev/perch/blob/main/agent/src/config.ts): `agent/src/config.ts`

### macOS overlay

- [Overlay startup](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/main.swift): `Sources/PerchOverlay/main.swift`
- [Agent WebSocket link](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/AgentLink.swift): `Sources/PerchOverlay/AgentLink.swift`
- [Strip interaction](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/StripController.swift): `Sources/PerchOverlay/StripController.swift`
- [Creature strip view](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/StripView.swift): `Sources/PerchOverlay/StripView.swift`
- [Sprite rendering](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchCore/Sprites/Sprite.swift): `Sources/PerchCore/Sprites/Sprite.swift`
- [Character templates](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchCore/Sprites/CharacterTemplate.swift): `Sources/PerchCore/Sprites/CharacterTemplate.swift`
- [Strip layout](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchCore/StripLayout.swift): `Sources/PerchCore/StripLayout.swift`
- [Hover status label](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/HoverLabel.swift): `Sources/PerchOverlay/HoverLabel.swift`
- [Creature menu](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/CreatureMenu.swift): `Sources/PerchOverlay/CreatureMenu.swift`
- [Menu bar controls](https://github.com/elrincondeldev/perch/blob/main/Sources/PerchOverlay/MenuBar.swift): `Sources/PerchOverlay/MenuBar.swift`

### Shared protocol

- [Client-server contract](https://github.com/elrincondeldev/perch/blob/main/shared/protocol.ts): `shared/protocol.ts`

### Other components

- **Perch user**
- **Claude Code**
- **Claude Desktop**
- **Pi panel**

## Connections

- Perch user → Strip interaction: interacts with
- Claude Code → Hook and panel servers: posts hook events
- Agent startup → Hook and panel servers: starts (evidence: `agent/src/agent.ts`)
- Agent startup → Claude agent poller: starts (evidence: `agent/src/agent.ts`)
- Hook and panel servers → Session hub: handles events (evidence: `agent/src/server.ts`)
- Claude agent poller → Session hub: reconciles sessions (evidence: `agent/src/poller.ts`)
- Session hub → Session state rules: applies state rules (evidence: `agent/src/hub.ts`)
- Session hub → SQLite session store: persists state and pins (evidence: `agent/src/hub.ts`)
- Hook and panel servers → Desktop session library: lists sessions (evidence: `agent/src/server.ts`)
- Hook and panel servers → Open session: opens requested session (evidence: `agent/src/server.ts`)
- Claude Desktop → Desktop session library: provides session metadata
- Agent startup → Desktop focus tracker: tracks focus (evidence: `agent/src/agent.ts`)
- Desktop focus tracker → Session hub: updates focused session (evidence: `agent/src/desktop-focus.ts`)
- Agent configuration → Hook and panel servers: configures agent endpoints
- Hook and panel servers → Client-server contract: exchanges messages (evidence: `shared/protocol.ts`)
- Pi panel → Hook and panel servers: connects optionally
- Overlay startup → Agent WebSocket link: starts connection (evidence: `Sources/PerchOverlay/main.swift`)
- Agent WebSocket link → Hook and panel servers: exchanges WebSocket messages
- Agent WebSocket link → Client-server contract: parses and sends messages (evidence: `Sources/PerchOverlay/AgentLink.swift`)
- Agent WebSocket link → Strip interaction: supplies session updates (evidence: `Sources/PerchOverlay/StripController.swift`)
- Strip interaction → Creature strip view: renders appearances (evidence: `Sources/PerchOverlay/StripController.swift`)
- Strip interaction → Strip layout: computes layout and hits (evidence: `Sources/PerchOverlay/StripController.swift`)
- Strip interaction → Hover status label: positions status label (evidence: `Sources/PerchOverlay/StripController.swift`)
- Strip interaction → Creature menu: creates session menus (evidence: `Sources/PerchOverlay/StripController.swift`)
- Creature strip view → Sprite rendering: draws creatures
- Sprite rendering → Character templates: uses templates (evidence: `Sources/PerchCore/Sprites/Sprite.swift`)
- Menu bar controls → Agent WebSocket link: reads agent status (evidence: `Sources/PerchOverlay/MenuBar.swift`)
- Menu bar controls → Strip interaction: controls strip (evidence: `Sources/PerchOverlay/MenuBar.swift`)
