Architecture
Module Overview
Namu is organized around four main code areas with clear boundaries:
| Area | Directory | Purpose |
|---|---|---|
| NamuKit | NamuKit/ |
Core logic. Domain models, Ghostty FFI, IPC, relay, services, alerting, browser, remote. No SwiftUI imports. |
| NamuUI | NamuUI/ |
SwiftUI and AppKit views. App entry point, workspace rendering, browser views, settings, notifications, update UI. |
| CLI | CLI/ |
The namu command-line client plus tmux compatibility, Claude hooks, Codex hooks, ref ID resolution, and helper entry points. |
| Remote Helper | daemon/remote/ |
Go daemon providing 12 RPC methods for remote session management, PTY resize, SOCKS5/HTTP CONNECT proxy, and stream multiplexing. |
NamuKit Internals
| Subdirectory | Responsibility |
|---|---|
Domain/ | Core value types: Workspace, Panel, PaneTree, session snapshots, WorkspaceRemoteConfiguration, and workspace placement settings. |
Terminal/ | Ghostty bridge/config/keyboard wrappers, TerminalSurfaceRegistry (pointer safety), PortalHostLease system, session lifecycle, CJK IME, dictation, middle-click paste, shell integration, copy mode, image transfer (Kitty + SCP), SSH detection, and ZDOTDIR overlay. |
IPC/ | SocketServer, RelayServer (TCP with HMAC-SHA256), command registry/dispatcher, access control, event bus, command namespaces, middleware, and password auth. |
Services/ | Workspace/panel managers, persistence, notifications (status/progress/log APIs), layout, appearance, analytics, PortScanner (batched ps+lsof), project config watcher, and app coordination. |
Alerting/ | Outbound channel delivery for Slack, Telegram, Discord, and generic webhook with rate limiting and credential security. |
Browser/ | BrowserProfileStore, BrowserHistoryStore, browser models, MarkdownPanel with file watching, 84+ browser command handlers, network tracing, and proxy configuration. |
Remote/ | RemoteSessionController, DaemonRPCClient, RemoteProxyBroker, RemoteProxyTunnel, and CLI relay server for SSH remote workspaces. |
Debug/ | Keystroke latency profiling (TypingTiming, 34 instrumentation points always compiled in). |
Scripting/ | AppleScript support (4 classes, 11 commands via SDEF). |
Config/ | Project configuration, directory trust, config hot-reload, and command execution. |
Dependency Graph
NamuUI
|
+---> NamuKit
| |
| +---> Domain
| +---> Terminal (Ghostty C FFI)
| +---> IPC (socket + relay + command dispatch)
| +---> Services (workspace, panel, notifications, config watcher)
| +---> Alerting
| +---> Browser (84+ commands, network tracing)
| +---> Remote (SSH orchestration, proxy broker)
|
+---> AppKit (hosting, overlays, browser integration)
CLI ---> Unix Socket ---> NamuKit/IPC
\-> Short ref IDs resolved locally before RPC
daemon/remote ---> TCP relay ---> RelayServer ---> CommandDispatcher
Runtime Flows
Keyboard Input
NSEvent
--> AppKit routing
--> performKeyEquivalent
--> keyDown
--> interpretKeyEvents (NSTextInputClient, CJK IME, dictation)
--> GhosttyKeyboard
--> Ghostty surface
Local Socket Command
CLI / automation client
--> SocketServer (access control + optional password auth)
--> CommandDispatcher
--> CommandRegistry
--> namespace handler
--> manager / service / terminal
SSH Remote Workspace
namu ssh user@host
--> RemoteSessionController
--> SSH process (BatchMode, ServerAliveInterval, ControlSocket)
--> DaemonRPCClient (hello + capability negotiation)
--> daemon binary (SHA256-verified, provisioned on demand)
--> session.attach / session.resize / session.detach
--> proxy.socks5 / proxy.http_connect (browser traffic)
--> CLIRelayServer (HMAC-SHA256 local socket)
--> forwarded commands via SSH tunnel to remote daemon
Alert Flow
EventBus event (process.exit | output.match | port.change | shell.idle)
--> AlertEngine (4 trigger types)
--> AlertRouter
--> Slack / Telegram / Discord / Webhook channel
--> outbound API delivery
Sidebar Notification APIs
CLI: namu sidebar set_status / set_progress / log
--> SocketServer
--> SidebarStatusCommands / SidebarLogCommands
--> WorkspaceManager
--> SidebarMetadata update
--> SwiftUI sidebar re-render (colored pills, progress bar, log entries)
Remote Relay Flow
Remote helper / forwarded client
--> RelayServer (TCP with HMAC-SHA256 constant-time verification)
--> Access control check
--> CommandDispatcher
--> JSON-RPC handler
--> response sent over relay socket
Port Scanner Flow
Background timer
--> PortScanner (batched ps+lsof)
--> coalesce + burst detection
--> port.change event published
--> EventBus subscribers notified
--> NAMU_PORT / NAMU_PORT_RANGE env vars updated per workspace
Key Design Decisions
Clean Architecture
Namu uses proven patterns — Ghostty embedding, socket namespaces, layout persistence, portal-style UI coordination — with a modular codebase. The main architectural goal is to avoid god objects and keep responsibilities narrow and testable.
Folder-Based Modules in a Single App Target
Most of the app builds as a single Xcode target organized by directory, rather than as many Swift packages. That keeps build complexity low while the architecture is still settling.
NamuKit Avoids UI Imports
Core logic lives in NamuKit and avoids SwiftUI/UIKit imports. The main
exception is AppKit where Ghostty surface hosting requires it.
TerminalBackend Boundary
TerminalBackend defines the abstraction boundary while
TerminalSession is the concrete Ghostty-backed implementation. Session
lifecycle is modeled explicitly through SessionState.
Immutable PaneTree
Layout state is modeled as an indirect enum. Operations return new trees instead of mutating nested nodes, which keeps persistence and snapshotting simple.
Focus Policy
Only workspace.select and pane.focus are allowed to steal
focus. All other commands preserve the current user focus state unless
--no-focus is passed.
Short Ref IDs
All list responses include a ref field alongside id.
The CLI resolves workspace:1, pane:2, and
surface:3 notation locally before sending RPCs, so scripts do not
need to track full UUIDs.
Security Model
The relay uses CryptoKit constant-time HMAC comparison to prevent timing attacks. The proxy tunnel blocks 169.254.169.254 (cloud metadata SSRF). Daemon binary manifests are path-traversal checked before download. Relay and proxy response sizes are capped (1MB and 64KB respectively).
Performance Targets
| Metric | Target | Measurement |
|---|---|---|
| Typing latency (p99) | < 5ms | Ghostty/keyboard-path instrumentation in debug builds |
| Socket command (read) | < 10ms | Dispatcher entry/exit timing |
| Socket command (write) | < 50ms | Dispatcher entry/exit timing |
| Alert routing | < 3s | AlertEngine emit to channel API response |
| Session restore | < 2s | Launch to rendered surfaces |