open source · JVM · local-first

the agent orchestrator
you can watch.

spectroscope fans the event stream of your agents into discrete, replayable lines, the way a spectroscope fans starlight. Spawn an agent in five lines, gate every tool call, replay every run byte for byte, and watch a whole fleet on one screen.

$ spectro run "write hello.py and run it" see how it works The user guide's table of contents user guide

Java 21 · virtual threads · no reactive DSL · permission gate built in

emission lines

every event is like a spectral line

An agent run lands as a stream of typed RunEvents, not a wall of logs: each token, tool call, and permission decision arrives as its own discrete line. One stream is the API, the storage format, the UI protocol, and the audit log, so what you watch is exactly what gets stored.

tokens tool calls permission gate subagent messages lifecycle

passive observation

watch without disturbing the run

The web UI subscribes to the same RunEvent stream the agent already emits. Opening the Trace view attaches a reader, not a debugger: the run proceeds exactly as it would unobserved. Quantum measurement disturbs what it measures. A spectroscope does not: the light left the star long before it reached the slit. The Trace view works the same way.

Harness

One agent, three parts: a container-free core, a blocking for (RunEvent e : agent.run(p)) loop on virtual threads, tools behind a first-class permission gate. Tool inputs are model output and therefore untrusted.

Orchestrator

Many small agents on a bus: spawn a panel of workers, hand off tasks with A2A-style task / status / result messages, and steer the whole fleet. Every exchange is visible in the same stream; there is no second protocol.

Trace

Every run lands as byte-stable JSONL you can replay in the CLI, the web app, the Lab step-through, or the graph. A session recorded on one machine replays on any other. For a regulated team, the trace file is the audit log.

measurement collapse

nothing runs until you decide

When an agent wants to touch the world, spectroscope holds the action in a pending state and asks. Until you decide, nothing has happened. Your approval or denial collapses the pending call into exactly one recorded outcome, and the decision itself becomes a line in the trace.

tool.runCommand("rm -rf build/")
event: permission.pending · outcome: unresolved

the why layer

spectro-explain: explainable AI, made practical

A spectroscope tells you what the light is made of. Every trace answers what happened; spectro-explain reads the same stream and answers why: which rule made the gate ask, which call caused which result, what a run did in plain language. The rule and the causal chain come straight from the stream, with no model in the loop; only the optional narrative summary calls one.

why did the gate ask

Every permission event joins the rule that fired. No model involved, just the stream: "the gate asked because runCommand is not on the allowlist."

causal chains

Each event carries its cause. Walk any result back to the call, the turn, and the prompt that started it, one hop at a time.

reasoning, recorded

The model's stated thinking lands in the trace as events, next to what it actually did. Put the two side by side, replay them, diff them. That is the model's self-report, not a window into the weights, and we say so. The Trace view ships this as the reasoning lens: see it running below.

spectro explain run.jsonl

A run summary in two layers: a deterministic skeleton (tools, costs, gate decisions) and an optional narrative on top. Explanations land in the trace as events, so they are as auditable as the run.

dispersion

the whole fleet on one screen

The Orchestrator runs many agents on one bus. The Spectrum tab disperses that single stream into parallel lanes, one line per agent, ordered and steady. You read the fleet the way you read a spectrum: at a glance for the pattern, line by line when something looks off.

straight from the app

four captures, two scripted runs

Every capture below is spectro web replaying one of its bundled demo scenarios in the browser. Scenarios are scripted runs, so you can explore every surface without a key or a server. The reasoning lens foregrounds what the model reported thinking and pins each thought to what it actually did next.

The trace tab of spectro web: 46 numbered frames of a review fan-out run with the reasoning lens active. A thinking frame is opened, showing its causal chain and an insight view of the raw event.
trace · reasoning lens on: the thinking frame reads “I fan out into three parallel reviewers”, chained to the tool call that then did
The spectrum tab of spectro web: four agent lanes, main plus three reviewers, every event a colored line on its lane.
spectrum · the same run dispersed into four lanes: main plus the bugs, perf and security reviewers
The chat tab of spectro web during the review fan-out: tool cards with OK results, subagent chips for bugs, perf and security, their three review answers, and the final summary.
chat · the fan-out as a conversation: tool cards, subagent hand-offs, three verdicts, one summary
The lab tab of spectro web: a system map with the agent, its permission gate, the operating system and the outside world. An MCP call to notes/search_notes travels toward the external MCP server while the gate waits for a decision.
lab · step through the run like a circuit: here an MCP call is on the wire and the gate holds it until you decide

