Skip to content

CLI Reference

Diapason provides a command-line interface through the diapason command. Built on Click, it offers subcommands for querying models, managing memory, running benchmarks, and serving an OpenAI-compatible API.

Global Options

diapason --version   # Print the Diapason version
diapason --help      # Show top-level help with all subcommands

diapason init

Detect local hardware (CPU, GPU, RAM) and generate a configuration file at ~/.diapason/config.toml.

diapason init           # Interactive — refuses to overwrite existing config
diapason init --force   # Overwrite existing config without prompting
Option Description
--force Overwrite existing configuration without prompting

The init command auto-detects:

  • Platform (Linux, macOS, Windows)
  • CPU brand and core count
  • RAM in GB
  • GPU vendor, model, VRAM, and count (via nvidia-smi, rocm-smi, or system_profiler)

Based on the detected hardware, it recommends an appropriate inference engine and writes a pre-configured TOML file.

Example output:

Detecting hardware...
  Platform : linux
  CPU      : AMD Ryzen 9 7950X (32 cores)
  RAM      : 64 GB
  GPU      : NVIDIA RTX 4090 (24.0 GB VRAM, x1)

Config written successfully.

diapason ask

Send a query to the inference engine (directly or through an agent) and print the response.

diapason ask "What is the capital of France?"

Options

Option Type Default Description
-m, --model MODEL string auto Model to use for inference
-e, --engine ENGINE string auto Engine backend (ollama, vllm, llamacpp, etc.)
-t, --temperature TEMP float 0.7 Sampling temperature
--max-tokens N int 1024 Maximum tokens to generate
--json flag off Output raw JSON result instead of plain text
--no-stream flag off Disable streaming (synchronous mode)
--no-context flag off Disable memory context injection
-a, --agent AGENT string none Agent to use (simple, orchestrator)
--tools TOOLS string none Comma-separated tool names to enable
-i, --image PATH path none Image file for a vision model (e.g. gemma3:4b); repeatable
-S, --screen flag off Capture the current screen and send it to the vision model

Direct Mode vs Agent Mode

Direct mode (default) sends the query straight to the inference engine:

diapason ask "Explain quantum computing"

Agent mode routes the query through an agent that can use tools and manage multi-turn interactions:

diapason ask --agent orchestrator "What is 2+2?"
diapason ask --agent orchestrator --tools calculator,think "Calculate sqrt(144) + 3^2"
diapason ask --agent simple "Hello"

Usage Examples

# Basic query
diapason ask "What is machine learning?"

# Specify a model
diapason ask -m qwen3:8b "Summarize this concept"

# Use the orchestrator agent with tools
diapason ask --agent orchestrator --tools calculator "What is 15% of 340?"

# Get JSON output
diapason ask --json "Hello"

# Disable memory context injection
diapason ask --no-context "Tell me about Python"

# Set maximum token generation
diapason ask --max-tokens 2048 "Write a detailed essay about AI"

Vision Input

Vision-capable models (such as gemma3:4b) can read images alongside your text prompt. Attach one or more image files with -i/--image, or capture the current screen with -S/--screen:

# Ask about a local image
diapason ask -i screenshot.png "What is shown in this image?"

# Send multiple images (the flag is repeatable)
diapason ask -i chart-a.png -i chart-b.png "Compare these two charts"

# Capture the current screen and ask about it
diapason ask --screen "Summarize what's on my screen"

Vision runs in direct mode only. If you also pass --agent, the image is ignored and a note is printed — re-run with --agent "" to force direct mode.

The Ollama context window can be tuned for large images or long prompts with the DIAPASON_NUM_CTX environment variable (default 16384):

DIAPASON_NUM_CTX=8192 diapason ask --screen "What's on my screen?"

For the server, set it once in config.toml instead — [intelligence] num_ctx = 32768 — so the desktop chat keeps room for its history after the 10 000-token tool prefix (see docs/development/diagnostic-performances-2026-09-19.md). The environment variable still wins when both are set.

