HTTP API

Talk to Maylyn over HTTP

Every route maylyn serve exposes: how to authenticate, how streaming chat works, and what each endpoint does. Loopback and a bearer token by default.

Reference for the HTTP API exposed by maylyn serve (and maylyn hub, which mounts the same routes with inference off). The route table is registered in NewServeMux in backend/serve.go and is the source of truth; if this page and that file disagree, the code wins.

Version this page was checked against: v0.44.1.

Contents

Quick start

MAYLYN_SERVE_TOKEN=$(openssl rand -hex 32) maylyn serve
# maylyn serve listening on 127.0.0.1:8787

curl http://127.0.0.1:8787/health

curl -N http://127.0.0.1:8787/ask/stream \
  -H "Authorization: Bearer $MAYLYN_SERVE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "say hello in one short sentence", "tools": false}'

If MAYLYN_SERVE_TOKEN is unset, a random token is generated and printed on startup.

Variable Default Purpose
MAYLYN_SERVE_ADDR 127.0.0.1:8787 Listen address. Loopback by default; a warning is printed if you widen it
MAYLYN_SERVE_TOKEN generated Static bearer token (admin/legacy credential)
MAYLYN_SERVE_ALLOW_TOOLS false Let HTTP callers run approval-gated tools (shell_exec, write_file, ...) unattended
MAYLYN_SERVE_WEBAPP config webapp_enabled Mount the bundled browser/phone UI. The env var overrides config in either direction
MAYLYN_SERVE_AUTH_MODE kratos kratos (Ory Kratos sessions, plus the static token as a fallback) or local (static token only)
MAYLYN_KRATOS_PUBLIC_URL http://127.0.0.1:4433, or <hub>/kratos when a hub is configured and serving Kratos Kratos public base URL
MAYLYN_KRATOS_START_CMD empty Optional command to autostart a localhost Kratos

MAYLYN_SERVE_ALLOW_TOOLS=true means a POST body can run a shell as the user that owns the process. Do not combine it with a non-loopback address unless that is exactly what you intend.

Conventions

  • Base URL: http://127.0.0.1:8787 unless MAYLYN_SERVE_ADDR says otherwise.
  • Bodies: JSON (Content-Type: application/json) unless noted. Request bodies are capped at 4 MiB; an invalid or oversized body returns 400.
  • Errors: standard HTTP status (400, 401, 403, 404, 429, 5xx). Most handlers answer with a plain-text body; the rate and concurrency limiters answer 429 with {"error": "..."} and a Retry-After header. A missing or bad credential returns 401 with unauthorized: log in, or send Authorization: Bearer <token>.
  • Path parameters are written {like_this}.
  • Per-person scoping: with a Kratos session, conversations, artifacts, memories and agents resolve to that person's own store. The static token resolves to the machine's shared store.
  • Client hint: the optional X-Maylyn-Client header (desktop or webapp) tells the server which shell is calling and may change how a turn is shaped.

Authentication

Every route is in one of these classes. The tables below label each route with the class that applies.

Class Meaning
Public No credential. Safe-to-expose status, public text, or web UI assets
Bearer Authorization: Bearer <token> where the token is the static MAYLYN_SERVE_TOKEN. When Kratos is reachable (the default auth mode) a verified Kratos session, sent as a browser cookie, is also accepted
Bearer or ?token= As Bearer, and additionally the static token may be passed as ?t= or ?token= for <img>, <a> and EventSource, which cannot set headers
Socket WebSocket upgrade; authenticated inside the handler
URL token The secret is part of the path (/hooks/{token}, /share/{token}, ...); no header needed
Signed Peer-to-peer mesh traffic authenticated by an ed25519 signature on the envelope

Details:

  • The static token is compared in constant time over SHA-256 digests.
  • A verified Kratos session wins over the static token and scopes the request to that person's store. Banned profiles get 403.
  • With Kratos active, unverified accounts get 403 unless they are the machine owner.
  • The webhook route POST /automation/webhook/{id} is Bearer-authenticated and additionally reads an X-Maylyn-Webhook-Token header.

Streaming chat

Two routes run the agent loop and answer as Server-Sent Events (Content-Type: text/event-stream).

POST /ask/stream

One-shot prompt. Bearer.

{ "prompt": "what changed in the repo?", "agent": "maylyn", "tools": true }
Field Type Notes
prompt string Required. Empty returns 400 prompt is required
agent string Agent profile name; default agent if empty
tools bool Enable tool calls for this turn

POST /chat/stream

Multi-message chat. Bearer.