spectral fingerprint

every run leaves a fingerprint

A finished run is a JSONL file: ordered, complete, byte-stable. Like an element's line pattern, the trace identifies exactly what the agent did, which tools it called, and what a human approved. Hand the file to a reviewer and they can read the entire run without access to your machine.

{"seq":12,"type":"tool.call","name":"readFile","gate":"granted"}

light is a record of the past

replay any run, byte for byte

Because the trace is byte-stable JSONL, any run replays exactly as it happened, event by event. Scrub back, pause at the moment a tool call went wrong, and read the surrounding state. A replay is the original stream played again, byte for byte, not a reconstruction.

t = now · playing forward

for regulated teams

trust what you can verify

spectroscope gives a regulated team four properties to check: every action is visible while it runs, gated before it touches the world, explained afterwards, and stored as a byte-stable record anyone can replay. When an auditor asks what the agent did, the answer is a file, and it is the same file you watched being written.

see it

The live stream shows every token, tool call and decision as it happens.

gate it

Every tool call meets the gate; the decision, a human click or an allowlist rule, lands in the trace.

explain it

Every why is answered from the same stream that carries the what.

prove it

Byte-stable JSONL that replays identically, on any machine, any time.

for developers

spawn in five lines. watch every line.

The stream is the observability: iterating it is the instrumentation.

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 the stream reads the same in both

spectro-core

The harness SDK: agents, tools, the permission gate, the typed RunEvent stream. Plain Java 21, virtual threads, no reactive DSL.

spectro-cli

The spectro launcher: run agents, replay traces, and check your setup with spectro doctor.

spectro-server + web

The local web app: Trace, Lab, Graph, and the Spectrum fleet view, all fed by one WebSocket of RunEvents.

spectro-orchestrator

Small agents on one bus, exchanging task, status, and result messages under one correlation id. The one module still under construction.

the JSONL wire format is the compatibility contract: traces recorded anywhere replay everywhere

Architecture: the agent emits one typed RunEvent stream; JSONL, the web UI, spectro-explain and exporters all read the same stream Module map: core, cli, server and web, orchestrator, explain and the mcp example on one RunEvent backbone

a stack you can see through

runs on Spring. almost nothing else.

An observability tool earns trust by being observable itself. spectroscope is five small Gradle modules you can read, not a platform you subscribe to.

plain new

spectro-core is a Java 21 library. You instantiate agents with new; there is no container to boot and no annotation processor to please. Spring appears in the core only as its HTTP client.

one ordinary Boot app

The server face is a single Spring Boot application that serves the web UI from its own jar. If you run Spring in production, you already know how to run this.

the whole dependency list

Jackson, Spring's web client, the Anthropic SDK, a cron parser, slf4j. The CLI adds picocli, the faces add logback. There is no agent framework underneath and no vector database to feed.

see-through by design

One typed event stream through every module, one gate for every side effect, every run on disk as JSONL you can open in an editor. Hold the tool up to the light and you can read it, like its namesake.

line spectrum vs blackbody

discrete lines, not blackbox glow

elsewhere

Most agent stacks radiate like a blackbody: plenty of output, no structure you can resolve. Observability is a cloud dashboard, a paid tier, or a listener you remember to register.

spectroscope

spectroscope emits a line spectrum. Because every event is typed, you filter, diff, and replay a run instead of grepping a log after the fact. Local first, permission-gated by design, on the JVM.

get started

The five lines above already run in the codebase. v0.1.0 ships under the coordinates shown. The source is public at github.com/spectroscope/spectroscope; the Maven artifact follows with the release.

maven

<dependency>
  <groupId>dev.spectroscope</groupId>
  <artifactId>spectro-core</artifactId>
  <version>0.1.0</version>
</dependency>

cli

$ spectro replay run.jsonl # byte for byte
$ spectro web      # the Spectrum view
$ spectro doctor   # checks your setup

user guide

Every surface in one book, from the thirty-second start to the fleet reference.
read it in the browser · dark
pdf: light · 15 MB · dark · 15 MB

v0.1.0 upcoming · macOS/Linux first-class · MIT licensed: use it commercially, fork it, ship it

read your agents like starlight.