Inspiration

It's 2 a.m. One operator is on call, half awake, and an autonomous agent is proposing cloud operations. The industry is racing to give agents more power; almost nobody is building the moment where the agent has to stop — where a destructive request freezes, a human looks at it, and only then does anything move. We built that moment, and made it the whole product: the gate is the feature. The look follows the story — the operator console is a 1980s night city, because that's what a night shift feels like, and the thesis is printed right on it: nothing moves in this city without a human yes.

What it does

Nighthawk is an approval-gated cloud operations and audit agent:

  • An operator (or any MCP client) submits plain-language operations requests — "audit last night's deployment," "check DynamoDB," "delete the production database."
  • Requests containing a gated action (delete, destroy, provision_high_spend) never execute on submit. They become PENDING proposals: no probes run, no model call fires. A named human clicks Approve (the run executes and is audited) or Deny (nothing executes; the denial itself is audited).
  • A run probes Nebius, DynamoDB, and Lambda in sequence with real, read-only calls, routes the request through NVIDIA Nemotron on Nebius Token Factory, and writes exactly one record for the whole run to a SHA-256 audit ledger — every record carries its own SHA-256 digest, optionally persisted to DynamoDB.
  • The model call is inference only. By design, no code path mutates cloud resources, even after approval — approval authorizes the audited run, not silent destruction.
  • Every result carries an honest badge — live, stub, or persisted. When a credential or service is absent, the output says so (live: false, fallback_reason: "not_configured", persisted: false) instead of simulating success.
  • It speaks MCP (official Model Context Protocol SDK, Streamable HTTP), exposing system_probe, nebius_route, and audit_ledger tools, so other agents and clients can drive it — and hit the same gate.

How we built it

Nighthawk is a retarget of the author's own BedrockOps stack: the same approval gate, orchestrator, and audit ledger architecture, with the model route moved from Amazon Bedrock to Nebius Token Factory serving NVIDIA Nemotron (nvidia/nemotron-3-super-120b-a12b, configurable via NIGHTHAWK_MODEL_ID).

  • Inference route (nebius_agent.py): one POST /v1/chat/completions to https://api.tokenfactory.nebius.com/v1/ via httpx, Authorization: Bearer <NEBIUS_API_KEY>, OpenAI-style messages. The route is live only when the key is set — with no key, zero HTTP is attempted and the result is deterministically labeled a stub. HTTP and transport failures return live: false with the failure named, never dressed up as success.
  • Gate & orchestrator (orchestrator.py): gated requests stop before any probe or model call and wait as PENDING proposals. Approve executes the run and audits it; Deny audits only.
  • Audit ledger (ledger.py): each record is digested with SHA-256; persistence to DynamoDB is optional (Terraform provisions one table with least-privilege IAM — PutItem + Query only) and is labeled persisted: false whenever it is not actually persisted.
  • Operator console (server.py): FastAPI + a single-page console staged as a composed night-city scene — layered skyline silhouette, synthwave sun, scrolling perspective grid floor, scanlines, chrome type — pure CSS/SVG, no external assets. The gate is staged as the set-piece, driven by real proposal state: PENDING freezes all scene motion and throws a pulsing red GATE HOLD banner; Approve surges the scene cyan — the city moves again; Deny dims it to a closed gate.
  • Tests: 34/34 green, run with no API key and no network — MCP protocol end-to-end, gate behavior (submit executes nothing), orchestration, DynamoDB persistence with fake clients, console flows, and the Nebius route's exact request shape pinned against httpx.MockTransport, including the honesty matrix (no key → no HTTP attempt; 429 → failure named; gated prompt → the gate fires before any HTTP).

Challenges

  • Honesty as an engineering constraint. It is easy to make a demo look live. We made the opposite the contract: every code path that doesn't reach a real service must say so in its output. That rule shaped the route, the probes (which raise rather than fake health), and the ledger's persistence badge.
  • The gate had to be structural, not a UI trick. A confirm dialog can be bypassed; a gate that fires before probes and before the model call — and that MCP clients hit identically to the console — cannot.
  • Retargeting without breaking the proof. Moving inference from Bedrock to Token Factory meant replacing the boto3 test surface with transport-level tests that pin the exact request shape, so the BedrockOps suite's coverage survived the swap.

What we learned

  • An approval gate changes how you design everything downstream: proposals need identity, state, and an audit trail of decisions, not just actions — including denials.
  • "Runs on the platform" should mean a real runtime call, honestly labeled when it hasn't happened. Stub modes are fine; fake success is not. Judges and users can tell the difference, and the codebase should too.
  • Presentation is not decoration when the product is a moment of trust: staging the gate as the console's dramatic set-piece made the safety model legible at a glance.

What's next

  • Model-ID re-verification against the live catalog on each new Token Factory release (the October 24, 2026 verification is in Live proof below).
  • Richer gated-action policy (per-action approvers, time-boxed approvals), ledger persistence on by default, and more read-only probes across the Nebius surface.
  • The same gate pattern applied to other agent stacks: any agent that can propose a destructive action should have to stop at a human first.

Live proof — endpoint verified October 24, 2026

Verified against the live Token Factory account before submission.

  • [x] Catalog check (Oct 24, 2026, ~8:25 PM CT): GET /v1/models returned HTTP 200 with 30 models; the lead model ID nvidia/nemotron-3-super-120b-a12b confirmed present verbatim in the live catalog (alongside Nemotron 3 Nano, Ultra, and 3.5 Super VL).
  • [x] Live run through the shipped code path: nebius_agent.invoke() returned live: true with model nvidia/nemotron-3-super-120b-a12b and a full Nemotron completion (180 tokens: 36 prompt / 144 completion, stop reason stop). Not a mock — the same function the console and MCP tool call.
  • [x] Screenshot: console result badge showing live for a routed request (routine request, approved run) — captured during the demo recording (Oct 25, 2026): Nebius panel HEALTHY with the teal live badge and models_returned: 30 in frame (shots/live-console-badge.png).
  • [x] Screenshot or output: GATE HOLD → Approve → executed run, with the resulting audit-ledger entry and its SHA-256 hash — captured during the demo recording (Oct 25, 2026): proposal 2c2ae644da60 ("delete the production database") PENDING under the GATE HOLD banner, then EXECUTED, with the orchestration_run ledger entry SHA-256 33fb0f185212… (shots/live-gate-hold.png; both states are also in the demo video itself).
  • [x] Test suite: 34/34 green in stub mode; the honesty contract is pinned by tests (no key → zero HTTP attempts, never a faked live).
  • [x] Rate limits: no 429s observed on the verification calls; the client surfaces 429s as a named failure, never as a success.

Built with

  • Nebius Token Factory (OpenAI-compatible inference API)
  • NVIDIA Nemotron — nvidia/nemotron-3-super-120b-a12b
  • Python 3.12
  • Model Context Protocol (official MCP Python SDK, Streamable HTTP)
  • FastAPI · Uvicorn · Pydantic
  • httpx
  • boto3 · Amazon DynamoDB (audit persistence, optional)
  • Terraform (audit table + least-privilege IAM)
  • HTML/CSS/SVG + vanilla JavaScript (console; zero external assets)

Origin

Nighthawk is a retarget of the author's BedrockOps codebase (https://github.com/RwTraylor/BedrockOps) — same gate, orchestrator, and ledger; new inference route (Nebius Token Factory + NVIDIA Nemotron), new console, new name. MIT license retained.

Built With

Share this project:

Updates

Submission history