Weather questions read Environment Canada's 7-day forecast page for the city named in the question; when no city is named, the chat uses [tools] ville = "Ottawa" from config.toml (any city of server/sources_officielles.py's table). With no city configured, the question must name one — Diapason never guesses a place.

Keep vision on-device

Images are sensitive. Diapason prints a privacy warning before sending an image to a non-local engine, so a screenshot never leaves your machine unnoticed. Use a local engine (e.g. ollama with gemma3:4b) to keep vision fully local.

JSON Output Format

When using --json in direct mode, the output includes:

{
  "content": "The response text...",
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 85,
    "total_tokens": 97
  }
}

When using --json in agent mode, the output includes:

{
  "content": "The response text...",
  "turns": 3,
  "tool_results": [
    {
      "tool_name": "calculator",
      "content": "51.0",
      "success": true
    }
  ]
}

diapason model

Manage and inspect language models available on running engines.

diapason model list

List all models available from running inference engines, displayed as a Rich table with model parameters, context length, and VRAM requirements.

diapason model list

Example output:

           Available Models
┌─────────┬────────────────┬────────┬─────────┬──────┐
│ Engine  │ Model          │ Params │ Context │ VRAM │
├─────────┼────────────────┼────────┼─────────┼──────┤
│ ollama  │ qwen3:8b       │ 8B     │ 32,768  │ 6GB  │
│ ollama  │ llama3.2:3b    │ 3B     │ 8,192   │ 3GB  │
└─────────┴────────────────┴────────┴─────────┴──────┘

diapason model info <model>

Show detailed information about a specific model.

diapason model info qwen3:8b

Example output:

┌─ Qwen 3 8B ──────────────────────────────┐
│ Model ID:     qwen3:8b                    │
│ Name:         Qwen 3 8B                   │
│ Parameters:   8B                          │
│ Context:      32,768                      │
│ Quantization: none                        │
│ Min VRAM:     6GB                         │
│ Engines:      ollama, vllm                │
│ Provider:     Alibaba                     │
│ API Key:      not required                │
└───────────────────────────────────────────┘

diapason model pull <model>

Download a model via Ollama. Shows a progress bar during download.

diapason model pull qwen3:8b

Note

The pull command requires a running Ollama instance. It connects to the Ollama API at the host configured in your config.toml.


diapason pearl

Access Pearl's native node, wallet, and RPC tools from the Diapason CLI.

diapason pearl doctor
diapason pearl node -- <pearld args>
diapason pearl wallet -- <oyster args>
diapason pearl ctl -- <prlctl args>
diapason pearl address

All Pearl wrapper commands use the diapason pearl <command> shape. The pass-through commands map to Pearl's native binaries:

Diapason command Pearl binary Use
diapason pearl doctor n/a Check whether pearld, oyster, and prlctl are discoverable
diapason pearl node pearld Run the Pearl full node
diapason pearl wallet oyster Run the Oyster wallet daemon
diapason pearl ctl prlctl Query Pearl node or wallet RPC
diapason pearl address prlctl --wallet getnewaddress Generate a wallet address from Oyster

Use PEARL_HOME=/path/to/pearl or --pearl-home /path/to/pearl if Pearl's bin/ directory is not on PATH. See the Pearl CLI guide for examples.


diapason memory

Manage the document memory store for retrieval-augmented generation.

diapason memory index <path>

Index documents from a file or directory into the memory store.

diapason memory index ./docs/
diapason memory index ./notes.md
diapason memory index ./data/ --chunk-size 256 --chunk-overlap 32
diapason memory index ./docs/ --backend sqlite
Option Type Default Description
--backend, -b string config Override the default memory backend
--chunk-size int 512 Chunk size in tokens
--chunk-overlap int 64 Overlap between chunks in tokens

The ingestion pipeline supports text, markdown, code files, and PDF (with pdfplumber installed). Binary files and hidden directories are automatically skipped.

diapason memory search <query>

Search the memory store for relevant document chunks.