{
  "messages": [{ "role": "user", "content": "hello" }],
  "agent": "maylyn",
  "tools": true
}
Field Type Notes
messages [{role, content}] Conversation so far; the last entry is the new user turn
images array Images attached to the last user message
agent string Agent profile name
model string Model override
conversation_id string Attach the turn to a saved conversation
knowledge_base_id string Retrieve from this knowledge base
skill string Pin one skill into the turn
max_iterations int Tool-loop cap
context_tokens int Context window override
auto_approve bool Skip approval prompts (the server still refuses unattended tools unless MAYLYN_SERVE_ALLOW_TOOLS is set)
tools bool Enable tool calls
tool_overrides object Per-tool picker: { "tool_name": "auto" } never asks, "off" hides the tool for this turn
concise bool Voice-originated turn; keep the reply short and speakable
resume bool Resume an interrupted turn
steer string Redirect a running generation
thinking string Reasoning-effort hint
mode string Turn mode
mesh_pack string Route the turn to a Pack

The full struct is chatStreamRequest in backend/serve.go.

Stream events

Event payloads are JSON. Names that the server emits include:

Event Meaning
meta Turn metadata (agent, model) sent first
response_chunk A piece of the assistant reply
response_retract Earlier streamed text was withdrawn
thinking_chunk A piece of model reasoning
tool_call The model called a tool (name, args)
tool_result A tool finished (name, result)
tool_denied A tool was refused (approval gate or unattended policy)
status / notice Progress or advisory text
timing Latency breakdown (setup, session, retrieval, pre-model)
error The turn failed
done The turn finished

Other chat routes

Route Auth Purpose
GET /chat/ws Socket WebSocket variant of chat/stream used by the web client
POST /chat/stop Bearer Stop the running turn. Prefer this over closing the stream
GET /approvals Bearer List pending tool approvals
POST /approvals Bearer Answer a pending approval. Only the session that raised the call may answer

Endpoint reference

Routes are grouped by area. "Bearer" includes verified Kratos sessions.

Health and downloads

Route Auth Purpose
GET /health Public Liveness plus process identity (status, pid, build id, executable)
GET /downloads/latest Public Latest release metadata (proxy used by the website)
GET /downloads/asset/{name} Public Release asset download proxy

Web UI shell (only when the web app is enabled)

All Public: GET / (shell), /styles.css, /app.js, /bootstrap.js, /thinking_phrases.json, /manifest.webmanifest, /sw.js, /favicon.ico, /icon-192.png, /icon-512.png, /icon-192-maskable.png, /icon-512-maskable.png, /apple-touch-icon.png, /mascot.png, and the prefixes /voice/canned/, /controllers/, /vendor/, /icons/achievements/, /icons/weather/. When the web app is off these return 404.

Sign-in and accounts

Route Auth Purpose
GET /auth/config Public Which auth mode is active and where flows live
GET /auth/kratos/login register recovery settings verification logout Public Redirects into the matching Kratos browser flow
/kratos/ Public Reverse proxy to the Kratos public API (kratos mode)
GET /access/required Public Legacy: whether an access key is needed
POST /access/validate Public Legacy: validate an access key
GET /me Bearer Current profile
POST /me/claim-owner Bearer Claim machine ownership
POST /me/name Bearer Update display name
POST /me/bio Bearer Update bio
GET /me/avatar POST /me/avatar DELETE /me/avatar Bearer Read, upload, or remove the avatar
POST /keys/invite Bearer Create an invite
GET /admin/people Bearer List accounts (owner)
POST /admin/people/revoke Bearer Revoke an account
POST /admin/people/ban Bearer Ban or unban an account
POST /admin/invites/revoke Bearer Revoke an invite

Agents, models and setup

Route Auth Purpose
GET /agents Bearer List agent profiles
GET /models Bearer List available models
GET /models/media PUT /models/media Bearer List every installed model, or set its image/video/audio input (Auto/On/Off)
DELETE /models/installed Bearer (owner) Uninstall any installed model by its path from GET /models/media; refuses the running model
GET /models/image Bearer Image models in the catalog (SDXL checkpoints and FLUX.1 schnell), with install state
POST /models/image/install DELETE /models/image Bearer (owner) Install (a setup job; follow /setup/job/events) or remove an image model by name
GET /setup/state Bearer First-run setup state
POST /setup/model /setup/art /setup/music Bearer Start an install job
GET /setup/job/events Bearer or ?token= SSE progress for the running setup job
POST /setup/job/cancel Bearer Cancel the setup job
POST /setup/complete Bearer Mark setup finished
GET /capabilities Bearer Feature and plugin capability matrix
POST /capabilities/plugin Bearer Enable or disable a plugin
GET /diagnostics/control Bearer Control-plane diagnostics
GET /vitals Bearer Machine vitals

Skills and library

