Non-Interactive Agent Queries#
How to use osprey query to run the OSPREY agent headlessly — in CI
pipelines, health checks, and automated workflows.
What You’ll Learn
What
osprey querydoes and when to reach for itHow project resolution works (
--project→OSPREY_PROJECT→ cwd)The
--jsonflag for machine-readable outputExit codes and what each means
The read-only guarantee and how it is enforced
How
osprey querydiffers fromosprey health
Prerequisites: A project built with osprey build.
Overview#
osprey query "<prompt>" boots the full OSPREY agent — MCP servers,
tools, provider authentication — passes your prompt, waits for a response,
and exits with a code that summarises the outcome. Write, execute, and
destructive tools are blocked at the SDK level (see Read-Only Guarantee
below): the command will not write to hardware, run shell commands or code,
or delete stored data, making it safe for CI pipelines and automated
workflows. (To deliver an answer it may still create workspace artifacts such
as plots — see the guarantee’s exact scope below.)
Use osprey query when you need to verify that the entire agent stack
works end-to-end against your real control system, not just that the model
is reachable.
Project Resolution#
osprey query resolves the project directory in this order:
--project DIRflag (explicit)OSPREY_PROJECTenvironment variableCurrent working directory (cwd)
# Explicit project
osprey query --project ~/projects/als-assistant "List vacuum sections"
# Via environment variable
export OSPREY_PROJECT=~/projects/als-assistant
osprey query "List vacuum sections"
# Current directory (cwd)
cd ~/projects/als-assistant
osprey query "List vacuum sections"
The command exits with code 2 if no valid project is found at the
resolved path.
Exit Codes#
Code |
Meaning |
When it occurs |
|---|---|---|
|
Pass |
The agent completed without error and all expected MCP servers connected. |
|
Verdict fail |
The agent ran but the outcome was unsatisfactory: a required MCP server was missing from the session, the agent returned an error result, or the run hit its cost budget (USD) or turn limit. |
|
Infra / usage error |
The run never started: no project found at the resolved path, the agent SDK is not installed, or the provider is not configured. |
Machine-Readable Output (--json)#
Pass --json to receive a structured JSON object instead of plain text:
osprey query --json "Summarise recent alarms"
Output format:
{
"final_text": "...",
"tool_traces": [
{"name": "tool_name", "input": {}, "result": "...", "is_error": false}
],
"mcp_servers": {"controls": "connected", "ariel": "connected"},
"exit_code": 0
}
mcp_servers maps each expected server name to its connection-status
string (e.g. "connected") from the MCP readiness snapshot taken before
the prompt is sent. exit_code repeats the shell exit code so the whole
verdict is self-contained in the JSON object.
Read-Only Guarantee#
osprey query enforces read-only execution at the SDK level by passing a
comprehensive disallowed_tools list directly to the runner. The agent
cannot call any of these tools even if it tries. The list is the union of:
Built-in write/exec/network tools —
Bash(arbitrary shell, which could itself write hardware viacaput),Write,Edit,MultiEdit,NotebookEdit,WebFetch,WebSearch.Control-system write tools —
mcp__controls__channel_writeandmcp__python__execute(plus any facility-specific tools in the project’shook_config.jsonwrite_toolsblock). These are always included even if a project’shook_config.jsonomits them.Approval-required MCP actions — every tool a framework MCP server marks as side-effecting (e.g.
mcp__ariel__entry_createlogbook writes,mcp__python__execute_file,mcp__osprey_workspace__setup_patch), derived from the server registry so the blocked set tracks the framework rather than a hand-maintained copy.Destructive workspace tools —
data_delete,artifact_delete, andartifact_delete_all, which permanently remove stored data/artifacts.Facility-custom write tools — any tool a custom MCP server in
claude_code.serversmarks underpermissions.ask(or a custom server that writes-check-gates all its tools) is blocked too. Declare custom write tools underpermissions.askso the read-only path recognises them.
Audited read tools (e.g. mcp__controls__channel_read) remain available.
The agent may still create workspace artifacts (plots, documents) and write
session logs to deliver its answer — these are additive and regenerable. The
guarantee is specifically that the run performs no hardware write, no code or
shell execution, and no deletion of stored data.
There is no --allow-writes flag. If you need an agent run that can write,
use osprey claude chat or the event-dispatch pipeline instead.
Note
This guarantee is independent of the claude_code.permissions settings
in config.yml: the headless runner uses bypassPermissions (under
which the interactive allow/deny/approval guards are inert), so the
read-only guarantee rests entirely on the SDK-level disallowed_tools
block. That is precisely why the block must cover the built-in and
approval-required tools above, not just the hook_config.json write list.
CI Loop Pattern#
Important
OSPREY ships no canned queries. A query that references a channel address, PV name, or subsystem label only makes sense for your facility. Write queries that reflect your real control system — a generic query cannot validate a facility-specific agent.
The recommended CI pattern is a direct || exit 1 guard:
osprey query "What PVs are used for beam current?" || exit 1
For pipelines that parse results, use --json and jq:
result=$(osprey query --json "Summarise recent alarms")
echo "$result" | jq '.final_text'
echo "$result" | jq '.exit_code'
For a project not in the current directory:
osprey query \
--project /opt/osprey/als-assistant \
"List all vacuum sections" \
|| exit 1
osprey query vs. osprey health#
|
|
|---|---|
Raw model ping — “can I reach the model?” |
Full agent run — “does the agent boot its MCP servers and answer against my control system?” |
Checks configuration, connectivity, and optionally sends a minimal test prompt |
Sends your real prompt through the full MCP + tools stack |
Fast; optional API cost |
Slower; costs one normal agent run |
Good for diagnosing a broken install |
Good for verifying end-to-end agent capability in CI |
Run osprey health first when something is wrong with the install.
Run osprey query to confirm the agent answers control-system questions
correctly once the install is healthy.
See also
- Use the CLI Chat Interface
Interactive agent sessions in your native terminal.
- Event Dispatch
Turn external events into headless agent runs via webhooks and cron.
- CLI Reference
Full
osprey queryandosprey healthcommand reference.