scryer-cli 0.3.0

CLI tool and shared daemon runner for Scryer code intelligence
scryer-cli-0.3.0 is not a library.

scryer-cli

Command-line interface and daemon binary for the Scryer Code Intelligence Server.

scryer provides high-performance workspace indexing, local usage reporting (report), an outline-size benchmark, and MCP server daemon lifecycle management supporting both standard I/O (stdio) and HTTP Server-Sent Events (SSE) transports.

Installation

cargo install --path crates/scryer-cli

Or run directly with cargo run -p scryer-cli -- <COMMAND>.

Commands and Usage

1. scryer serve

Run the Model Context Protocol (MCP) server.

In stdio mode with a local database (the default), scryer serve is a thin client: it connects to the shared daemon's Unix socket (starting scryer daemon run in the background if none is listening), sends a one-line handshake with its working directory and whether to register it (the default; --no-watch turns it off), then copies bytes between stdin/stdout and the socket. This is what lets any number of MCP clients share one database. See crates/scryer-mcp/README.md for the protocol.

# Run over stdio (default, ideal for Claude Desktop or Cursor local process)
scryer serve

# Do not register the working directory or watch projects (the default is to do both)
scryer serve --no-watch

# Run over HTTP on port 8080 (MCP endpoint: http://<host>:8080/mcp)
scryer serve --transport sse --port 8080

# Connect to a remote Turso database instance
scryer serve --db-url "libsql://my-org.turso.io" --auth-token "my-token"

Options:

  • --transport <stdio|sse>: MCP transport protocol (default: stdio). sse serves rmcp Streamable HTTP at /mcp on <host>:<port>, in-process, with a fresh session state per HTTP session.
  • --host <ADDR>: Bind address for HTTP transport (default: 127.0.0.1).
  • --port <PORT>: Port for HTTP transport (default: 8080).
  • --no-watch / SCRYER_NO_WATCH: Don't register the working directory or watch projects. By default the first call registers the working directory as a project if no registered project contains it (it needs a project marker: .git, Cargo.toml, pyproject.toml, setup.py, package.json, tsconfig.json; / and the home directory never qualify) and indexes it in the background, and every registered project is watched. A call that arrives while the first index runs waits for it (SCRYER_FIRST_QUERY_WAIT seconds, default 20), then answers in full or says INDEXING n%. --watch is accepted and does nothing.
  • --tools <core|full> / SCRYER_TOOLS: which tools the session lists (default full). core lists six (search_symbols, inspect_symbol, find_references, get_file_outline, get_enclosing_scope, calculate_blast_radius); every tool stays callable by name. Use core for clients that don't defer tool definitions.
  • --always-load <core|none>: mark the core tools anthropic/alwaysLoad so Claude Code loads them up front (default core). Older Claude Code versions ignore it; set "alwaysLoad": true for the server in .mcp.json there.
  • --project <SLUG|ID|PATH> / SCRYER_PROJECT: project active when the session starts (stdio only); an unknown project fails the session.
  • --max-tokens <N> / SCRYER_MAX_TOKENS: default response token budget for calls that don't pass max_tokens.
  • --no-daemon / SCRYER_NO_DAEMON: Open the database in this process instead of using the daemon. Fails with an explanation if a daemon already owns the database.
  • --idle-timeout <SECS>: How long an auto-started daemon stays alive with no clients (default: 600, 0 = forever).
  • --db-url <URL> / SCRYER_DB_URL: Turso database URL or local path (default: ~/.scryer/scryer.db).
  • --auth-token <TOKEN> / SCRYER_AUTH_TOKEN: Authentication token for remote Turso databases.

The daemon is used only for stdio, local database files, and Unix. Remote (libsql:/turso:/https:) and :memory: databases, --no-daemon, and other platforms run in-process.

Note on stdio mode: When running with --transport stdio, standard output (stdout) is strictly reserved for JSON-RPC MCP messages. All tracing and operational logs are written to stderr.


2. scryer daemon

