REST endpoints (123)
Extracted from the @GetMapping/@PostMapping/@DeleteMapping annotations in spectro-server.
POST /api/analyze
One analysis call, streamed as NDJSON.
AnalyzeController.java
GET /api/analyze/engine
The opt-in run analysis (card 294): an imported run's compact digest goes to the configured provider ONCE, on an explicit click, and the model's reading comes back as a stream.
AnalyzeController.java
GET /api/browser/status
Where the browser pane goes, and whether one exists — the two things the web UI needs in order to draw the browser segment honestly.
BrowserViewportController.java
POST /api/browser/viewport
The rectangle the browser segment reserved, in window CSS pixels.
BrowserViewportController.java
GET /api/bundles
The starter-bundle endpoints.
BundleController.java
GET /api/bundles/{id}
The catalog for a given stamp.
BundleController.java
POST /api/bundles/{id}/scaffold
POST /api/bundles/{id}/scaffold {dir, build} — write the bundle's files into dir.
BundleController.java
GET /api/claude/transcripts
Read-only browser for the Claude Code transcript store under ~/.claude/projects.
ClaudeTranscriptsController.java
GET /api/claude/transcripts/content
The listing itself, fence already passed.
ClaudeTranscriptsController.java
GET /api/claude/transcripts/facts
A JSON body already built, at a given status.
ClaudeTranscriptsController.java
GET /api/claude/transcripts/folders
GET /api/claude/transcripts/folders: which of a session's three folders are really on disk.
ClaudeTranscriptsController.java
POST /api/claude/transcripts/folders/open
POST /api/claude/transcripts/folders/open: show one of them.
ClaudeTranscriptsController.java
GET /api/claude/transcripts/gists
What a click on this row would fetch, weighed now.
ClaudeTranscriptsController.java
POST /api/claude/transcripts/gists
POST /api/claude/transcripts/gists: write the missing ones.
ClaudeTranscriptsController.java
GET /api/claude/transcripts/run
GET /api/claude/transcripts/run: one whole recorded run, as texts.
ClaudeTranscriptsController.java
GET /api/claude/transcripts/sidecars
The agents beside one session, named.
ClaudeTranscriptsController.java
POST /api/codegraph/start
POST /api/codegraph/start: starts graphify in the background against the session's resolved folder.
CodeGraphController.java
GET /api/codegraph/status
"Build code graph" (card 472): graphify run as a background job of the harness against a session's working folder, and its graph.html served to the internal browser.
CodeGraphController.java
GET /api/codegraph/view
GET /api/codegraph/view: the session folder's graph.html, for the internal browser, under {@link #SANDBOX}.
CodeGraphController.java
GET /api/commands
The chat commands for the web (card 554, owner option A): the web chat's /help, its slash picker and the Skills and Commands page are built from this answer, and the terminal REPL prints the same list from the same resource.
CommandsController.java
GET /api/config
Card 379: whether rtk resolves where the agent's shell looks, and which version answered.
SessionsController.java
GET /api/context
Why a value is not the shape its setting takes, or null when it is.
SessionsController.java
GET /api/copilot/account
The Copilot sign-in sheet's endpoints (card 495).
CopilotAccountController.java
POST /api/copilot/account/cancel
POST /api/copilot/account/cancel: stops a waiting sign-in.
CopilotAccountController.java
POST /api/copilot/account/sign-in
POST /api/copilot/account/sign-in: starts a device flow, or takes the Copilot CLI's stored sign-in when the method is cli and the CLI has one.
CopilotAccountController.java
POST /api/copilot/account/sign-out
POST /api/copilot/account/sign-out: deletes the stored tokens, or the choice of the CLI's sign-in.
CopilotAccountController.java
GET /api/docker/status
Reports whether Docker is usable on this machine, so the Observability settings can offer the right next step instead of a command that cannot work.
DockerStatusController.java
POST /api/explain
The LLM-backed explain (card 62): the Text tab POSTs a bounded, readable digest of the viewed run (the same feed it renders) and gets back a streamed INTERPRETATION — what the agent was trying to do, why each step followed, where it hesitated, how it recovered.
ExplainController.java
GET /api/file
The tree/content root for a request: THAT session's resolved workspace, and nothing else.
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/fleet
The fleet's REST face (block C): the roster fold and per-node ring replay.
FleetController.java
POST /api/fleet/nodes
Spawn a readonly fleet node (block 3b) — the RCE-sensitive surface, gated to the teeth: LOCAL-ORIGIN (loopback remote address AND a localhost Host — the Host check is what stops DNS rebinding, which a loopback check alone does not), JSON-only (consumes makes a browser form POST a 415), OPT-IN (SPECTRO_ALLOW_SPAWN, default off), a spawn cap, and the node is FORCED readonly (see {@link NodeSpawner}).
FleetController.java
GET /api/fleet/port-check
Card 585: both hub settings as the server read them, the port in use, and why the hub differs from what was written.
FleetController.java
GET /api/fleet/{node}/events
Per-node replay from the hub ring — bounded by the ring, and saying so.
FleetController.java
POST /api/fleet/{node}/gate
Answer a parked permission gate on a fleet node (block 4): dispatch a ctl{gate} carrying the operator's verdict to the node over the hub.
FleetController.java
POST /api/fleet/{node}/message
Carry the operator's words to a fleet node that stays (card 166's server leg) — the verb that turns a node you can only stop into one you can talk to.
FleetController.java
POST /api/fleet/{node}/stop
Stop a running fleet node (block 3): dispatch a ctl{stop} to it over the hub.
FleetController.java
GET /api/governing-numbers
The numbers that govern a run, read out for the settings room — card 357.
GoverningNumbersController.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}
The Copilot runtime's own model list (card 496), in its order.
SessionsController.java
GET /api/jobs/state
The scheduler's job-state map (the same data `spectroscope cron status` prints), plus the code graph builds of this server process under codegraph: (card 472), whose status is running while they build.
SessionsController.java
GET /api/leveling
The ladder over REST: read the state, report a visited surface, switch mode, restart, and tick a criterion by hand.
LevelingController.java
POST /api/leveling/mode
Switches how much of the ladder is doing work in this home.
LevelingController.java
POST /api/leveling/reset
Restarts the ladder from the dark frame, keeping the chosen mode.
LevelingController.java
POST /api/leveling/tick
Marks a criterion by hand.
LevelingController.java
POST /api/leveling/visit
Reports that a surface was shown, which is how acts the event stream cannot see reach the ladder.
LevelingController.java
GET /api/local-model/catalog
The built-in provider's model endpoints, behind the picker's chooser dialog: GET /api/local-model/catalog (every offered model, its download state and whether this machine can hold it), GET /api/local-model/status (polled for progress) and POST /api/local-model/download (starts the fetch).
LocalModelController.java
POST /api/local-model/download
Start one model's download (idempotent per model; two different models may download concurrently).
LocalModelController.java
GET /api/local-model/status
Current download/presence state of one model — polled by the dialog for its progress bar.
LocalModelController.java
GET /api/logs
The doctor page's live server log (card 85): the rolling ~/.spectro/logs/spectroscope.log the shared logback.xml writes, served as a tail plus cheap incremental deltas — the client polls with the returned byte offset and receives only what was appended since.
LogsController.java
GET /api/models
Curated fallbacks — used when the live model APIs are unreachable.
SessionsController.java
GET /api/models/capabilities
LM Studio's own listing, read for one model; unknown when it does not answer.
ModelCapabilityController.java
GET /api/models/tool-use
The capability sibling of /api/models (card 88): what one (provider, model) pair honestly supports for reasoning control, as the {@link ReasoningCapability} record — the same record the providers gate their wire fields on, so the picker and the request path share ONE truth.
ModelCapabilityController.java
POST /api/onboarding/key
Save an API key from the onboarding UI — LOCAL browsers only.
SessionsController.java
GET /api/otlp/probe
The doctor's OTLP check: is the configured exporter endpoint reachable and does it accept our auth?
OtlpProbeController.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/playbooks
The playbook routes: the known folders and the pin per workspace, loading a registered folder, and copying a bundled playbook into a folder the owner picked.
PlaybookController.java
PUT /api/playbooks/active
PUT /api/playbooks/active {workspace, dir} : pins a registered folder to a workspace.
PlaybookController.java
POST /api/playbooks/bundled/{id}/copy
POST /api/playbooks/bundled/{id}/copy {dir} : writes a shipped playbook into the folder and registers it.
PlaybookController.java
GET /api/playbooks/contents
One of the card 523 routes: the fence, the registered folder, then the work.
PlaybookController.java
GET /api/playbooks/draft
The largest draft body the check reads.
PlaybookController.java
POST /api/playbooks/draft
POST /api/playbooks/draft?dir=&workspace= with the draft as the body : the editor view of the body, checked as a load would check it.
PlaybookController.java
GET /api/playbooks/export
The largest body POST /api/playbooks/import reads: a bundle of 24 MB in JSON, twice over, for base64 and escaped text.
PlaybookController.java
PUT /api/playbooks/file
PUT /api/playbooks/file?dir=&workspace= with {"baseHash", "playbook"} : saves the draft as the folder's playbook.json in the canonical form.
PlaybookController.java
DELETE /api/playbooks/file-at
DELETE /api/playbooks/file-at?dir=&path= : removes one text file of a registered folder, never a folder and never playbook.json, LICENSE or PROVENANCE.md at the root.
PlaybookController.java
POST /api/playbooks/folders
POST /api/playbooks/folders {dir} : registers a folder that holds a playbook.json.
PlaybookController.java
POST /api/playbooks/import
A JSON answer on a route whose body is a stream: Spring writes a {@link StreamingResponseBody} whatever the status, so a refusal is serialized here.
PlaybookController.java
POST /api/playbooks/import-hooks
POST /api/playbooks/import-hooks {dir, replace?, baseHash?, workspace?} : writes the hooks of the user settings into hooks/hooks.json, copies the scripts their commands name from the home into hooks/, writes the project folder (the workspace, else the launch folder) as {project}, leaves out a hook that names a dot folder of the home (card 538), and lists the file in contents.hooks.
PlaybookController.java
POST /api/playbooks/import-plugin
POST /api/playbooks/import-plugin {dir, baseHash?, plugin:{root?, marketplace, name, version, kinds:[skills|agents|commands|hooks]}} : copies the chosen kinds of a listed plugin into the folder (card 526).
PlaybookController.java
POST /api/playbooks/import-skills
POST /api/playbooks/import-skills {dir, baseHash?, items:[{source, root?, pack?, name?]}} : copies installed or catalogue skills into the folder's skills// and lists the pack in contents.skills.
PlaybookController.java
GET /api/playbooks/import-sources
GET /api/playbooks/import-sources?dir=&workspace= : what can be put into a registered folder (card 523): the installed skills by root label and pack, the catalogue skills by id and the hooks of the user settings, each hook with left set when the import leaves it out.
PlaybookController.java
GET /api/playbooks/load
GET /api/playbooks/load?dir=&workspace= : a registered folder, loaded.
PlaybookController.java
POST /api/playbooks/new-agent
POST /api/playbooks/new-agent {dir, name, type, skill?, description?} : writes agents/.md from the template and lists it in contents.agents.
PlaybookController.java
POST /api/playbooks/new-command
POST /api/playbooks/new-command {dir, name} : writes commands/.md from the template and lists it in contents.commands.
PlaybookController.java
GET /api/playbooks/plugin-sources
GET /api/playbooks/plugin-sources?dir= : the Claude Code plugins of this home (card 526), from the plugin cache and the local plugins of each marketplace under ~/.claude/plugins, each by its root label, marketplace, name and version, with the count of each kind it carries, whether it carries MCP servers and whether it has a licence.
PlaybookController.java
GET /api/playbooks/read
GET /api/playbooks/read?dir=&path= : one text file of a registered folder with its sha256.
PlaybookController.java
POST /api/playbooks/remove-content
POST /api/playbooks/remove-content {dir, kind, path} : takes the entry out of contents and removes the files under its path, never a file outside the kind's folder and never playbook.json.
PlaybookController.java
GET /api/playbooks/start-preview
GET /api/playbooks/start-preview?dir=&workspace= : the confirmation of a run (card 482).
PlaybookController.java
GET /api/playbooks/tree
The largest body PUT /api/playbooks/write reads: a text of 1 MB in JSON, where an escaped control character takes six bytes.
PlaybookController.java
PUT /api/playbooks/write
PUT /api/playbooks/write {dir, path, text, baseHash} : writes one text file of a registered folder through a temp file and an atomic move.
PlaybookController.java
GET /api/providers
The provider registry on the wire.
ProvidersController.java
POST /api/providers/check
POST /api/providers/check: runs a bounded check and returns the rows.
ProvidersController.java
GET /api/run-document
The bytes of one file whose path a route has already checked, typed for the preview: the answer /api/file and /api/run-document share once their own checks have passed.
WorkspaceController.java
GET /api/sessions
The REST endpoints alongside the socket.
SessionsController.java
GET /api/sessions/live
The REST twin of the live_sessions socket frame (card 212).
LiveSessionsController.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
PATCH /api/sessions/{id}
Card 445: renames or pins one stored session.
SessionsController.java
GET /api/sessions/{id}/browser-wire
The read side of the browser record (card 204): the sidecar the {@link BrowserWireRecorder} writes under ~/.spectro/browser-wire/, served three ways — the whole file as a download, a bodiless ledger the replay view scrubs, and one action's two lines on demand.
BrowserWireController.java
GET /api/sessions/{id}/browser-wire/action/{cid}
One action's two recorded lines, parsed: the drill-in behind a scrubber step.
BrowserWireController.java
GET /api/sessions/{id}/browser-wire/index
The bodiless ledger the replay view scrubs: one object per action in file order, the call and its result paired by cid while STREAMING the file.
BrowserWireController.java
GET /api/sessions/{id}/bundle
Export one stored session as a bundle (card 473): a zip with the session file, its llm wire, its browser wire and its child session files, each entry the file on disk byte for byte.
SessionsController.java
GET /api/sessions/{id}/events
The config for a session's recorded provider and model; the server's own config when the session recorded none.
SessionsController.java
GET /api/sessions/{id}/export
Export one stored session as its RAW JSONL — the mirror of the existing import, so a session can leave the machine and come back byte-identical.
SessionsController.java
GET /api/sessions/{id}/llm-wire
The read side of the backend-to-LLM record (card 184): the sidecar file the {@link LlmWireRecorder} writes under ~/.spectro/llm-wire/, served three ways.
LlmWireController.java
GET /api/sessions/{id}/llm-wire/exchange/{xid}
One exchange's two recorded lines, parsed: the drill-in behind an index row.
LlmWireController.java
GET /api/sessions/{id}/llm-wire/index
The bodiless ledger: one object per exchange in request order, request and response lines paired by xid.
LlmWireController.java
GET /api/sessions/{id}/messages
Card 503: the agent messages of one stored session, as the peer_message frames the page folds into its message blocks, read from its .messages.jsonl under ~/.spectro/messages.
SessionsController.java
GET /api/sessions/{id}/playbook-runs
The playbook runs of one session (card 482): a row per run read from the sidecar, and the graph file of a run.
PlaybookRunsController.java
GET /api/sessions/{id}/playbook-runs/{run}/graph
GET /api/sessions/{id/playbook-runs/{run}/graph}.
PlaybookRunsController.java
POST /api/sessions/{id}/title/suggest
Card 445, criterion 8: asks the session's own provider and model for a title, once, from its first prompt.
SessionsController.java
GET /api/settings
The settings API — the read side.
SettingsController.java
GET /api/settings/allowlist
GET /api/settings/allowlist: the auto-approve allowlist READ OUT — every entry with the tier it now carries, per scope and folded (card 199, criterion 4).
SettingsController.java
GET /api/settings/env
GET /api/settings/env: the operator settings the UI may save, and what they are set to now.
SessionsController.java
POST /api/settings/env
POST /api/settings/env: save one operator setting to ~/.spectro/.env.
SessionsController.java
GET /api/settings/hooks
One layer's raw autoApprove array, read out through the gate's own parser.
SettingsController.java
PUT /api/settings/local
PUT /api/settings/local?session=: applies a partial patch to the session's workspace .spectro/settings.local.json (machine-local, gitignored — {@link SettingsWriter#patch} ensures the .gitignore entry) and answers the fresh session-moment view.
SettingsController.java
PUT /api/settings/project
PUT /api/settings/project?session=: applies a partial patch to the session's workspace .spectro/settings.json and answers the fresh session-moment view.
SettingsController.java
PUT /api/settings/user
One layer's raw hooks array, read out through the core's own record.
SettingsController.java
GET /api/skills
The settings page's skill manager (card 90): list the skills of both roots (user ~/.spectro/skills and project /.spectro/skills) — including DISABLED ones the loader hides — toggle a .disabled marker, and delete a user-root skill (the seeding ledger keeps it from returning).
SkillsController.java
POST /api/skills/install
The shelf, with installed recomputed per request — the index itself is built once, since the catalogue rides inside the artifact and cannot move.
SkillsController.java
POST /api/skills/install-set
Copy several catalogue skills into the user root in one request, all or nothing (card 410: a pack's install button).
SkillsController.java
POST /api/skills/remove-set
Take several catalogue skills out of the user root in one request, all or nothing (card 410: a pack's remove button).
SkillsController.java
GET /api/spectrolyzr
The Spectrolyzr routes: the catalog the wizard offers, a preview of the files one set of choices renders, and the generate route that writes them.
SpectrolyzrController.java
POST /api/spectrolyzr/generate
POST /api/spectrolyzr/generate with archetype, language, addons, name, dir, playbookDir: writes the project and, with the playbook add-on, the playbook folder, and pins the latter to the former.
SpectrolyzrController.java
GET /api/spectrolyzr/preview
GET /api/spectrolyzr/preview: the files one set of choices renders, each with its reason, and the test and check commands.
SpectrolyzrController.java
POST /api/stt/model/download
Fetch the pinned model.
SttController.java
GET /api/stt/status
What speech-to-text needs, whether it is here, and the one half of it this app can honestly fetch (card 184 leg 2b).
SttController.java
POST /api/transcribe
The web face of voice input: the browser records with MediaRecorder, converts the recording to 16 kHz mono WAV itself, and POSTs that here; the server runs the SAME {@link Transcriber} the CLI uses.
TranscribeController.java
POST /api/translate
One translation run, streamed as NDJSON — a provider call per passage.
TranslateController.java
GET /api/translate/engines
Translating an imported session (owner 2026-07-27, reading an incident-response transcript written in Ukrainian): the reader hands over the READABLE passages of the record and gets each one back in the language they picked, from either the built-in local model or the configured cloud provider.
TranslateController.java
POST /api/workspace/reveal
The folder chip's two server actions (card 462): show a live session's working folder in Finder, and open Terminal in it.
WorkspaceOpenController.java
POST /api/workspace/terminal
POST /api/workspace/terminal: opens Terminal in the session's working folder.
WorkspaceOpenController.java