
Agent
Interoperability
Security and permissions
Web applications
Monitoring
Fixes
Safety
Known issue
Requires InterSystems IRIS or IRIS for Health 2026.2 or later. Upgrading from 1.0.11 keeps your agent definitions, conversations, settings and audit records.

1st place in the Experts Nomination and 2nd place in the Freshmen Nomination of the InterSystems Programming Contest: Build Your Own Management Portal.
An agent co-pilot for the InterSystems IRIS System Management Portal.
A rebuilt portal for the six areas administrators live in, with an AI agent beside every screen.
Try it · Live demo · Video · Quick start · Get a key · Walkthrough · Article · Developer reference
OcuPilot is an Angular portal served from the IRIS instance itself, with an ObjectScript REST API
behind it. It covers the six areas named by InterSystems’ “Build Your Own Management
Portal” contest - web applications, permissions,
security and secrets, tasks, OS management and the logs - with list screens, row actions and full
editors that work against live instance data. Home adds the instance’s performance and a list of
security and operational findings, each with a fix you can review, and a log hub merges every log
the instance keeps into one timeline.
A panel docked on the right of every screen holds the agent: a language model you choose - Claude,
GPT, Gemini, or a model on your own network. You ask in your own words, about any screen. It answers
from the rows in front of you, opens the screen a conversation is about, and can propose any change
the screens themselves make - everything except its own configuration - through tools that run
strictly as you. Every change it wants to make is shown as a proposal you confirm; nothing changes
until you press Confirm. The change then runs with your own privileges, is marked in the IRIS
audit database as an agent write, and the screen refreshes and marks the row that changed.
In your browser, with nothing to install. Open ocupilot.org, choose
Open the demo and sign in as demo with the password ocupilot-demo. It runs the current release
on a real IRIS for Health instance, and the agent already has a model, so you need no key.
/csp/myapp as Changed.demo.operator with the password ocupilot-operator, and ask for the same change:Everyone shares the demo, and it resets at the top of every hour, offline for a few minutes while it
does. If you land on a reset, watch the three-minute video first.

What needs attention - Home shows the instance’s performance and its findings; Fix it asks
the agent for a proposal, which waits for your Confirm.

Every log in one timeline - the unified log hub merges messages.log, the audit database and
the other logs, newest first, and any entry can be explained.

The dashboard - performance, system usage, errors, licensing and the Task Manager at a glance.

The guardrails, in one place - what the agent and the screens refuse, what always needs your
Confirm and what is never sent to the model, read from the rules the instance enforces.

Who can do what - a user’s effective privileges, each resource with the role or public
permission that grants it, and Check permission for any user or role.

Disks, not only a list of them - mount, dismount, truncate, compact and defragment a database,
and a three-step integrity check with its own log.

Asking about the screen you are on - the agent reads the task schedule and history and explains
what needs attention.

Full editors - here the SSL/TLS configuration editor, with its connection test.

Fewer privileges, plainly explained - signed in as operator, the agent declines a security
change and says what would be needed; Home marks the screens this user may not open.

Light and dark - every screen in both themes.

