the reference

read the light.

A spectroscope tells you what light is made of without touching the source. This reference works the same way: every section below is extracted straight from the source tree, and each one names the file it came from. The RunEvents are the spectral lines, a run is the light they add up to, and the JSONL file on disk is the plate it is recorded on.

the facade

Extracted from Spectro.java; the example is the owner-frozen wording from SPECTRO-API.md.

var agent = Spectro.agent()
    .model(Anthropic.opus())
    .tools(Tools.readFile(), Tools.runCommand())
    .workspace(Path.of("/tmp/scratch"));

for (RunEvent event : agent.run("Write hello.py and run it")) {
    System.out.println(event);   // the stream IS the observability
}

the Python port is in design. The JSONL wire is the contract, so a stream recorded by either edition replays in the other.

agent()AgentThe five-lines facade — spectroscope's front door.
panel()FleetPanelThe fleet path — several agents, one merged spectrum — in exactly the facade's shape.
model(LlmProvider provider)AgentOne configured agent: setters chain, #run streams.
tools(Tool... tools)AgentThe tool belt the model may call.
workspace(Path workspace)AgentThe directory the file tools resolve and sandbox against.
systemPrompt(String systemPrompt)AgentReplaces the default unattended system prompt entirely.
run(String prompt)EventStreamRuns one prompt against the agent and hands back the live stream.

RunEvents (17)

The wire contract. Extracted verbatim from spectro-web/src/events.ts — the same union the TypeScript edition and the JSONL files share. The server additionally announces workspace_info on the socket (SessionConnection.java); consumers skip unknown types by contract.

run_start

runIdstring
agentIdstring
parentIdoptionalstring
promptstring
provideroptionalstring
attachmentsoptionalAttachmentRef[]
tsnumber

turn_start

agentIdstring
turnnumber
tsnumber

text_delta

agentIdstring
textstring
tsnumber

thinking_delta

agentIdstring
textstring
tsnumber

tool_call

agentIdstring
callIdstring
namestring
inputunknown
tsnumber

permission_request

agentIdstring
callIdstring
namestring
inputunknown
tsnumber

permission_decision

callIdstring
allowedboolean
tsnumber

tool_result

agentIdstring
callIdstring
outputstring
isErrorboolean
durationMsnumber
tsnumber

agent_spawn

agentIdstring
parentIdstring
taskstring
tsnumber

compaction

agentIdstring
removedTurnsnumber
summaryCharsnumber
tsnumber

usage

agentIdstring
inputTokensnumber
outputTokensnumber
cacheReadTokensoptionalnumber
cacheCreationTokensoptionalnumber
tsnumber

run_end

runIdstring
stopReasonstring
tsnumber

error

agentIdoptionalstring
messagestring
tsnumber

image_generated

agentIdstring
callIdstring
promptstring
providerstring
modelstring
mediaTypestring
blobPathstring
sha256string
tsnumber

context_info

agentIdstring
turnnumber
messagesnumber
estimatedTokensnumber
thresholdnumber
parts{ label: string; chars: number; estTokens: number }[]
tsnumber

agent_message

fromstring
tostring
rolestring
statestring
textstring
labeloptionalstring
tsnumber

plan

agentIdstring
steps{ text: string; status: string }[]
tsnumber

socket frames (8)

Client → server messages on /ws. The server sends nothing but RunEvent JSON in the other direction.

user_message

textstring
attachmentsoptional{ mediaType: string; dataBase64: string }[]

permission_response

callIdstring
allowedboolean
rememberoptionalboolean
persistoptionalboolean

abort

set_image_provider

providerstring

set_thinking

enabledboolean

set_provider

providerstring
modeloptionalstring

set_workspace

pathstring

set_permission_mode

modestring

REST endpoints (17)

Extracted from the @GetMapping/@PostMapping/@DeleteMapping annotations in spectro-server.

GET /api/claude/transcripts

Read-only browser for the Claude Code transcript store under ~/.claude/projects.

ClaudeTranscriptsController.java

GET /api/claude/transcripts/content

One transcript's raw JSONL — the client runs it through detectAndLoad.

ClaudeTranscriptsController.java

GET /api/config

The active LLM backend for the header + the Lab map: the boot config's provider and model (the same layers the socket builds its agent from).

SessionsController.java

GET /api/context

What goes to the LLM BEFORE any user message — the main agent's assembled system prompt, tools, skills, MCP servers and the subagent role profiles.

SessionsController.java

GET /api/file

The tree/content root for a request: without a session parameter, the boot root (unchanged behaviour); with one, THAT session's workspace — a per-session pin (the folder the user picked, shared state with the socket side) wins, else the config/auto rules via {@link WorkspaceResolver#locate} (no directory is ever created by a GET).

WorkspaceController.java

GET /api/files

