Production Control Systems Tutorial#
The Hello World Tutorial built a single-server agent that reads channels by their exact PV name. A production control room needs more: operators think in terms of devices and physics — “the booster’s defocusing quadrupole” — not PV strings; they need to search the electronic logbook, pull historical trends, and produce shift reports. This tutorial builds the control-assistant agent, which adds those capabilities on top of the same mock control system and the same safety model.
By the end you’ll have an agent that finds channels from natural-language descriptions, searches a seeded operations logbook, plots archived data, and runs control-room operator skills.
Prerequisites
Required:
Python 3.11+
Claude Code CLI installed
Osprey framework installed (
uv tool install osprey-framework, oruv sync --extra devif working from a clone)ANTHROPIC_API_KEYset in your environment
Recommended:
Finish the Hello World Tutorial first. This tutorial assumes you already understand the mock connector, the safety limits system, and the human-approval flow, and it does not re-teach them.
Note
New to Osprey? Start with the Hello World Tutorial.
It covers project layout, the controls MCP server, and the safety model
in detail — everything below builds directly on it.
Step 1: Build the Project#
Create a project from the control-assistant preset:
osprey build my-control-assistant --preset control-assistant
cd my-control-assistant
Like hello-world, this project starts in mock mode, so every example
below is safe to run with no hardware attached; hardware writes are still gated
behind the human-approval prompt. Unlike
hello-world, the preset ships a channel database, a seeded electronic
logbook, and a mock archiver, plus a set of sub-agents and operator skills.
Note
First run may take 1–2 minutes to create a virtual environment and install dependencies. Subsequent builds are near-instant.
Step 2: What’s Different from Hello World#
The control-assistant preset keeps the same controls MCP server and the
same safety hooks, then adds production capabilities. The most visible additions:
Capability |
What it adds |
|---|---|
Channel finder (sub-agent) |
Resolve channels from a natural-language description by exploring a channel database — no need to know PV names. |
Logbook search (sub-agents) |
|
Archiver + visualization |
A mock archiver serves historical data; the |
Operator skills |
|
Web terminal |
A browser split-pane UI with logbook and channel-finder panels (documented separately — see Run the Web Terminal). |
The safety model is unchanged: limits checking, the pre-write check, and the human-approval prompt all behave exactly as in the Hello World Tutorial. Refer back to that tutorial’s “Safety & Limits” step for the write-approval walkthrough — we won’t repeat it here.
Start the agent the same way as before, from the project directory:
claude
Note
On first run, the Osprey agent will ask you to trust the MCP servers in this project. Accept to allow the agent to use the control system and channel-finder tools.
Step 3: Find Channels by Description#
This is the headline capability. In Hello World you had to know the exact PV:
You: Read channel SR:BEAM:CURRENT
With the control assistant, you describe the channel in plain language and the agent figures out the PV for you:
You: Read the current in the booster's defocusing quadrupole
The main agent delegates to the channel-finder sub-agent, which explores the
channel database and resolves your description to a real PV before reading it.
The exact wording depends on your CLAUDE.md and output style, but you’ll see
something like:
Resolved "booster defocusing quadrupole current" → BR:MAG:QD:01:CURRENT:RB
Channel: BR:MAG:QD:01:CURRENT:RB
Value: 142.7 A
Status: OK
Try a few more descriptions — none of them require you to know the PV naming scheme:
You: What's the storage-ring beam current?
You: Show me the horizontal corrector magnet setpoints in the storage ring
The first resolves to SR:DIAG:DCCT:01:CURRENT:RB (the storage-ring DC current
transformer); the second resolves to the SR:MAG:HCM:*:CURRENT:SP family.
How it works. The channel database is organized as a hierarchy
(ring : system : family : device : field : subfield), and the channel-finder
agent navigates it systematically: it checks prior examples
(view_examples), explores the available options at each level
(get_options), then constructs and validates the final addresses
(build_channels). It never fabricates PV names — every channel it returns
comes from the database. For a deeper look at the finder and its other search
strategies, see How to Use the Channel Finder.
Step 4: Search the Electronic Logbook#
The control-assistant bundle seeds an electronic logbook with realistic operations entries — RF trips, vacuum maintenance, beam-recovery shifts, radiation surveys, and more. Ask the agent about past events in natural language:
You: Search the logbook for RF cavity temperature trips
The agent delegates to the logbook-search sub-agent, which matches the query against the logbook and summarizes what it finds:
Found 3 related entries:
- "Beam dump — RF cavity C1 reflected power trip (thermal excursion)"
- "Investigation: Recurring cavity C1 thermal excursions"
- "RF cavity C1 cooling manifold repair"
Summary: Cavity C1 tripped on reflected power after its temperature climbed;
a follow-up investigation traced it to reduced cooling-water flow, later fixed
by a manifold repair.
For questions that span several entries and need synthesis (for example, “trace the root cause of the recurring C1 trips and what finally resolved them”), the agent can use the logbook-deep-research sub-agent, which performs a multi-hop search and stitches the entries into a single narrative.
Step 5: Pull Historical Data and Plot It#
The bundle also configures a mock archiver that serves synthetic historical data, so you can exercise the trend-and-plot workflow without a real archive appliance. Ask for a trend:
You: Plot the storage-ring beam current over the last 24 hours
The agent finds the channel (SR:DIAG:DCCT:01:CURRENT:RB), reads its history
from the archiver, and delegates to the data-visualizer sub-agent to render
the result. The visualizer produces a self-contained figure artifact:
Read 1440 samples for SR:DIAG:DCCT:01:CURRENT:RB (last 24h).
Created interactive plot: beam_current_24h.html (artifact)
The data-visualizer can produce interactive Plotly figures, publication-quality
matplotlib images, dashboards, and LaTeX reports. In development everything runs
against the mock archiver; in production the same query hits your real archiver
(see Step 7).
Step 6: Run Operator Skills#
The preset installs control-room skills you invoke directly. A few worth trying:
Generate a shift report — summarize the session’s actions into a polished, self-contained HTML report:
You: /session-report
The skill asks what kind of report you want (chronological log, technical analysis, or executive briefing), gathers the session’s artifacts, and saves an HTML report to the artifact gallery.
Triage an infrastructure failure — when a tool call or server misbehaves:
You: /diagnose
/diagnose investigates Osprey infrastructure problems (failed tool calls,
connection errors, configuration drift) and produces a structured root-cause
report — it is for diagnosing the assistant, not the accelerator.
Other skills: demo-gallery generates a showcase of plot and report
artifacts to explore the gallery’s capabilities, and setup-mode inspects and
repairs the project’s configuration when something looks misconfigured.
Note
This project also ships a browser-based web terminal with logbook
and channel-finder panels. It has its own guide —
see Run the Web Terminal to launch it with osprey web.
Step 7: Tune the Assistant and Go to Production#
Choose a channel-finder strategy. The preset defaults to hierarchical
mode, which scales to large facilities with thousands of channels. For a small
facility (under ~1,000 channels) the in_context strategy can be simpler and
faster. The strategy is a build-time choice, so select it when you build:
osprey build my-control-assistant --preset control-assistant \
--set channel_finder_mode=in_context
See How to Use the Channel Finder for a comparison of the strategies.
Switch to real hardware. As in Hello World, moving to production is a
configuration change, not a code change. Point the connectors at your facility in
config.yml:
control_system:
type: epics # was: mock
archiver:
type: epics_archiver # was: mock_archiver
Because these are build-time inputs, regenerate the agent’s artifacts and relaunch:
osprey claude regen
claude
Your queries don’t change — “Read the current in the booster’s defocusing quadrupole” and “Plot the storage-ring beam current over the last 24 hours” now run against live EPICS and your real archiver. The connectors handle the difference; the agent, the channel finder, and your prompts stay the same.
Next Steps#
You’ve built a production-shaped control assistant with channel finding, logbook search, historical plotting, and operator skills. Where to go next:
Channel finder in depth: How to Use the Channel Finder compares the hierarchical, in-context, and middle-layer strategies and explains the database format.
Web terminal: Run the Web Terminal launches the browser UI and its panels with
osprey web.Tailor a preset to your facility: Build Profiles shows how to extend
control-assistantwith your own overrides and overlays.Architecture deep dive: the Conceptual Tutorial and the Architecture section explain the agent + MCP design, the connector system, and the safety mechanisms.
CLI reference: see CLI Reference for all
ospreycommands.