Clinical AI agents that show their work — and pass review.
Healthcare AI agents need to do three things audit-side: scope access by role, tag every memory write with [phi], and pause before any irreversible clinical action. ONTO ships all three as runtime primitives.
The pain.
Role-based access is non-negotiable.
Intake nurse, attending clinician, billing — each has a different scope of what they can read, write, and order. A general-purpose chat agent can't enforce that.
Every write has to be tagged and auditable.
Protected health information needs to be machine-marked at write time, not after the fact. "Tag PHI" is not a policy — it's a structural property of the memory model.
Some actions cannot be implicit.
Placing an order, scheduling imaging, sharing records — these are decisions the clinician makes, not the model. The agent proposes; the human approves.
Data stays inside the network.
For most US health systems, patient data cannot leave the VPC. Hosted-only agent SDKs are off the table.
The primitives that map to it.
Each piece of the pain above maps to a specific ONTO primitive — not a workaround layered on top.
Per-call consent scopes
Intake nurse runs with [memory:write, patient:intake]. Clinician runs with [memory:read, patient:order]. Same agent code; different consent at the call site.
Plan Mode
Clinician runs in plan_only mode. Tasks return for review. Nothing fires until the clinician approves task-by-task with execute scopes.
Regulation-tagged memory
Every assertion carries tags. [phi] writes are routed to a separate decay policy, encrypted at rest, and surfaced in the audit feed.
On-prem deployment
Postgres + pgvector + local Ollama. Helm chart in the repo. No data leaves your VPC.
A runnable example.
Same agent. Two roles. Different consent. The Policy Guard refuses any tool the role hasn't been granted — even if the LLM tries to call it.
from onto import Onto, Models, BuiltinTools
onto = Onto(model=Models.GPT_OSS_20B, builtin_tools=BuiltinTools.STANDARD)
# Intake nurse: can read patient data and write typed facts.
nurse_result = onto.run_sync(
"The patient reports chest pain and shortness of breath since this morning.",
user_id="patient_a912",
consent_scopes=["memory:write", "patient:intake"],
extract=True, # → typed assertions with [phi] tag
)
# Clinician: can read patient data, place orders. Cannot write arbitrary facts.
clinician_result = onto.run_sync(
"Summarize the intake history and propose next clinical steps.",
user_id="patient_a912",
mode="plan_only",
consent_scopes=["memory:read", "patient:order", "audit:write"],
)
# The clinician approves specific tasks → execute with same scopes.
for task in clinician_result.tasks:
if approved(task):
onto.execute_task(task, consent_scopes=["patient:order", "audit:write"]) Considerations at scale.
HIPAA audit trail
Every gate decision, every write, every read is logged with timestamp, user_id, scope set, and rule_id. Postgres triggers reject UPDATE/DELETE on the audit table.
Open-weight models
For PHI workloads, use a self-hosted Ollama with an open-weight model. No third-party API call. ONTO ships pointed at Ollama Cloud by default; flip the env var for fully local.
Multi-tenant clinics
Per-clinic scoping means one ONTO deployment can serve many clinics with hard isolation. UPO assertions are partitioned by tenant_id.
Cost observability
The cost meter tracks per-patient inference cost — useful for cost-per-encounter analytics and detecting runaway loops.
Build the AI workflow your compliance team can sign off on.
Read the runnable healthcare-triage example or the HIPAA-readiness checklist article.