Welcome to the Spettro macOS app documentation. This is a native SwiftUI
desktop client that wraps the spettro command-line agent and drives it
over the Agent Client Protocol (ACP).
- Overview — what Spettro is, what it isn't, and the one-paragraph mental model
- Project layout — the directory tree, the Xcode project, and the dependency graph
- Building and running — prerequisites, the
CLI, the dev binary, and the day-to-day
defaultsworkarounds - Architecture overview — the runtime topology, the lifecycle state machine, and the data flow between layers
- App lifecycle and phases —
Phase,bootstrap, install flow, project picker, failure recovery - The AppModel (root coordinator) — the single source of truth: sessions, config, permissions, agent restarts, persistence
- ACP connection layer —
ACPConnection, JSON-RPC framing, the subprocess, callbacks - ACP agent façade —
ACPAgent, all ACP methods, session/resume semantics, parameter encoding - ACP protocol types — content blocks, config options, tool calls, plan/usage, permissions
- JSONValue / RPCID — the dependency-free dynamic JSON type that backs the protocol layer
- Chat session model —
ChatSession, transcript mutation, replay suppression, pending config changes - Transcript models —
ChatMessage,ToolCallItem,TranscriptItem, presentation derivations - Session persistence —
SessionStore,StoredSession, codable mapping, JSON file location - Image attachments — downsampling, JPEG re-encoding, paste and file import
- Memory files — user and project memory, the on-disk format, scope resolution
- Subscription store — reading
~/.spettro/ config.json, thePlanenum, file-system watcher, the rainbow MAX badge - Terminal drawer — SwiftTerm panels, per-project scoping, tab persistence, the resizable drawer
- Design system —
Theme,CardBackground,GlassEffectContainerusage, semantic colors - Preview support —
DEBUG-only mock data, every preview factory
- ContentView and routing —
Phaseswitch,LoadingView,FailureView, sheets - Sidebar —
SidebarView, project sections, archived, search, pin/archive context menu - Chat view and header —
ChatView,ChatHeaderView, plan/context/git chips,GitStatModel - Transcript rendering —
TranscriptItemView, user/assistant/reasoning/notice bubbles, sub-agent cards, typing dots - Tool calls and diffs —
ToolCallView,SubAgentCallView,ToolDiffView, the+N/-Nstat label - Composer —
ComposerView, slash-command palette, image attachments, send/stop, terminal toggle - Config bar —
ConfigBar, data-driven config options rendered as glass chips - Project picker —
ProjectPickerView, the home screen - Onboarding —
OnboardingView, install automatically / choose existing, install log - Settings —
SettingsView, account, CLI path, project folder, memory editor entry point - Permission sheet —
PermissionSheet, keyboard shortcuts, allow/reject mapping - Markdown rendering —
MarkdownText, chunking strategy, code blocks, copy-to-clipboard - Memory editor —
MemoryView, scope picker, save/revert, inline write-failure surface - Question sheet —
QuestionSheet, the ask-user form: multi-question tabs, single/multi select, free text, notes, previews
- SwiftPM dependencies — every pinned package, where it's used
- Build settings reference —
MACOSX_DEPLOYMENT_TARGET, signing, bundle id, Info.plist keys - UserDefaults keys — every key the app reads or writes, plus the CLI config keys it mirrors
- On-disk file map — Application Support, home directory, project folder: what lives where
- Spettro Remote protocol — the wire protocol
between the iPhone/iPad app and a host, pairing, and the spec the Go
/remotehost is to be written against - CLI ↔ App contract — the ACP
surface Spettro expects from
spettro --acp
Spettro.app is a SwiftUI macOS front-end that doesn't ship any AI
itself. (There is now a second target, SpettroMobile for iPhone and
iPad, which ships no AI and no agent: it drives the Mac over the local
network — see Spettro Remote protocol.) It locates a spettro CLI binary on disk, spawns it as
spettro --acp --cwd <folder>, and talks to it over newline-framed JSON-RPC
2.0 on stdio. Every chat, every tool call, every streamed token arrives as a
notification; every prompt and config change is a request. The app owns the
display transcript, the per-session config UI, the project sidebar, a
terminal drawer, and a memory file editor; the CLI owns the model, the
agent loop, the file edits, and its own cross-turn memory. The two pieces
are linked by ACP and nothing else.
If you're new here, start with Overview, then jump to Architecture overview.