Skip to main content
reticle serve starts the daemon: the WebSocket bridge your app dials into, plus the tool engine behind it. It spawns a detached child and then waits for that child to answer /status before reporting success.
Most people never type this. Your agent runs reticle mcp, which starts a daemon itself if one is not already up.

Flags

The HTTP flags are honoured or refused, never silently dropped: against an already-running daemon that does not serve the requested verify port, serve --http exits 1 and names both ports. A running daemon keeps the flags it was started with, so reticle stop, then serve again. A verify port that cannot be bound fails the daemon start with a reticle_daemon_start_failed line naming that port.

What it prints

One structured line. When a daemon already owns the port, it says so and does nothing:
A successful spawn logs reticle_daemon_spawned with the port:
A port held by something that is not a Reticle daemon is refused up front rather than spawned into. The reason is repeated as plain text on stderr for the person who typed the command. Real capture, with python3 -m http.server 4498 holding the port and the punctuation between the two halves of the reason shown as ...:

Exit codes

serve reports the bind, not the spawn. It used to exit 0 the moment it forked, while the child died on an EADDRINUSE nobody joined back up. It now waits for the daemon to answer.

Worked example

What the daemon is

The bridge, the tool engine, and where .reticle/ lives.
Last modified on September 1, 2026