Greenlight is a portfolio project that puts an AI agent inside a financial
approval workflow without letting it near the commit button. An agent drafts an
auto-repair triage and estimate; a service advisor reviews it and
greenlights it; only then does the system write the financial record —
with a full audit trail. The agent proposes, a human
approves, the backend commits. No financial
write ever happens without that approval gate.
One thesis, applied twice: put deterministic guardrails around a
non-deterministic model. The product does it at runtime — a
human-approval gate and an append-only audit trail around an LLM that writes
estimates. The build process does it at build time — hooks and CI around an LLM
that writes code. Same idea at two altitudes.
// the problem
I spent a decade building line-of-business software — budgeting, approvals, work
orders, financial workflows — where the hard part is never the happy path; it's
the gate that decides what gets committed and who signed off. LLMs are genuinely
useful inside those workflows, but they cannot be trusted to write to the system
of record on their own. Greenlight is where I put that conviction on the table:
the model is allowed to draft, never to commit.
// the workflow
A focused vertical slice of an auto-repair shop — three entities (Customers,
Vehicles, Repair Orders) and one star workflow, built clean-room on synthetic
data:
intake request
→ LangGraph agent drafts triage + estimate (tools via MCP: parts pricing, vehicle history)
→ agent returns a proposal — it writes nothing to the system of record
→ service advisor reviews in Vue and approves / edits / rejects
→ on approval, the C# backend commits the order + writes an append-only audit record
// architecture
Four services on one request path. The C#/.NET backend is the system of record
and the security boundary; the Python agent only ever proposes; the Vue frontend
is the human in the loop; Terraform provisions it on Azure.
[ Vue frontend ] --HTTP--> [ C# / .NET backend ] --HTTP--> [ Python agent (LangGraph) ]
approve / edit / reject system of record, API, drafts triage + estimate,
auth, validation, THE calls MCP tools, returns
APPROVAL GATE, audit log a proposal (writes nothing)
|
[ MCP server ]
parts pricing, vehicle history
[ Terraform ] provisions the stack on Azure — Container Apps · Azure PostgreSQL
// the approval gate & audit trail
The agent proposes; a human approves; the backend commits.
This is the whole point, so it is enforced where it counts. The agent returns a
proposal and writes nothing to the system of record. The
approval gate lives server-side in the C# backend — not just in
the UI — and the estimate endpoint can never move an order to approved or commit
a cost on its own. A separate, human-driven approval action is the only thing
that commits the estimate, flips the order to approved, and appends an
immutable audit record. A test pins the invariant directly: given a
fully-formed agent proposal, the estimate path still produces no approval and no
committed cost — the agent cannot commit unilaterally.
// observability
A four-service system is only debuggable if you can follow a single request
across every hop. Greenlight is wired end-to-end with
OpenTelemetry: one trace id follows a request
from the browser click, through nginx and the ASP.NET Core backend (including
the Postgres span), across the backend→agent boundary via a W3C
traceparent header, down to the Claude LLM span and the MCP tool
spans — one trace from the browser click to the Claude call, viewable in Jaeger.
A greenlight.repair_order_id span attribute bridges the draft trace
and the later approval trace across the human-in-the-loop gap. The
cross-boundary propagation is pinned by tests at each seam. (Tracing runs against
the local docker compose stack today; shipping it to a cloud backend
is a later increment.)
browser click (Vue) → nginx → .NET backend → Postgres
└→ Python agent → Claude (llm.draft) + MCP tool spans
one trace id · one W3C traceparent · end to end · viewable in Jaeger
// how it was built
I treat AI-assisted development as an engineering discipline, not a productivity
hack. Work is spec-first: requirements, a technical plan, and a
task breakdown are committed as version-controlled artifacts (specs/)
before implementation, so the agent is steered by structure rather than
improvisation.
The standards I care about aren't left to memory — they're layered so each is
harder to bypass than the last: intent (the instructions the
agent reads every session), reflexes (Claude Code hooks that run
a test-and-coverage gate during the agent loop), and law
(pre-commit and CI gates the build can't pass without). Coverage bars aren't
uniform; rigor is concentrated where bugs are expensive — the backend that
enforces the approval rule carries the strictest bar (≥85%), the agent is
standard (≥80%), the frontend is lighter (≥70%). That is the same
guardrails-around-a-probabilistic-actor pattern as the product, applied one level
up to the LLM that writes the code.
No hosted demo — Greenlight runs locally with docker compose up
(Postgres, backend, agent, frontend, plus a Jaeger + OpenTelemetry collector).
Built clean-room on synthetic data.