Raymon

Ingestão HTTP com estado + servidor MCP + interface de terminal para logs no estilo Ray.

Documentação

raymon

Crates.io Version CI CodSpeed Crates.io Downloads License Discord Buymecoffee

Raymon is a local-first Ray-style log receiver with an HTTP ingest endpoint, a Streamable HTTP MCP server, durable JSONL storage, and a Ratatui terminal UI.

Use Raymon when you want Ray-compatible dumps from your app to be visible in a terminal and searchable by AI agents through MCP.

Raymon terminal UI screenshot

What Raymon provides

SurfaceWhat it does
HTTP ingestAccepts Ray-style JSON envelopes on POST /.
MCP serverExposes raymon.search and raymon.get_entries on POST /mcp.
Terminal UIBrowses live logs, filters by screen/type/color, opens payloads, yanks details, and manages JSONL archives.
StoragePersists entries to data/entries.jsonl under the active storage root.
Rust crate APIExposes raymon::run() plus public raymon_core, raymon_ingest, raymon_storage, raymon_mcp, and raymon_tui modules for embedding and tests.

Raymon listens on the Ray default port, 23517, so many Ray client libraries can target it with little or no configuration.

Quickstart

Prerequisites

  • A Raymon binary from Cargo, Homebrew, GitHub Releases, or a local source build.
  • A terminal. The default run mode opens the TUI.

Run with generated events

Start Raymon in demo mode:

raymon --demo

Expected result: the TUI opens and demo events begin appearing. Press ? for help or q to stop Raymon.

Run without the TUI and send one event

Start Raymon in one terminal:

RAYMON_NO_TUI=1 raymon

Send a Ray-style event from another terminal:

curl -sS http://127.0.0.1:23517/ \
  -H 'content-type: application/json' \
  -d '{
    "uuid": "readme-demo-1",
    "payloads": [
      {
        "type": "log",
        "content": {
          "message": "hello from Raymon",
          "color": "green"
        },
        "origin": {
          "hostname": "local",
          "fileName": "README.md",
          "lineNumber": 1
        }
      }
    ],
    "meta": {
      "project": "raymon-readme",
      "host": "local",
      "screen": "readme"
    }
  }'

Expected output contains:

{"ok":true,"error":null}

Stop the server with Ctrl+C.

Installation

Cargo

Raymon requires Rust 1.89 or newer.

cargo install raymon

Homebrew

brew install bnomei/raymon/raymon

GitHub Releases

Download a prebuilt archive from GitHub Releases, extract it, and place raymon on your PATH.

From source

git clone https://github.com/bnomei/raymon.git
cd raymon
cargo build --release

The binary is written to target/release/raymon.

Sending logs

Raymon stores Ray-style log entries. Generate them with a Ray-compatible library in your application, then point that library at Raymon's host and port.

Known Ray integrations include PHP, JavaScript, Bash, Ruby, Python, Go, Dart, and Rust. For Rust-native payloads, see ray-dbg.

The default local endpoint is:

http://127.0.0.1:23517/

If your sender uses the Ray desktop defaults, Raymon usually works by starting raymon before you emit logs.

Inbound envelopes must include a non-empty uuid, at least one payload, a non-empty payloads[*].type, and a non-empty payloads[*].origin.hostname. When the same UUID is ingested more than once, Raymon merges the payloads into one entry and stores the merged entry before it publishes live state or events.

Run modes

Local TUI

raymon

This starts the HTTP ingest endpoint, the MCP endpoint, and the TUI on 127.0.0.1:23517.

Headless local server

RAYMON_NO_TUI=1 raymon

Use this for background logging, MCP-only workflows, or tests.

Remote server with auth

export RAYMON_AUTH_TOKEN="change-me"
RAYMON_ALLOW_REMOTE=1 \
RAYMON_HOST=0.0.0.0 \
RAYMON_NO_TUI=1 \
raymon