Phase 5: the workspace panel's backend — a read-only, sandboxed view of the agent's working directory.

WorkspaceController.java

GET /api/health

The health probe the desktop shell polls before loading the UI.

SessionsController.java

POST /api/images/copy-to-workspace

Copies a generated image from the global content-addressed store (~/.spectro/images/.) into a session's workspace — the gallery's "copy to workspace" button.

ImageCopyController.java

GET /api/images/{file}

A dedicated client for the model-list probes with FINITE connect + read timeouts.

SessionsController.java

GET /api/jobs/state

The scheduler's job-state map (the same data `spectroscope cron status` prints).

SessionsController.java

GET /api/models

Curated fallbacks — used when the live model APIs are unreachable.

SessionsController.java

POST /api/pick-workspace

Opens the NATIVE folder chooser on the machine spectroscope runs on and returns the picked absolute path.

WorkspacePickController.java

GET /api/sessions

The REST endpoints alongside the socket.

SessionsController.java

DELETE /api/sessions/{id}

Session ids as the store mints them (yyyyMMdd-HHmmss-uuid8) plus the test/CLI-friendly general shape — never a path, never a dot.

SessionsController.java

GET /api/sessions/{id}/events

The events of one session as JSON — the graph tab replays exactly this.

SessionsController.java

GET /api/settings

The settings API — the read side.

SettingsController.java

POST /api/transcribe

The web face of voice input: the browser records with MediaRecorder and POSTs the webm/opus bytes here; the server converts them to 16 kHz mono WAV (an ffmpeg child process) and runs the SAME {@link Transcriber} the CLI uses.

TranscribeController.java

modules (7)

From settings.gradle.kts, plus the two npm toolchains.

spectro-core gradle module

The harness SDK: agents, tools, the permission gate, the typed RunEvent stream. Plain Java 21; Spring appears only as its HTTP client.

spectro-cli gradle module

The ./spectro launcher's engine: run, REPL, doctor, cron, sessions, resume (picocli).

spectro-server gradle module

One Spring Boot app: WebSocket + REST faces, serves the built web UI from its jar.

spectro-mcp-notes gradle module

A worked MCP server example (stdio JSON-RPC) to copy from.

spectro-orchestrator gradle module

The fleet: BusEnvelope choreography over one bus, every lane a full core agent, one merged EventStream.

spectro-web npm toolchain

The browser cockpit (React 19 + Vite): chat, Spectrum, trace, graph, text and Lab over one WebSocket; builds into the server's static resources.

spectro-desktop npm toolchain

The Electron shell: supervises the boot jar as a child process (not a gradle module).

tools (10)

The public catalog on the Tools facade (Tools.java), wire names cross-checked against StandardTools.java; the permission gate fronts every one of them.

Tools.readFile()read_fileTool factories that read as plain names — the frozen facade's tool vocabulary: .tools(Tools.readFile(), Tools.runCommand()).
Tools.writeFile()write_file@return write_file — create or overwrite a workspace file
Tools.editFile()edit_file@return edit_file — exact-match replacement inside a workspace file
Tools.listDir()list_dir@return list_dir — a workspace directory listing
Tools.glob()glob@return glob — filename patterns over the workspace
Tools.grep()grep@return grep — content search over the workspace
Tools.runCommand()run_command@return run_command — a shell command in the workspace (permission-gated)
Tools.viewImage()view_image@return view_image — shows the model an image from the workspace
Tools.viewFile()view_file@return view_file — shows the model a document from the workspace
Tools.all()@return the full standard belt, in registration order

environment (15)

SPECTRO_* keys found in spectro-core. Precedence: defaults < env < user settings < project settings < workspace settings < flags.

SPECTRO_BASE_URLOverride the provider endpoint (local proxies, compat servers).
SPECTRO_CHROMEPath to the Chrome binary the vision tools drive.
SPECTRO_IMAGE_MODELImage generation backend override.
SPECTRO_IMAGE_PROVIDERsee the SpectroConfig javadoc
SPECTRO_LOG_LEVELWire logging: info by default.
SPECTRO_MAX_RETRIESProvider retry budget.
SPECTRO_MODELModel name for the selected provider.
SPECTRO_PROMPT_CACHINGsee the SpectroConfig javadoc
SPECTRO_PROVIDERLLM backend: anthropic, ollama or any OpenAI-compatible server.
SPECTRO_STT_MODELSpeech-to-text model for /voice.
SPECTRO_THINKINGsee the SpectroConfig javadoc
SPECTRO_TOOL_INPUTsee the SpectroConfig javadoc
SPECTRO_TOOL_NAMEsee the SpectroConfig javadoc
SPECTRO_TOOL_RESULTsee the SpectroConfig javadoc
SPECTRO_WORKSPACEsee the SpectroConfig javadoc