On your own machine, with Docker only:
git clone https://github.com/jbrandtmse/OcuPilot.git
cd OcuPilot
docker compose up -d --wait
Then open http://localhost:52774/ocupilot/ and sign in as _SYSTEM / SYS. The first start takes a
few minutes. Every screen works without a model; for the agent, add a key under
Connect a model. On your own IRIS 2026.2 or later, zpm "install ocupilot"
installs the same thing.
Built on the SysAdmin API. Screens and the agent’s tools call the /api/admin v2 operations
described in the published specification,
in process and as the signed-in user, so IRIS checks your privileges on every call. Building OcuPilot
turned up seven places where the specification and IRIS 2026.2 disagree; three are
reported upstream as issue #1
and issue #2.
OcuPilot/Security/AgentWrite, the screen marks the changed row, and a read-back line says%All holder, _SYSTEM, the signed-in user, the service%All, certificates that expire within 30 days, auditing switched off, dismounted orCtrl+K),| Area | Screens | What you can do |
|---|---|---|
| Web applications | Web applications, web sessions, REST API explorer, OpenAPI document viewer, %-class access, Doc DB applications, privileged routine applications | Create, edit, enable, disable and delete applications; end web sessions; browse every REST application’s endpoints, send a request from its OpenAPI document and copy it as curl; create a spec-based REST service from an OpenAPI document and delete one; grant and remove %-class access; create, edit and delete Doc DB applications and privileged routine applications, with their roles, matching roles and routines |
| Permissions | Users, roles, resources, services, SQL privileges, SQL column privileges, SQL admin privileges | Create and edit users and roles, set passwords, grant and revoke roles and resource permissions; edit services - enabled state, allowed IP addresses, roles and authentication methods; see a user’s effective privileges, and check whether a user or role holds a permission and through which role; copy a new user from an existing one, set the password rules, and see and set each role member’s admin option; grant and revoke SQL privileges on objects and columns, and SQL admin privileges |
| Security and secrets | SSL/TLS, X.509 credentials, wallet, OAuth 2.0 (client server descriptions, client configurations, resource servers, the authorization server, server client descriptions), LDAP, auditing, allowed directories, encryption key files, database encryption, data element encryption, authentication options, superservers, managed file transfer | Editors for each, SSL/TLS and LDAP connection tests, an LDAP test sign-in that keeps no password, OAuth token revocation, audit event configuration, and audit database copy and purge; create an encryption key file and add or remove its keys and administrators; removing a key that OcuPilot, a protected database or the journal depends on is refused; activate and deactivate database and data element encryption keys; change the encryption startup settings, where turning on audit-log encryption takes the strongest confirmation and asking for the key at startup is refused while the audit log or a system database is encrypted; change the authentication and web session options; create, edit and delete superservers and managed file transfer connections, and revoke a connection’s token; create and replace RSA and symmetric-key wallet secrets |
| Tasks | Task schedule, on-demand tasks, upcoming tasks, task history, task details, background tasks | A New Task wizard, edit, run, suspend, resume and delete; export and import tasks; suspend and resume the Task Manager itself; pause, resume and cancel background tasks |
| OS management | Processes, process details, locks, system usage, dashboard, license usage, databases, local databases, remote databases, journals, journal settings, journal records, license key, license servers, ECP data servers, ECP settings, ECP application servers, SQL activity, integrity check and its log, namespaces, devices, external language servers, the dashboard’s detail views (ECP, global and routine, most active processes, system resources), Prometheus metrics | Suspend, resume and terminate processes; remove a lock, all of a process’s locks or all of a remote client’s; broadcast a message to terminal sessions; create, edit and delete local databases, optionally with their files; create, edit and delete remote databases on an ECP data server; list journal files and page through their records, switch to a new journal file or directory, check a journal’s integrity and change the journal settings; validate and activate a license key; create, edit and delete license servers; create, edit and delete ECP data servers and change their status; change the ECP settings; see the application servers connected to this one, and authorize, reject or delete their SSL/TLS requests; see the SQL statements running right now, slowest first, and open the process behind one; mount, dismount, truncate, compact, defragment, expand and grow databases, with progress for the long ones; run the integrity check and read its log; create, edit and delete namespaces and their global, routine and package mappings, and copy mappings between namespaces; enable interoperability on a namespace; edit devices; free space per database; create, edit, delete, start and stop external language servers and read their activity log; open the dashboard’s detail views; read the instance’s Prometheus metrics as a table |
| Logs | A unified log hub; alerts.log, messages.log and its older files, application errors, the audit database, and six more: the System Monitor log, background task errors, xDBC errors, SQL diagnostics, the interoperability event log and the analytics log |
See every log in one list and one timeline, newest first; search and page each log, filter the audit database to agent writes, delete application errors, and ask the agent to explain any entry, which it reads alongside the rest of the page |
Four more areas sit beside the six. Home shows the instance’s performance, refreshing itself,
and its findings. Interoperability appears in namespaces where it is enabled: start, stop,
restart, update and recover productions; enable, disable, add and remove production items, with tabs
for each item’s status, queue, jobs, messages and log, and a Test tab that sends it a request; view
and change item settings, where settings that look like passwords or keys stay hidden and are changed
in the classic portal; watch the production monitor; abort queues, queued messages and jobs, and
suspend or stop a job; list business processes, business rules and data transformations; create and
edit lookup tables and their entries, with .LUT import and export; and view business partners.
Accounts that use the classic Interoperability pages can sign in to OcuPilot for these screens. System Explorer lists a namespace’s classes and routines, shows and edits their
source, shows a class’s reference page from the instance’s own class documentation, searches source, compares two documents line by line and finds where a macro is defined; it
compiles and deletes them, exports them as XML to a file on the server or a download, and imports an
XML export or a source file from the server or your computer. Its SQL catalog lists schemas, tables,
views and procedures with their details, limited to what your own SQL privileges show. SQL query runs
a statement as you, with your SQL privileges: a query runs at once, a statement that changes data or
the schema runs only after you confirm it, a long query can run in the background, and statements
that would manage users, databases or OcuPilot’s own tables are refused. The data browser opens
tables in tabs and pages through their rows with filter and sort, goes to a row number and downloads
the page as CSV. You can edit, add, duplicate and delete rows, and they are saved in one step after
you confirm, as you, with your SQL privileges. Document databases lists a namespace’s DocDB
databases, creates one, and drops one after you type its name; it needs the %Service_DocDB
service enabled. What you type into SQL query and the
rows it returns stay on your screen and do not reach the agent through screen context. The agent has
its own SQL tool: it runs read-only queries as you, with your SQL privileges, masks columns whose
names suggest credentials and refuses DDL that carries code, and what it reads goes to your model
provider like any other tool result. A statement that changes data or the schema is a proposal you
confirm, and that action starts switched off. A picker chooses which agent definition a conversation
uses; picking another starts a new conversation, and a turn replays only earlier turns that ran under
the same definition, so a conversation’s history never goes to a different provider. As in the
classic portal, browsing needs only %Development and read access to the namespace’s code database,
so a developer with no administration role can use it; changing code also needs write access to that
database, and OcuPilot’s own classes are refused. Saving table rows is a person’s action only. The
agent can propose saving an edit to a class or routine, or creating a new one, and saves only after
you confirm; a source save is refused if someone else changed the document since it was read.
Agent co-pilot holds the agent’s definitions, switches and governance policy for administrators,
the Screen permissions list, which shows the permission each screen requires and lets an
administrator adjust it, and for everyone the Guardrails page, your transcripts, and the agent audit ledger of each model
call, tool call and confirmed write.
An area opens when you may use any of its screens, and each screen still checks your own
privileges.
You need Docker (Docker Desktop on macOS or Windows, or Docker Engine with Compose v2 on Linux)
and nothing else.
git clone https://github.com/jbrandtmse/OcuPilot.git
cd OcuPilot
docker compose up -d --wait
The first start takes a few minutes: IRIS for Health Community starts, then the container compiles
and installs OcuPilot. --wait returns once the health check reports OcuPilot installed.
Then open http://localhost:52774/ocupilot/ and sign in as _SYSTEM with the password SYS.
Community Edition ships the _SYSTEM password already expired; OcuPilot’s first install clears that,
so you are not asked to change it.
The host ports are 52774 (web) and 1973 (SuperServer), one above the IRIS defaults, so OcuPilot can
run beside an IRIS container you already have. The classic Management Portal stays available at
http://localhost:52774/csp/sys/UtilHome.csp.
The first time an administrator signs in with no model configured, OcuPilot opens the agent
definition form. It opens only that once: Cancel takes you to Home, and every screen works
without a model.
The key is never shown again: the field reads “Stored” and takes a new value only to replace it.
New definitions can propose changes; every change still waits for your Confirm.
The Docker path installs a small set of demonstration objects, so every screen has something to show
and the agent has something to fix. The IPM install never creates them.
/csp/myapp, a disabled web application with no resourceOcuPilotDemoTLS, an SSL/TLS configuration, and OcuPilotDemoCert, a self-signed X.509OcuPilotDemo.Sample, a wallet collectionTo install without them, remove OCUPILOT_DEMO: "1" from docker-compose.yml before the first
start.
Your agent definitions, keys, conversations, settings and audit records live in ./iris-data and
carry over.
git pull
docker compose restart iris
docker compose up -d --wait
docker compose up on its own does not update: the running container keeps the release it started
with. The restart installs the new release over the same data, and --wait returns once the health
check reports it installed.
Since 1.0.2, OcuPilot removes agent conversations older than each agent definition’s Retention
(30 days unless you change it) once a night, at 03:15 instance time. That includes conversations
from before the update. To keep them longer, raise Retention on the definition in Agent
co-pilot → Agent definitions right after you update.
In 1.0.3, the agent’s local database delete, namespace delete, task import and audit purge start
switched off, on an update as on a new install, unless you already set them explicitly. The screens
themselves still do all four; to let the agent propose them, turn them on under Agent co-pilot →
Governance policy.
In 1.0.4, the agent’s eight disk operations - mount, dismount, truncate, compact, defragment,
expand, grow and the integrity check - start switched off in the same way. The screens do all eight,
and settings you already made are kept.
From 1.0.5, an installed OcuPilot carries no test code. The first start after the update removes the
test classes earlier releases compiled into the install namespace, and its log says how many (835 on
a 1.0.4 install). Nothing you use changes.
In 1.0.6, the agent’s enable-interoperability action starts switched off in the same way. The
Namespaces screen does it for an account assigned the %All role itself, and settings you already
made are kept.
In 1.0.7, the agent’s remote database delete and its class and routine delete and import start
switched off in the same way; the screens do all five.
In 1.0.9, the agent’s license server and ECP data server deletes and its ECP data server status
change start switched off in the same way; the screens do all three.
In 1.0.10, the agent’s encryption key file actions - creating a key file, adding or removing a key,
adding or removing an administrator - and its deletion of an ECP application server’s SSL/TLS
authorization start switched off in the same way; the screens do all six.
In 1.0.11, seven more agent actions start switched off in the same way: activating or deactivating a
database or data element encryption key, changing the encryption startup settings, dropping a
document database, and running SQL that changes data or the schema. The screens do all seven, and
settings you already made are kept.
In 1.0.12, fifteen more agent actions start switched off in the same way: removing a production
item; aborting a job, a queue or a queued message; removing a lookup entry; deleting or importing a
lookup table; deleting a managed file transfer connection or revoking its token; replacing an RSA
wallet secret; deleting a superserver; and deleting a %-class access entry, a Doc DB application, a
REST service or a privileged routine application. The screens do all fifteen. The other way round,
the agent’s saves of classes and routines now start switched on: after the update it offers to save
edits and create new ones, each only after you confirm, unless you had switched those saves off
yourself, which is kept. Passwords typed as literals in SQL statements are now masked where
statement text is shown and before it reaches the agent.
| Provider | Default model | Where to get a key |
|---|---|---|
| Anthropic | claude-opus-5-5 |
console.anthropic.com → Settings → API keys |
| OpenAI | gpt-5.6-terra |
platform.openai.com/api-keys |
| Google Gemini | gemini-3.8-flash |
aistudio.google.com/apikey |
| OpenAI-compatible | none - you name it | Your own server: Ollama, vLLM, LM Studio and others |
http://host.docker.internal:11434/v1 - tick Local model andServer_Response_Timeout for a slow model; OcuPilot never changes that setting itself, andRequires InterSystems IRIS or IRIS for Health 2026.2 or later. OcuPilot is built on version 2
of the IRIS admin API, which first shipped in 2026.2, so it does not run on earlier versions. The
Docker quick start already uses 2026.2. If you install with IPM, check your instance first:
theintersystemsdc/iris-community:latestandintersystemsdc/irishealth-community:latestimages
are currently 2026.1, so use their2026.2tags instead (for example
intersystemsdc/irishealth-community:2026.2-zpm). IPM refuses to install OcuPilot on an older
version.
OcuPilot is also one IPM package. In the namespace you want it in (not %SYS or another system
namespace):
zpm "install ocupilot"
If IPM answers that no repositories are configured, run zpm "enable -community" once, then
install again.
Then open /ocupilot/ on that instance’s web server. Two things differ from the container path:
IPM never clears an expired _SYSTEM password, and it creates no demonstration objects. The
installer grants the OcuPilotAdmin role to the account that runs the install when that is a named
user; otherwise it prints the one command that grants it. OcuPilot needs IRIS or IRIS for Health
2026.2 or later and IPM 0.10.0 or later. On plain IRIS Community, which has no HSCUSTOM
namespace, the container installs into USER.
OcuPilot signs each person in with their own IRIS account, and every screen checks that account’s
privileges. An account whose only role is %Manager also needs read access to the database of the
namespace OcuPilot is installed in, for example %DB_HSCUSTOM; without it, every request is
refused.
OcuPilot is an administration tool, so it says plainly what it adds to an instance.
OCUPILOT, guarded by the %DB_OCUPILOT resource, which no ordinary roleOcuPilotAdmin resource and role, which gate the agent’s configuration. Using the agent/ocupilot (the portal’s static files, served unauthenticated),/api/ocupilot (the REST API: password sign-in, JWT, no server session) and/api/ocupilot/readiness.OcuPilotState and OcuPilotIdentity, a global mappingOcuPilotProvider, for model calls.OcuPilot/Security/AgentWrite, ConfigChange, SecurityChange, RoleGranted, LedgerRead).Uninstalling (zpm "uninstall ocupilot") removes what the installer created.
Open Web applications and ask the agent: “Enable /csp/myapp and give it the %Development
resource.” If you ask from another screen, the agent opens this one first.
The proposal card appears. It names the target, shows the fields that change with their
current and new values - computed on the instance from a fresh read, not by the model - the
privilege the change needs, and how to reverse it.

