I'm an Oracle Apps DBA. My whole job is built on one instinct: nothing touches a production system without me knowing exactly what it's about to do.
So when I started building AI agents to run my daily work, I refused to do the usual thing — hand a model a shell and hope. Instead I spent the time building a small operating system around the agents. Here's what came out of it.
(2-min demo: launching a live DB diagnostic, watching the agent think in real time, and the moment an agent tries to write a file and gets frozen by the approval gate.)
What it actually does
Six agents ("skills"), each a folder with a manifest and a prompt:
- ebs-dba — read-only Oracle/EBS diagnostics: AWR summaries, top SQL, blocking sessions
- patch-triage — parses Oracle CPU advisories, filters to my stack (19c + EBS R12.2.11), buckets by urgency, CISA KEV first
- daily-brief — wakes at 7:00, checks DB health + git status across my projects, sends me a digest. Runs on Haiku. Costs about one cent.
- research — fan-out web search with citations and cross-checked claims
- project-runner — build/test/deploy tasks (deploys always need my approval)
- content-pipeline — drafts content; structurally incapable of publishing anything
Adding a skill = dropping in a folder:
# skills/ebs-dba/manifest.yaml
name: ebs-dba
description: Read-only Oracle/EBS diagnostics - reports findings only
triggers: [awr, top sql, blocking, tablespace]
model: claude-opus-4-8
tools: [oracle-dba.*] # glob allowlist against MCP tools
risk: read-only # read-only | write | spend | prod-touch
requires_approval: false
schedule: null # or a cron expression
The part I actually care about: the permission model
The AI was the easy part. The trust model is the product.
Every tool registers with a tier: read, write, spend, or prod-touch. The kernel enforces gates from the tier — never from anything the model says:
-
readruns automatically (all Oracle tools register as read; there is no write path to the database at all) - everything else halts with a dry-run preview and waits for an explicit yes
- unattended runs (cron) can't prompt anyone — so gated calls park in a queue and notify me
- an approval matches the exact arguments, hashed, single-use. Approving
npm run buildcan never be replayed asrm -rf - a gate that can't read stdin fails closed
The tier of a shell command is decided per-call:
# "git status", "pytest", "npm run build" -> read, runs free
# "vercel --prod", "terraform apply" -> spend, hard gate
# anything else -> write, gated
# sqlite3 is allowed only if the SQL is SELECT-only:
if cmd.startswith("sqlite3 ") and "select" in cmd.lower() \
and not SQLITE_WRITE_RE.search(cmd):
return Tier.READ
Fun fact: my first live test caught a real hole here. The model ran sqlite3 -header -column ... — flags I hadn't anticipated — and a lazy prefix rule I'd written would have let a DELETE through unprompted. The test suite now has a regression case for it. Live runs find what unit tests don't.
Everything is audited, to the cent
Every run writes to SQLite and a per-run JSONL file: every model turn, every tool call with arguments and duration, every approval decision, and the token cost accumulating turn by turn.
$ agentos runs
20260705-0027 daily-brief done 6264/723 tokens $0.0099
20260705-0022 research done 115606/3411 $0.6633
20260705-0020 patch-triage done 25647/3659 $0.2197
That research run cost 66 cents — and I know it to four decimal places, because an agent platform without cost accounting is a platform you'll turn off the first time a bill surprises you.
The dashboard
A FastAPI app on localhost (single HTML file, zero CDNs, nothing leaves the machine) that tails the audit log over SSE. Launch a run from any terminal and you watch it think live in the browser: MCP server connects, the actual SQL it ran, the cost ticking up, and — when it hits a gate — a red approval card with the dry-run JSON and approve/deny buttons.
Stack
-
Python 3.12+, dependencies pinned with
uv— anthropic, mcp, typer, apscheduler, fastapi, pyyaml, rich - Claude Opus 4.8 for reasoning-heavy skills, Haiku 4.5 for cheap/frequent ones (the router and the morning brief)
-
MCP (Model Context Protocol) for tools — my existing
mcp-oracle-dbaserver plugs in with one YAML entry - SQLite for memory, run history, and the approvals queue
- APScheduler + launchd for unattended scheduled runs
- 30 tests, including an end-to-end kernel loop against a real MCP server over stdio
What's next
The current version answers when asked and runs on schedule. The next one notices things on its own: a sentinel loop polling a live database every few seconds — blocking sessions, tablespace pressure, concurrent-request backlogs — that triggers an investigation agent automatically and delivers a root-cause report before I'd have opened a terminal. Real database, real locks, zero prompts typed.
That's the next post. If you've built approval gates or agent audit trails differently, I'd genuinely like to hear how — this pattern feels like something we should be converging on as an industry.
Questions about the permission model or the MCP wiring? Ask below — I'll answer everything.
Top comments (0)