diapason memory search "machine learning basics"
diapason memory search -k 10 "neural networks"
diapason memory search --backend faiss "embeddings"
Option Type Default Description
--top-k, -k int 5 Number of results to return
--backend, -b string config Override the default memory backend

Results are displayed in a table with rank, score, source file, and a content preview.

diapason memory stats

Show memory store statistics including document count and database size.

diapason memory stats
diapason memory stats --backend sqlite
Option Type Default Description
--backend, -b string config Override the default memory backend

diapason telemetry

Query and manage inference telemetry data stored in SQLite.

diapason telemetry stats

Show aggregated telemetry statistics including total calls, tokens, cost, and latency, broken down by model and engine.

diapason telemetry stats
diapason telemetry stats -n 5    # Show top 5 models
Option Type Default Description
-n, --top int 10 Number of top models to show

diapason telemetry export

Export raw telemetry records in JSON or CSV format.

diapason telemetry export                          # JSON to stdout
diapason telemetry export --format csv             # CSV to stdout
diapason telemetry export --format json -o data.json  # JSON to file
diapason telemetry export -f csv -o metrics.csv    # CSV to file
Option Type Default Description
-f, --format choice json Output format: json or csv
-o, --output path stdout Output file path

diapason telemetry clear

Delete all telemetry records from the database.

diapason telemetry clear         # Interactive confirmation
diapason telemetry clear --yes   # Skip confirmation
Option Type Default Description
-y, --yes flag off Skip confirmation prompt

Warning

This permanently deletes all stored telemetry data. Use --yes to skip the confirmation prompt in automated scripts.


diapason bench

Run inference benchmarks against a running engine.

diapason bench run

Execute benchmarks and report results.

diapason bench run                               # Run all benchmarks, 10 samples
diapason bench run -n 20                         # 20 samples per benchmark
diapason bench run -b latency                    # Only the latency benchmark
diapason bench run -b throughput -n 50 --json    # Throughput, 50 samples, JSON output
diapason bench run -o results.jsonl              # Write JSONL results to file
diapason bench run -m qwen3:8b -e ollama         # Specific model and engine
Option Type Default Description
-m, --model MODEL string auto Model to benchmark
-e, --engine ENGINE string auto Engine backend
-n, --samples N int 10 Number of samples per benchmark
-b, --benchmark NAME string all Specific benchmark to run
-o, --output PATH path none Write JSONL results to file
--json flag off Output JSON summary to stdout

Available benchmarks:

  • latency -- Measures per-call inference latency (mean, p50, p95, min, max)
  • throughput -- Measures tokens-per-second throughput

diapason channel

Manage messaging channels for multi-platform communication. Channels connect directly to platform APIs (Telegram, Discord, Slack, etc.) -- no gateway required.

diapason channel list

List registered channel backends and their connection status.

diapason channel list

diapason channel send

Send a message to a specific channel.

diapason channel send slack "Hello from Diapason!"
diapason channel send discord "Build complete"
Argument Type Description
TARGET string Channel name to send to
MESSAGE string Message content

diapason channel status

Show connection status for configured channels.

diapason channel status

Channel Dependencies

Each channel requires its platform-specific credentials (bot tokens, API keys) configured in the [channel.<platform>] section of your config. See Configuration for details.


diapason serve

Start an OpenAI-compatible API server.

diapason serve                                      # Default host/port from config
diapason serve --port 8000                          # Custom port
diapason serve --model qwen3:8b                     # Specify default model
diapason serve --agent orchestrator                 # Route requests through an agent

# Let your other devices reach this machine — mesh routes only, on a
# second socket. The full application stays on 127.0.0.1.
diapason serve --lan-host 0.0.0.0                   # Mesh on 0.0.0.0:8001
diapason serve --lan-host 0.0.0.0 --lan-port 8123   # …on another port
Option Type Default Description
--host HOST string config Bind address for the full application
--port PORT int config Port number
--lan-host HOST string none Listen address of the mesh alone, on a second socket (e.g. 0.0.0.0). Omitted: no second socket at all
--lan-port PORT int 8001 Port of that second socket. Must differ from --port
-e, --engine ENGINE string auto Engine backend
-m, --model MODEL string config Default model for inference
-a, --agent AGENT string none Agent for non-streaming requests