Manage the shared daemon that scryer serve connects to. It is normally started automatically.

scryer daemon status          # PID, version, build, socket, log, sessions, watched projects and directory counts
scryer daemon stop            # stop it (connected clients disconnect)
scryer daemon run             # run in the foreground (what `scryer serve` spawns)

Options:

  • --db-url <PATH> / SCRYER_DB_URL: Database the daemon owns (default: ~/.scryer/scryer.db). Each database gets its own daemon.
  • --idle-timeout <SECS> (run only): Exit after this long with no sessions (default: 600, 0 = forever).

Runtime files live in ~/.scryer/run/, named by a hash of the database path: <hash>.sock (socket), <hash>.pid (lock held by the running daemon), <hash>.lock (serializes daemon startup), <hash>.log (daemon log). If that socket path would exceed the OS limit (~104 bytes), the socket moves to $XDG_RUNTIME_DIR or /tmp as scryer-<hash>.sock, and clients verify it is owned by the current user before connecting. Each binary has a build ID (its executable's size and mtime, read at startup), exchanged in the handshake. scryer serve and the CLI stop a daemon from a different build before connecting when it has no sessions, so a rebuilt or reinstalled binary takes effect on the next connection. A daemon that still has sessions is left running, the client prints a warning suggesting scryer daemon stop, and get_indexing_status reports server.stale: true.


3. scryer index

Perform a manual scan and incremental indexing of a workspace into Turso. If a daemon owns the database, the request is sent to it (via the index_workspace tool) instead of opening the database.

# Index current workspace
scryer index

# Index specific directory with an explicit project slug
scryer index --path /path/to/repo --slug my-service

Options:

  • -p, --path <PATH>: Directory path of the workspace to index (default: current directory .).
  • -s, --slug <SLUG>: Explicit project slug identifier (defaults to directory basename).
  • -d, --db-url <URL>: Target database URL or file path.
  • -a, --auth-token <TOKEN>: Database authentication token.

Outputs a structured summary table reporting scanned files, added/modified/deleted files, extracted symbols, lexical scopes, references, and call graph edges.


4. scryer status

Display registered workspaces, entity metrics, file counts, and database status, as well as the global Cargo dependencies cache (Project 0). If a daemon owns the database, the status is fetched through it and shows file and symbol counts.

# View all registered workspaces and global Cargo dependencies (Project 0)
scryer status

# View status for a specific workspace project
scryer status --project my-service

# View status for global Cargo dependencies cache only
scryer status --project 0
scryer status --project dependencies

Options:

  • -p, --project <SLUG|ID>: Filter status by specific project slug, numeric ID, or "0"/"dependencies" for the Cargo cache.
  • -d, --db-url <URL>: Database URL or file path.
  • -a, --auth-token <TOKEN>: Database authentication token.

scryer doctor

Check the health of the index: how much is in it, and what could not be indexed. Reads the statistics recorded by the last indexing run and counts rows with SQL. If a daemon owns the database it is asked instead.

# Every registered project
scryer doctor

# One project (slug, ID or root path)
scryer doctor --project my-service

Output per project: file, symbol, reference and edge counts, files by language, references by how they were resolved (exact, name, macro), when it was last indexed, how many references name nothing in the project or its dependencies (standard library and other external code), the Cargo dependency state, and a Problems: list: files that failed to parse (with the first error), files with syntax errors (the parser may not support newer syntax or macros), files over the 2 MiB size cap or unreadable, and dependencies that could not be indexed (cargo metadata failed, or crates are not downloaded: run cargo fetch). An index built before this was recorded says so; run scryer index again.

Options:

  • -p, --project <SLUG|ID|PATH>: Report on one project (default: all).
  • -d, --db-url <URL>: Database URL or file path.
  • -a, --auth-token <TOKEN>: Database authentication token.

scryer delete

Unregister a project and delete its index data and ADR records from the database. Source files and ADR markdown on disk are not touched. Goes through the daemon when one is running, which also stops the project's file watcher.

# By slug, numeric ID, or root path
scryer delete my-service
scryer delete 3
scryer delete /home/me/projects/my-service

Options:

  • -d, --db-url <URL>: Database URL or file path.
  • -a, --auth-token <TOKEN>: Database authentication token.

5. scryer benchmark

Compare the size of the AST outline with the whole file (exact BPE tokens). This is a size comparison only: agents rarely read whole files, so it does not say what Scryer saves in a session (that is what scryer report and the harness measure). Supports benchmarking workspace directories or indexed external Cargo dependencies (Project 0).

# Benchmark current directory
scryer benchmark

# Benchmark a specific source file or directory
scryer benchmark --target src/main.rs

# Outline size for the public surface of the top 5 indexed Cargo dependencies
scryer benchmark --dependencies

# Benchmark up to 10 dependencies or a specific crate
scryer benchmark --dependencies --limit 10
scryer benchmark --dependencies --package tokio

Metrics Reported:

  • Naive Tokens: Exact BPE token count for reading the entire raw file.
  • AST Tokens: Exact BPE token count for extracted outline and declarations.
  • Reduction %: How much smaller the outline is than the file.
  • Elapsed Time: AST extraction latency.

5b. scryer report

How your own sessions used Scryer, from the usage the server records locally: per tool, calls, how often the next call was another Scryer call, mean response tokens and truncations.

scryer report                  # every recorded session in the database
scryer report --session ID     # one session
scryer --json report           # the raw summary (what get_token_savings_metrics returns)
find_references: 14 calls, followed by another Scryer call 80% of the time, 910 response tokens per call, truncated 2 of 14

Measured quantities only: no cost or savings estimate. Recorded per call: tool name, session, project, response tokens, truncated flag, latency, time; never arguments, symbol names or answers (ADR 0015). The data stays in the database; nothing is sent. SCRYER_TELEMETRY=off stops recording. A follow-up is any Scryer call right after in the same session; the server cannot see a grep or file read, so the real rate is higher. get_token_savings_metrics is the same data as an MCP tool.


6. scryer init

Set up a project for its coding agents in one command: guidance, each agent's MCP configuration and permissions, a first index, and a health check.

scryer init                        # AGENTS.md block + skill; agents detected from the project
scryer init --agent claude         # claude | codex | cursor | all (repeatable)
scryer init --check                # verify everything is up to date; exit 1 if not; writes nothing
scryer init --no-index             # skip the first index and the doctor run
scryer init /path/to/repo          # another directory (or an AGENTS.md path)
scryer init --print                # print the AGENTS.md block
scryer init --print-skill          # print the skill (how plugin/scryer/skills is regenerated)
scryer init --print-codex-config   # print the Codex config.toml entry

What it writes:

File Content
AGENTS.md the Scryer block, about ten lines
.agents/skills/scryer/SKILL.md the full playbook
.mcp.json (--agent claude) scryer server with serve --tools core and alwaysLoad: true, so Claude Code loads the tools up front
.claude/settings.json (--agent claude) Bash(scryer:*) and the core tools added to permissions.allow
CLAUDE.md (--agent claude, only if it exists) a block with @AGENTS.md: Claude Code reads AGENTS.md only when there is no CLAUDE.md
.codex/config.toml (--agent codex) the [mcp_servers.scryer] table with enabled_tools and tool_timeout_sec
.cursor/mcp.json (--agent cursor) scryer server with serve --tools core

Without --agent, agents are detected: CLAUDE.md, .claude/ or .mcp.json mean Claude Code; .codex/ Codex; .cursor/ Cursor.

It never overwrites what you wrote. Text goes between <!-- scryer:start --> / <!-- scryer:end --> (# scryer:start / # scryer:end in TOML) sentinels, JSON is merged under Scryer's own key (other servers and settings stay), permissions are only ever added. A scryer server entry you already have in .mcp.json or config.toml is left as it is (--check accepts it), and a file that isn't valid JSON is left untouched with an error. Running it twice changes nothing.

After the files, it indexes the project (through the daemon when one runs; skipped when the directory has no project marker or with --no-index) and prints the scryer doctor report for it, so you know the setup works before the first agent call.

The two guidance files have different jobs. AGENTS.md is read in every session, so its block is short: use Scryer instead of grep, the one-line tool choice, when grep is still right, how to read an empty or partial result, and a pointer to load the scryer skill. The skill holds the full playbook (decision tree, working rules, MCP / Antigravity / CLI invocation, workflows, payload options). The MCP server's instructions (at most 1,800 characters, because Claude Code truncates at 2,048) carry the same decision tree for clients that read neither file. All three generators live in installer.rs and server.rs; tests keep them short, in step, and limited to real tool names.


7. Direct Code Intelligence Commands (CLI & Shell Tool Fallback)

Every Scryer MCP tool can be run directly from the command line using strongly typed Clap subcommands or dynamically via scryer call. This provides a complete fallback for coding agents operating without direct MCP tool integrations, and makes all capabilities self-discoverable via --help.

# Discover all tools and subcommands
scryer --help

# Discover specific tool flags and documentation
scryer get-file-outline --help
scryer resolve-definition --help
scryer get-type-contract --help

# File outlines without reading method bodies
scryer get-file-outline src/main.rs --compact
scryer get-file-outline src/main.rs --kinds function,struct --limit 20

# Type contracts and shapes
scryer get-type-contract MyStruct
scryer get-type-contract --type-name MyStruct --file-path src/models.rs

# Symbol navigation & references
scryer resolve-definition src/main.rs 42 10
scryer find-references MySymbol
scryer find-references MySymbol --role call --scope-level dependencies

# Call hierarchies & blast radius
scryer trace-call-hierarchy my_function --direction callers
scryer calculate-blast-radius MySymbol --files-only

# Dynamic generic tool invocation
scryer call list_projects
scryer call get_file_outline src/main.rs --compact

Short verbs and text output

Tool commands print compact text by default: a header line (counts, complete or TRUNCATED, index state), then one line per item. --json (global) prints the tool's JSON instead; tools without a text form print compact JSON.

scryer callers X         # who calls X: each calling function once, with its line
scryer refs X            # every usage site of X, one line each
scryer files X           # the files that use X, with counts
scryer def X             # definition, signature, code, callers, ADRs   (inspect-symbol)
scryer outline FILE      # declarations of a file                       (get-file-outline)
scryer at FILE:LINE      # the function or type containing a line       (get-enclosing-scope)
scryer find retry backoff  # symbols by concept words                   (search-symbols)

The long subcommands (find-references, inspect-symbol, ...) and their aliases still work. Whether to tell agents to prefer these over MCP is decided by the harness cli condition (Plan 20 Phase 7 gate); the skill lists them as an option.

scryer hook pre-grep (experimental, off by default)

A Claude Code PreToolUse hook for Grep and plain grep/rg Bash commands. With SCRYER_HOOK=on, a search for a bare identifier (four or more characters) that names exactly one function or type in a ready index is denied once, with Scryer's caller answer as the reason; repeating the same search runs it. It never touches regexes, strings, paths, case-insensitive or one-file searches, docs or tests; SCRYER_HOOK=off (or unset) does nothing; SCRYER_HOOK=context allows the grep and adds the answer as context (a control for the experiment). Any error means no output and exit 0. It is enabled by default only if the with-hook harness condition beats with; see testing-harness/README.md.

3-Tier Invocation Model:

  1. Direct MCP (Codex, Cursor, Claude Code, Windsurf): Native tool calls (get_file_outline, resolve_definition).
  2. MCP Gateway (Google Antigravity / Gemini CLI): Gateway dispatch via call_mcp_tool(ServerName: "Scryer", ToolName: "...", Arguments: {...}).
  3. CLI Subcommand Fallback (Shell / Non-MCP): Terminal execution via scryer <command> with full --help discoverability.