Press Confirm. OcuPilot re-checks that you still hold the privilege, that the target has not
changed since the proposal was made, and that the change is not prohibited, then runs it as you.
The screen refreshes and marks /csp/myapp as Changed, with a read-back line that says the
instance now holds the new values; the panel shows the change done and audit-marked, confirmed by
you.

Open Logs → Audit database, tick Agent-marked events only and press Search: the
change is there as an OcuPilot/Security/AgentWrite event.

A proposal expires after ten minutes and can be confirmed once. It is refused if, in between, the
target changes, you are no longer the user who asked, or the conversation, the agent definition or
the read-only state changes.
Everything the portal does goes through OcuPilot’s REST API at /api/ocupilot, which accepts your
IRIS user name and password, so the same work can be scripted. Reading a screen returns its rows:
curl -s -u demo:ocupilot-demo \
"https://demo.ocupilot.org/api/ocupilot/screens/webapp.list/read?maxRows=5"
Asking the agent takes three calls: start a conversation, send a message, and follow the turn until
it completes. Any change it wants to make comes back as a proposal, which you confirm with your own
credentials:
B=https://demo.ocupilot.org/api/ocupilot
C=$(curl -s -u demo:ocupilot-demo -X POST -H 'Content-Type: application/json' -d '{}' $B/conversation | jq -r .conversationId)
T=$(curl -s -u demo:ocupilot-demo -X POST -H 'Content-Type: application/json' \
-d "{\"conversationId\":\"$C\",\"message\":\"Which web applications are disabled?\"}" $B/turn | jq -r .turnId)
curl -s -u demo:ocupilot-demo $B/turn/$T/progress | jq '{state, reply, proposals}'
# once a proposal is shown: curl -s -u demo:ocupilot-demo -X POST -H 'Content-Type: application/json' -d '{}' $B/proposal//confirm
Against your own install, use http://localhost:52774/api/ocupilot and your own account.
For any other REST application on the instance, the OpenAPI document viewer’s Try it sends a
request from the portal, and Copy as curl gives you the same request for a script, with the
token and hidden values left as placeholders.