Server Dependencies

The serve command requires the server extra:

uv sync --extra server

This installs FastAPI, uvicorn, and related dependencies.

Two sockets, one process

--host carries the whole application and is meant to stay on 127.0.0.1. --lan-host opens a second socket that mounts nine mesh routes and nothing else (create_lan_app in src/diapason/server/app.py):

Method Path Description
POST /v1/mesh/pairings/redeem Redeem an invitation code
POST /v1/mesh/commands/deliver Deliver a command to this device
POST /v1/mesh/commands/poll Poll for commands addressed here
POST /v1/mesh/commands/ack Acknowledge a command
POST /v1/mesh/presence Presence beat from a peer
POST /v1/mesh/files/offer Offer a file, open a session
POST /v1/mesh/files/{session_id}/chunk Push one encrypted chunk
POST /v1/mesh/files/{session_id}/finish Verify the digest, reveal the file
POST /v1/mesh/files/{session_id}/status Which chunks are still missing (resume)

A few consequences worth knowing before you open that port:

  • POST /v1/chat/completions on the mesh socket answers 404, not 401 — the route is not mounted there at all. Chat, speech and Succès stay on --host.
  • Those nine routes authenticate by Ed25519 device signature, invitation or session token — not by the local API key.
  • The second socket serves no /docs, /redoc or OpenAPI schema.
  • Both sockets run in a single process: the command inbox and the transfer sessions live in memory, and two processes would lose them.
  • --lan-port equal to --port is refused before anything starts (exit code 2): on macOS both would bind silently, on Linux the second would fail.
  • When a second socket exists, it is the address peers are told to use — the mesh beacon announces --lan-host:--lan-port, not the loopback pair.

Startup prints the mesh line on its own line, before the Starting Diapason API server block:

  Maillage : http://0.0.0.0:8001 — neuf routes, créance d'appareil exigée

--host 0.0.0.0 still exists and still puts the entire API on the network, protected only by the local API key. Prefer --lan-host unless you genuinely want every route reachable.

API Endpoints

The server exposes the following OpenAI-compatible endpoints:

Method Path Description
POST /v1/chat/completions Chat completions (streaming & non-streaming)
GET /v1/models List available models
GET /health Health check
GET /v1/channels List available messaging channels
POST /v1/channels/send Send a message to a channel
GET /v1/channels/status Channel bridge connection status

Example with curl:

curl http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3:8b",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

When an agent is configured (e.g., --agent orchestrator), non-streaming requests are routed through the agent with access to all registered tools. For tool-capable agents (orchestrator, react, openhands), all registered tools are automatically loaded and made available.


diapason serve-service

Keep the API server running at login, as a macOS LaunchAgent. All subcommands exit with an error on any other platform.

diapason serve-service install                    # 127.0.0.1:8000, at every login
diapason serve-service install --maillage-reseau  # …plus the mesh on 0.0.0.0:8001
diapason serve-service status
diapason serve-service restart
diapason serve-service logs --lines 100
diapason serve-service uninstall

diapason serve-service install

Option Type Default Description
--host HOST string 127.0.0.1 Bind address of the full application. A non-loopback value is refused
--port PORT int 8000 Port of the full application
--maillage-reseau flag off Also open the mesh socket on 0.0.0.0
--lan-port PORT int 8001 Port of that mesh socket

--maillage-reseau adds --lan-host 0.0.0.0 --lan-port <port> to the serve command line written into the plist — the nine mesh routes, device signature required. The full application stays on the loopback either way. Installing prints a warning first, because any machine on your network will be able to reach that port.

--allow-network is gone

The old --allow-network put the entire API on the network. It no longer installs anything: the command fails, names --maillage-reseau as its replacement, and exits non-zero. It fails rather than aliasing quietly — the same command must not start doing something else without saying so.

