Architecture Overview
Spettro is a Go application with a Bubble Tea TUI front-end and internal service packages.
Entry point and runtime
cmd/spettro/main.goinitializes config, encrypted keys, provider manager, model catalog, manifest validation, and TUI.internal/tuiis the active runtime: command dispatch, dialogs, rendering, approval flows, and agent execution.- Project manifest loading is handled by
internal/config(LoadAgentManifestForProject).
Core packages
internal/tui: interactive terminal UI, command handling, approvals, and session interactions.internal/agent: LLM runtime loop, native tool-call execution, delegation, policy checks, and tool output spooling (large results fromfile-read,grep,shell-exec,web-fetchetc. are written to a session-scoped spool file with a truncated head and a pageable offset, so the model can retrieve the full content viajob-outputwithspool:NIDs).internal/config: config persistence, encrypted keys, trust list, manifest parsing/validation/migration.internal/provider: provider adapters, endpoint resolution, connected model routing, and Fantasy-backed text model execution with legacy SDK fallback for vision or legacy completion endpoints.internal/models: fetch/cache ofmodels.devcatalog.internal/session: persistent session storage (messages,tasks,agentsevents) and resume support.internal/storage: project/global.spettrodirectory setup.internal/hooks: global/project hook loading, merge, and execution.internal/compact: context usage policy and compaction guardrails.internal/workflow: the workflow script engine — a goja JavaScript runtime withagent/parallel/pipeline/phase/log/budgetglobals, an event loop that resolves agent promises from goroutines, meta-header parsing, structured-output validation, and the journal that makes a run resumable. It knows nothing about Spettro's agents: sub-agent execution arrives through aRunnerinterface (implemented ininternal/agent/workflow.go) and progress leaves through anObserver, so the engine is testable without a provider.internal/skills: Agent Skills discovery, parsing, install/uninstall, and prompt rendering. DiscoversSKILL.mdpacks from<cwd>/.spettro|.agents|.claude|.openai/skills/and~/.spettro|.agents|.claude|.openai/skills/so Claude Code and OpenAI skills work without conversion. See skills.md.
Agent manifest
Spettro loads spettro.agents.toml from project root when present; otherwise it uses built-ins.
See AGENTS.md for schema details (version = 2, [runtime], [[tools]], [[agents]], permissions, validation).
Execution flow
- User prompt enters current active agent (
planby default). - Agent emits native tool calls via the provider API (parallel-capable via multiple calls per response).
- Runtime executes allowed tools per manifest and permission policy.
- Plans can be queued and executed via
/approvethroughcoding. - Outputs, tool traces, and session events are appended to timeline/session storage.
Orchestration contract (orchestrators vs workers)
Spettro deliberately splits the agent roster into orchestrators (plan, coding, ask) and workers (explore, code, git, test, review, docs, general-purpose). The orchestration contract is:
- Orchestrators are coordinators. They decompose the user's request and spawn workers via the
agenttool, preferring parallel batches (the runtime allows up to 4 concurrent sub-agents per step). Their prompts inagents/planning.md,agents/coding.md, andagents/chat.mdenforce "delegate first". planis enforced at the manifest level: it has no direct read tools (glob/grep/file-read/ls). Discovery must go through anexploreworker. The corresponding contract tests live intests/config/manifest_test.go.codingkeeps its raw write/exec tools as an emergency escape hatch, but the prompt strongly discourages using them directly. The expected default path iscoding → {explore, docs}(parallel)→ code(impl)→ {test, review}(parallel)→ git.- Workers are individual contributors.
agents/code.mdis the dedicatedcodeworker prompt; the orchestrator-styleagents/coding.mdis used only by thecodingorchestrator. Workers do not re-delegate (andcodeis the only worker that has theagenttool, gated by handoffs). general-purposeis the fallback worker: every other worker covers one slice, so an open-ended subtask that mixes discovery, change, and verification had to be split by hand. It holds the read/write/execute surface those specialists split between them, and its prompt lives inagents/general-purpose.md.- The runtime's
agentdispatch already validates role + handoff compatibility (isDelegationRoleAllowedininternal/agent/llm_runtime_shell.go), so workers can't accidentally spawn an orchestrator.
Provider abstraction
- Text requests route through Charm's
fantasySDK foranthropic,openai, and OpenAI-compatible providers. - Image requests and legacy completion-only backends fall back to Spettro's direct SDK adapters so existing compatibility is preserved.
- Known provider base URLs and local endpoints still resolve through the same manager layer.
- Catalog-backed model lists are preferred; fallback models are used when catalog is unavailable.