Raymon refuses non-loopback binds unless RAYMON_ALLOW_REMOTE=1 is set. If the bind address is non-loopback, Raymon also requires RAYMON_AUTH_TOKEN unless you explicitly set RAYMON_ALLOW_INSECURE_REMOTE=1.

CLI reference

raymon [OPTIONS]
OptionMeaning
--host <HOST>Override the HTTP bind host.
--port <PORT>Override the HTTP bind port.
--config <PATH>Load a specific JSON config file instead of searching for ray.json.
--ide <COMMAND>Command used by the TUI to open origin files.
--editor <COMMAND>Command used by the TUI to open selected detail payloads in a temp file.
--jq <COMMAND>jq command used for detail-pane searches.
--tuiEnable the TUI.
--no-tuiDisable the TUI.
--demoGenerate local demo events.
-v, --verboseEnable info logging. Use -vv for debug logging.
-h, --helpPrint CLI help.
-V, --versionPrint the Raymon version.

Configuration precedence is:

  1. Defaults.
  2. ray.json.
  3. Environment variables.
  4. CLI flags.

Configuration

Raymon searches for ray.json from the current directory upward. If it finds one, the directory containing that file becomes the storage root. Without ray.json, the current working directory is the storage root.

Example ray.json:

{
  "host": "127.0.0.1",
  "port": 23517,
  "tui": true,
  "max_entries": 10000,
  "storage_max_entries": 100000,
  "mcp_redact_payloads": false
}

Environment variables use the same concepts with RAYMON_ names:

VariableDefaultMeaning
RAYMON_ENABLEDtrueEnable or disable Raymon.
RAYMON_HOST127.0.0.1HTTP bind address.
RAYMON_PORT23517HTTP bind port.
RAYMON_TUItrueEnable the TUI.
RAYMON_NO_TUIfalseDisable the TUI. Takes precedence over RAYMON_TUI.
RAYMON_IDEcodeIDE command used for origin-file jumps. For VS Code line jumps, use code --goto.
RAYMON_EDITORVISUAL/EDITOR/vimEditor command used for selected detail payloads.
RAYMON_JQjqjq command used for detail search.
RAYMON_MAX_BODY_BYTES1048576Maximum HTTP request body size and merged stored-entry size.
RAYMON_MAX_QUERY_LEN265Maximum search, command, picker, and MCP query length in bytes.
RAYMON_MAX_ENTRIES10000Maximum entries kept in memory for MCP and live resync. 0 disables in-memory eviction.
RAYMON_STORAGE_MAX_ENTRIES100000Maximum distinct entries kept in data/entries.jsonl. 0 disables storage retention.
RAYMON_JQ_TIMEOUT_MS10000Detail-search jq timeout in milliseconds.
RAYMON_ALLOW_REMOTEfalseAllow binding to non-loopback addresses.
RAYMON_ALLOW_INSECURE_REMOTEfalseAllow non-loopback binding without auth. Avoid this unless you accept the exposure risk.
RAYMON_INSECURE_REMOTEunsetAlias for RAYMON_ALLOW_INSECURE_REMOTE.
RAYMON_ALLOW_MCP_SHUTDOWNfalseAllow MCP ray/quit, ray/exit, raymon/quit, and raymon/exit custom methods to stop Raymon.
RAYMON_MCP_REDACT_PAYLOADSfalseRedact sensitive-looking payload fields in MCP results and event notifications.
RAYMON_AUTH_TOKENunsetRequire Authorization: Bearer <token> or x-raymon-token: <token> for all HTTP requests.
RAYMON_TOKENunsetAlias for RAYMON_AUTH_TOKEN.
RAYMON_TUI_PALETTEunsetOverride the TUI palette with 18 comma-separated colors.
RAYMON_PALETTEunsetAlias for RAYMON_TUI_PALETTE.
RAYMON_LOGunsetTracing filter. Falls back to RUST_LOG when unset.

RAYMON_TUI_PALETTE expects:

fg,bg,black,red,green,yellow,blue,magenta,cyan,white,bright_black,bright_red,bright_green,bright_yellow,bright_blue,bright_magenta,bright_cyan,bright_white