Other refusals, all before anything is installed:

  • --host anywhere but 127.0.0.1, localhost or ::1.
  • --lan-port equal to --port when --maillage-reseau is set.
  • --port already served by something that is not this agent. Installing means launching (the plist carries RunAtLoad), so a second server on the same port would be a silent duplicate. Re-installing over Diapason's own service is allowed — launchd replaces a job of the same label.

status reports four separate facts: whether the LaunchAgent is loaded, where its plist lives, whether http://127.0.0.1:8000/health actually answers, and where the logs are. Loaded is not the same as answering. See the launchd deployment guide for the plist itself.


diapason mesh

The fleet of paired devices: join one, see who is in it, send a file to it. Pairing is invitation-based — the host machine shows a code under Appareils → Ajouter un appareil (the Devices page), and the guest redeems it here.

diapason mesh join

Join another Diapason's fleet.

diapason mesh join 192.168.0.5:8000 ABCD-1234
diapason mesh join 192.168.0.5:8001 ABCD-1234 --address 192.168.0.9:8001
Argument Type Description
HOST string The other machine's address, e.g. 192.168.0.5:8000
TOKEN string The invitation code it shows in Appareils → Ajouter un appareil
Option Type Default Description
--address ADDR string guessed The address this device is reachable at

On success it prints the host's fleet identity, its device id, its address, and the capabilities granted so far — or rien pour l'instant when none were, rather than letting you assume a permission you did not receive. A refused pairing exits 1.

HOST may be the mesh socket as well as the main one: pairings/redeem is one of the nine routes carried there. A device whose registry already holds at least one non-revoked device — whatever its trust level — refuses to join a different fleet; so does one whose registry cannot be read at all. Adopting another fleet identity would lose every peer it has at once, so the command stops and you decide.

diapason mesh devices

List the devices of the fleet, with their presence.

diapason mesh devices
diapason mesh devices --all   # include revoked devices

Columns: name, platform, trust level, presence, device id.

diapason mesh send

Send a file to a device of the fleet.

diapason mesh send ~/Documents/rapport.pdf "mon PC"
diapason mesh send ./photo.jpg "mon téléphone"
Argument Type Description
FICHIER path The file to send. Must exist and not be a directory
APPAREIL string The target, designated the way the mesh resolver reads it: by name ("PC du bureau") or by kind ("mon téléphone"). A device id is not accepted — the resolver matches names, device types and platforms only

The command takes no options. What it does, in order:

  1. Reads the registry and keeps only TRUSTED devices. With none paired it says so and exits 1.
  2. Resolves APPAREIL through the mesh resolver. A phrase that designates two devices is refused, never settled at random; so is one that matches nothing, or that means this very machine. The resolver's own sentence is printed verbatim and the command exits 1.
  3. Prints the file name and its human-readable size, then a n/total morceaux counter as the chunks go out.
  4. Prints the receiver's message: green when the transfer landed (COMPLETE, or ALREADY_PRESENT when content-deduplication found the file already there, whole and verified), yellow for any other status. When the receiver reports a path, it is shown as chez <device> : <path>.

A refusal from the recipient or the transport is relayed as it stands, in red, with exit code 1 — it knows why, the sender does not.

This is the first production caller of the file-transfer core: the peer must be reachable, which on a real network means it runs diapason serve with --lan-host (see Two sockets, one process).

diapason mesh whoami

Print this device's identity in the fleet: device id and name, platform, fleet (owner) id, and the public key. The private key appears nowhere.

diapason mesh whoami

LLM-guided spec search (no CLI yet)

LLM-guided spec search (the frontier-driven harness-learning subsystem) is exposed as a Python library only — there is currently no top-level diapason subcommand for it. Construct a SpecSearchOrchestrator directly from diapason.learning.spec_search.orchestrator and call .run(trigger) with a trigger from diapason.learning.spec_search.triggers. See docs/user-guide/llm-guided-spec-search.md for the architecture and the building blocks (splits.py, external corpora, external_adapter).