Route Auth Purpose
GET /skills Bearer List skills
GET /skills/{name} Bearer Read one skill
POST /skills/preview Bearer Preview a skill before installing
POST /skills/install Bearer Install a skill
DELETE /skills/{name} Bearer Remove a skill
GET /library/models DELETE /library/models Bearer List or delete models installed from Hugging Face search
GET /library/models/search Bearer Search for models
POST /library/models/install Bearer Install a model
GET /library/offline DELETE /library/offline Bearer List or delete offline packs
GET /library/offline/catalog Bearer Offline pack catalog
POST /library/offline/install Bearer Install an offline pack
GET /library/mcp-directory Bearer Browse the MCP connector directory
POST /library/mcp-install DELETE /library/mcp-install Bearer Add or remove an MCP server
POST /library/mcp-check Bearer Test an MCP server

Conversations, shares and attachments

Route Auth Purpose
GET /conversations Bearer List saved conversations
GET /conversations/{id} Bearer Read one
GET /conversations/{id}/artifacts Bearer Artifacts produced in a conversation
POST /conversations Bearer Save a conversation
DELETE /conversations/{id} Bearer Delete a conversation
POST /wiki/consolidate Bearer Consolidate memory into the wiki
POST /shares/oneoff Bearer Create a one-off read-only share link
GET /shares Bearer List shares
GET /shares/{id}/preview Bearer Preview a share
DELETE /shares/{id} Bearer Revoke a share
GET /share/{token} URL token Replay a shared conversation
POST /attachments/parse Bearer Parse an uploaded attachment into text

Knowledge bases and projects

Route Auth Purpose
GET /knowledge-bases POST /knowledge-bases Bearer List or create
GET /knowledge-bases/{id} DELETE /knowledge-bases/{id} Bearer Inspect or delete
GET /knowledge-bases/{id}/chunks Bearer Indexed chunks
POST /knowledge-bases/{id}/sources DELETE /knowledge-bases/{id}/sources Bearer Add or remove a source
GET /projects POST /projects Bearer List or create projects
POST /projects/active Bearer Set the active project
DELETE /projects/{name} Bearer Delete a project
GET /projects/pending Bearer Project handed off from the CLI, awaiting a decision
GET /projects/detect Bearer Detect a project in a directory
POST /projects/link Bearer Link a directory as a project
POST /projects/index Bearer Start indexing
GET /projects/index/{id} Bearer Indexing status

Files and artifacts

Route Auth Purpose
GET /files GET /files/ Bearer or ?token= File browser and file reads inside the sandbox
GET /plugins/files/list GET /plugins/files/read Bearer List and read sandbox files
POST /plugins/files/mkdir create rename delete upload Bearer Sandbox file operations
GET /artifacts/ Bearer Serve a stored artifact file
GET /plugins/artifacts/history Bearer Artifact revision history
POST /plugins/artifacts/delete Bearer Delete an artifact
POST /plugins/images/upload Bearer Upload an image
POST /plugins/pixel/analyze Bearer Analyze pixel art
POST /plugins/dice/roll Bearer Roll dice

Studio, canvas and sound

Route Auth Purpose
GET /studio/assets POST /studio/assets Bearer List or create art-studio assets
GET /studio/assets/{id} Bearer Read an asset
POST /studio/assets/{id}/animation/op animation/export Bearer Animation edit and export
POST /studio/assets/{id}/sound/op sound/render sound/export Bearer Sound edit, render, export
GET /studio/assets/{id}/sound/graph Bearer Sound node graph
GET /canvas/styles Public Local checkpoints and styles (no paths or secrets)
GET /canvas/tags Bearer Tag vocabulary
POST /canvas/jobs Bearer Submit an image job
GET /canvas/jobs/{id} Bearer Job state
GET /canvas/jobs/{id}/events Bearer Job SSE events
GET /canvas/jobs/ws Socket Job updates over WebSocket
POST /canvas/jobs/{id}/cancel retry Bearer Cancel or retry a job
GET /sound/capabilities Bearer Sound backend capabilities
POST /sound/import POST /sound/sessions POST /sound/ai Bearer Import audio, open a session, run an AI sound action
GET /sound/waveform GET /sound/artifact Bearer Waveform data and rendered audio

Voice

Route Auth Purpose
GET /voice/config Public Whether voice is on, plus the chosen voice (no secrets)
GET /voice/state Bearer Voice server state
POST /voice/tts Bearer Text to speech, proxied to the configured server
POST /voice/stt Bearer Speech to text, proxied to the configured server
POST /voice/install Bearer Install the local voice servers

Browser automation

Route Auth Purpose
GET /browser/state Bearer Current browser session state
POST /browser/action Bearer Perform a browser action
POST /browser/replay Bearer Replay a recorded action sequence