Each color can be #RRGGBB, rgb:RR/GG/BB, or rgb:RRRR/GGGG/BBBB.

Storage

Raymon stores entries as newline-delimited JSON in:

data/entries.jsonl

The data/ directory is created under the active storage root. The TUI also writes session archives under:

data/archives/

On startup, Raymon restores stored entries into the core state so MCP search can see persisted logs. The TUI starts with a fresh live view and lets you browse archive files from the archives pane.

Retention keeps the newest distinct UUIDs. During restore, Raymon skips corrupt JSONL lines and legacy blob entries instead of aborting startup.

HTTP API

Method and pathPurpose
POST /Ray ingest endpoint for Ray payload envelopes.
POST /mcpMCP Streamable HTTP endpoint. Prefer this path for MCP clients.

POST / also accepts MCP JSON-RPC requests as a compatibility fallback when ingest parsing rejects the body and the JSON looks like MCP JSON-RPC. Prefer /mcp for new MCP clients.

When RAYMON_AUTH_TOKEN is set, every request must include one of these headers:

Authorization: Bearer <token>
x-raymon-token: <token>

Ingest responses use HTTP status codes:

StatusMeaning
200The envelope was stored and published.
400The request body was invalid JSON.
413The merged entry exceeded RAYMON_MAX_BODY_BYTES.
422The envelope was missing required fields or had invalid data.
500Storage, state, or event-bus handling failed.

MCP setup

Add a local Raymon MCP server to Codex:

codex mcp add raymon --url http://127.0.0.1:23517/mcp

Remote setup with bearer-token auth:

codex mcp add raymon \
  --url http://<host>:23517/mcp \
  --bearer-token-env-var RAYMON_AUTH_TOKEN

Equivalent MCP JSON:

{
  "mcpServers": {
    "raymon": {
      "url": "http://127.0.0.1:23517/mcp"
    }
  }
}

Remote MCP JSON with auth:

{
  "mcpServers": {
    "raymon": {
      "url": "http://<host>:23517/mcp",
      "headers": {
        "Authorization": "Bearer ${RAYMON_AUTH_TOKEN}"
      }
    }
  }
}

MCP tools

Raymon exposes two read-only tools.

raymon.search

Search stored entries and return compact summaries.

Input:

{
  "query": "string (optional; plain text or /regex/)",
  "types": ["string"],
  "colors": ["string"],
  "screen": "string (optional)",
  "project": "string (optional)",
  "host": "string (optional)",
  "limit": "number (optional)",
  "offset": "number (optional)"
}

types and colors also accept comma-separated strings:

{ "types": "error,exception", "colors": "red" }

Result:

{
  "entries": [
    {
      "uuid": "string",
      "received_at": 0,
      "project": "string",
      "host": "string",
      "screen": "string",
      "payload_count": 1,
      "payload_types": ["log"]
    }
  ],
  "count": 1,
  "limit": 100,
  "offset": 0,
  "scan_limit": 5000
}

Defaults and limits:

FieldDefaultLimit
limit100500
offset05000
scan_limit5000Fixed newest-entry scan window
queryunsetRAYMON_MAX_QUERY_LEN bytes

raymon.get_entries

Fetch full entries by UUID.

Input:

{
  "uuids": ["<uuid>"],
  "redact": false
}

Supported input aliases:

{ "uuid": "<uuid>" }
{ "uuids": "<uuid-1>,<uuid-2>" }

redacted and redact_payloads are aliases for redact. When redaction is enabled, Raymon replaces sensitive-looking payload fields such as passwords, tokens, API keys, cookies, and secrets.

Result:

{
  "entries": [
    {
      "uuid": "string",
      "received_at": 0,
      "project": "string",
      "host": "string",
      "screen": "string",
      "session_id": null,
      "payloads": [
        {
          "type": "log",
          "content": {},
          "origin": {
            "project": "string",
            "host": "string",
            "screen": "string",
            "session_id": null,
            "function_name": null,
            "file": null,
            "line_number": null
          }
        }
      ]
    }
  ]
}