/ocupilot; the API, the agent/api/admin v2 operationsmessages.log, alerts.log and the/api/mgmnt.%UnitTest classes run inside IRIS; 116 Node test files and 239 Angular componentbash scripts/smoke.sh --container ocupilot --user _SYSTEM --password SYS asks the running instance whether OcuPilot works; the assertions live insideHTTP 401 from everything on a fresh container: the _SYSTEM password is still expired. The
first install clears it, so this usually means an older iris-data/ folder was reused. Clear it
with:
docker compose exec -T iris iris session iris -U "%SYS" '##class(Security.Users).UnExpireUserPasswords("_SYSTEM")'
docker compose up --wait reports the container unhealthy: run docker compose logs iris and
look for the container-start: lines. LOAD-FAILED means a compile error, STARTPATH-FAILED
names the install step that failed. A failed install is retried three times and then left
stopped; fix the cause and run docker compose up -d --wait again.
On Windows, the container stops at once with set: Illegal option -: the clone checked the
start scripts out with Windows line endings. A clone of 1.0.4 or later is not affected. In a clone
made before 1.0.4, run this once from its folder after git pull, then start again; it replaces any
local edits in those three folders:
git checkout HEAD -- scripts .githooks _bmad/scripts
Test connection says the model did not answer in time: see the local-model note under
Get a model key.
Anthropic refuses the key: create a key inside one workspace.
Ports 52774 or 1973 are taken: change the host side of the two port mappings in
docker-compose.yml.
OcuPilot implements three ideas from the InterSystems Ideas portal
that carry Community Opportunity status:
messages.log line, alert or audit record in front of itmessages.log viewer opens every older messages file the instance keeps, with theNew releases arrive about once a week, each installed and tested on a clean machine before it
reaches main. Next:
After that, OcuPilot grows toward parity with the classic portal: backup and mirroring, startup and
memory settings, locales and SQL settings, the globals pages and the SQL tuning tools, and an undo
for the agent’s changes.
https://github.com/jbrandtmse/OcuPilot/blob/main/docs/DEVELOPMENT.md is the contributor reference: the development container
and its start path, the installer, the smoke script and CI, the IPM manifest, VS Code setup and the
IRIS MCP server suite. Building the client needs Node ^22.22.3, ^24.15.0 or ^26.0.0. To run the
ObjectScript test suite in the container, set OCUPILOT_LOAD_TESTS: "1" in its environment in
docker-compose.yml and recreate it with docker compose up -d --wait; a restart does not apply
a changed environment.
OcuPilot was planned and built with the BMAD Method,
with Claude Code as the development agents: research, a product brief and PRD, UX design and an
architecture spine first, then every story through the same spec, implementation, QA, code review
and CI cycle. The planning documents are under
https://github.com/jbrandtmse/OcuPilot/blob/main/_bmad-output/planning-artifacts/.
MIT - see https://github.com/jbrandtmse/OcuPilot/blob/main/LICENSE. Third-party material redistributed with OcuPilot is listed in
https://github.com/jbrandtmse/OcuPilot/blob/main/ATTRIBUTIONS.md.