Automations

Route Auth Purpose
GET /automations PUT /automations Bearer List or save automations
DELETE /automations/{id} Bearer Delete
POST /automations/{id}/run cancel Bearer Run or cancel
GET /automations/{id}/journal Bearer Run journal
GET /automations/{id}/ws Socket Live run updates
GET /automations/scheduler PUT /automations/scheduler Bearer Read or set the scheduler
GET /automations/briefs Bearer Generated briefs
POST /automations/briefs/{id}/seen Bearer Mark a brief seen
GET /automations/palette Bearer Step palette for the editor
POST /automations/try Bearer Dry-run a step
GET /automations/connections PUT /automations/connections Bearer List or save API connections
DELETE /automations/connections/{name} Bearer Remove a connection
POST /automation/webhook/{id} Bearer + X-Maylyn-Webhook-Token Trigger an automation
POST /hooks/{token} URL token Trigger a flow. The token is the credential

Packs and mesh

Route Auth Purpose
GET /packs POST /packs Bearer List or create Packs
POST /packs/join Bearer Join with an invite
GET /packs/my-invite Bearer Your invite
GET /pack-invites/{token} URL token Peek at an invite
GET /packs/discover Bearer Public Pack directory
GET /packs/{id}/state DELETE /packs/{id} Bearer State, or delete
POST /packs/{id}/leave invite public join-request Bearer Membership actions
POST /packs/{id}/devices Bearer Enroll a device
POST /packs/{id}/devices/{node}/sharing location Bearer Device sharing and location
DELETE /packs/{id}/devices/{node} Bearer Remove a device
GET /packs/{id}/requests Bearer Pending join requests
POST /packs/{id}/requests/{principal} Bearer Approve or deny a request
GET /packs/{id}/jobs POST /packs/{id}/jobs Bearer List or submit Pack jobs
GET /packs/{id}/jobs/{job} Bearer One job
GET /mesh/peers Bearer Known peers
GET /mesh/terms Bearer Participation agreement plus this machine's acceptance
GET /mesh/terms/text Public Agreement text
POST /mesh/terms/accept Bearer Accept the agreement
GET /mesh/globe Public Coarse public Pack directory (name, ~20 km centroid, counts)
POST /mesh/envelope Signed Node-to-node envelope
POST /mesh/job-status Signed Requester pulls job results
POST /mesh/register Signed Hub check-in. Answers not_a_hub unless running maylyn hub
POST /internal/pool-relay/{token}/chat/completions URL token Pool relay, OpenAI-shaped completions

Authority layer

Route Auth Purpose
GET /authority/status Bearer Authority layer status
GET /authority/tasks Bearer Autonomous tasks
POST /authority/delegations revoke Bearer Grant or revoke a delegation
POST /authority/stop Bearer Emergency stop
GET /authority/ledger Bearer Action ledger
GET /authority/credentials POST /authority/credentials Bearer List or store credentials
POST /authority/credentials/revoke Bearer Revoke a credential
GET /authority/wallet Bearer Wallet status
POST /authority/reauth Bearer Re-authenticate for a sensitive action

See architecture/AUTHORITY_LAYER.md.

Achievements

Route Auth Purpose
GET /achievements Bearer Your achievements
GET /achievements/leaderboard Bearer Leaderboard
PUT /achievements/pinned Bearer Set pinned achievements

Image backend (embedded canvas server)

When Maylyn Canvas runs in-process it also answers on its own listener with GET /health, POST /generate, POST /edit, POST /upscale, and the OpenAI-shaped POST /v1/images/generations, /v1/images/edits and /v1/images/upscale. These are served by the image backend, not by the main maylyn serve listener. See backend/canvas_embedded.go.

Profiling (opt-in)

Setting MAYLYN_PPROF=6060 (or 127.0.0.1:6060) starts a separate profiling listener serving /debug/pprof/* and /debug/goroutines. It refuses to bind anywhere but loopback and is not part of the main maylyn serve listener. See backend/pprof.go.

Limits and hardening

  • Loopback-only bind by default; widening it is a deliberate act.
  • Conservative header, read and idle timeouts; bounded header size.
  • Per-IP rate limiting with burst control; 429 with Retry-After: 1 when exceeded.
  • Stream concurrency limit returns 429 with Retry-After: 5.
  • Concurrency caps and time budgets on /ask/stream and /chat/stream.
  • Baseline security headers and panic containment on every response.
  • Tools that require approval are refused over HTTP unless MAYLYN_SERVE_ALLOW_TOOLS is set; read-only tools always work.

Design background: architecture/SECURITY_INVARIANTS.md.