Limits:

LimitValue
UUIDs per request100
Bytes per UUID265
Serialized tool result1048576 bytes

Connected MCP peers receive ray/event notifications for inserted, updated, cleared, and lagged events. If a client receives a lag notification, it should refresh with raymon.search.

TUI

The TUI is keyboard-first and has built-in help. Press ? for the full keymap.

KeyAction
?Open keybindings.
qQuit Raymon and stop the HTTP/MCP server.
SpaceOpen the picker menu.
/ or fSearch messages and file paths with fuzzy search.
rStart a regex search.
:Search inside the selected detail payload. Uses jq for JSON queries when available.
j/k, arrowsMove in the focused pane.
h/l, left/right arrowsMove focus left or right.
J/K, PageUp/PageDownScroll the detail pane.
Tab, Shift+TabMove focus between logs, detail, and archives.
gGo to a log position.
GJump to the last log.
sSnap color and type filters to the selected log entry.
uReset search and filters.
pPause or resume live updates.
aToggle the archives pane.
xArchive the current view to a JSONL file.
EnterLoad the selected archive when the archives pane has focus.
nRename the selected archive. Live archives cannot be renamed.
dDelete the selected archive after confirmation. Live archives cannot be deleted.
yYank the selected list entry.
YYank the selected detail payload.
zToggle expanded JSON rendering.
ZToggle raw JSON rendering.
mToggle style and metadata payloads in the detail pane.
1 through 6Toggle list columns: color dot, timestamp, type label, file, message, UUID.
oOpen the origin file in the configured IDE.
eOpen the selected detail payload in the configured editor.
Ctrl+lClear the live log list without deleting stored entries.
Ctrl+cQuit from anywhere.

Mouse support is enabled: click to focus or select, and use the wheel to move through the pane under the pointer.

Raymon uses the terminal ANSI palette by default, so it inherits light, dark, and base16-style terminal themes. Use RAYMON_TUI_PALETTE when you need a fixed palette.

Agent skill

This repository includes an AI-facing runbook at skills/raymon/SKILL.md. It teaches agents how to:

  • Generate Ray-style events with common Ray integrations.
  • Add Raymon as a local or remote MCP server.
  • Use raymon.search before raymon.get_entries to inspect logs efficiently.

The skill is documentation for agents. It is not runtime code.

Source layout

PathPurpose
src/cli.rsRuntime lifecycle, configuration, storage restore, demo mode, and TUI/server orchestration.
src/cli/http.rsAxum router, auth, body limits, concurrency limits, ingest, and MCP mounting.
src/raymon_core.rsIO-free domain types, filters, events, and Ray envelope normalization.
src/raymon_ingest.rsHTTP ingest parsing, validation, duplicate-UUID merging, storage, and event emission.
src/raymon_mcp.rsMCP tools, notifications, query limits, result limits, and shutdown hooks.
src/raymon_mcp/schema.rsMCP request and response schemas.
src/raymon_storage/JSONL persistence, indexing, listing, and retention.
src/raymon_tui.rsTUI state, rendering, search, filtering, key handling, editor integration, and archive workflows.
tests/ray_php_local.rsIgnored local PHP/Ray integration test.

Development

Run the Rust test suite:

cargo test --all-targets

Run formatting and clippy checks:

cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings

Run pre-commit hooks when prek is installed:

prek validate-config prek.toml
prek run --all-files
prek install

Run the local-only PHP Ray integration test after installing the global PHP ray() helper:

cargo test --test ray_php_local -- --ignored ray_php_local_integration

Build and package release artifacts:

TARGET=x86_64-apple-darwin scripts/build-release.sh
VERSION=0.7.0 TARGET=x86_64-apple-darwin scripts/package-release.sh

The release workflow builds Linux musl (x86_64, aarch64), macOS (x86_64, aarch64), and Windows MSVC (x86_64) targets. Unix artifacts are .tar.gz archives, Windows artifacts are .zip archives, and each package gets a .sha256 file.

License

MIT. See LICENSE.