incident-response-agent started as a hand-rolled ReAct agent. Typed state machine, separate budgets for iterations and tool calls, cycle detection, sanitized traces. That was v0. It taught me the problem space. It was also the last agent harness I’m going to build myself.
For this project, the harness had become commodity infrastructure rather than the differentiating work. This is what happened after I stopped.
Where v0 led
The v0 loop wrapped observe → decide → act → reflect with separate execution budgets and a cycle detector. It had a trace recorder from the start: trace_id, transition events, sanitized events with no raw prompts or secrets. It worked, and it ate real sessions: malformed tool calls, budget exhaustion, repeated actions, knowing when to stop. All solved problems, all still a slog to build.
I wanted an incident-response agent: a model that investigates a sick service, proposes a bounded fix, and acts only with explicit human approval. So instead of extending my own loop, I reached for the LangChain stack: Deep Agents for the investigation, LangGraph for the approval interrupt, LangSmith for the evals. OTel was already in v0, so that stayed.
The stack, with the marketing removed
Deep Agents is the investigation core. One create_deep_agent call gave me the model/tool loop, structured output, optional delegation, checkpoint integration, and a virtual filesystem that I explicitly denied access to. It replaced the loop I’d hand-built with better discipline: typed tool schemas, read-only diagnostics, a structured diagnosis as output.
The provider-specific gotcha was Qwen thinking mode rejecting the structured tool choice Deep Agents needed. Disabling thinking mode fixed it without a custom adapter — exactly the kind of compatibility detail that only appears once the real model enters the loop.
LangGraph became the approval boundary for the resumable workflow. interrupt() pauses the graph mid-run; the application presents an immutable, hash-bound proposal, and only an explicit human resume proceeds. The same proposal and approval contract remains authoritative outside Studio.
LangSmith is where the agent stops being a demo. A versioned dataset with hidden reference diagnoses, deterministic evaluators for diagnosis, action, evidence precision, distractor rejection, tool coverage, and tool budget. Then a reflection mode: one structured critique, one bounded revision. The evaluators gave me the first honest before/after numbers I had.
I kept OTel for application lifecycle spans and bounded operational metrics; LangSmith captured model, tool, and evaluation trajectories. They answer different questions.
The surprise, and it’s not the one you’d guess
The capability registry was the last phase. The agent can propose a new action as a structured contract: fifteen schema-validated fields, extra="forbid", parameters with bounds, an allowlisted target class, blast radius, verification and rollback steps. Review, a hidden-case gate, promotion, then execution bound to the exact record: id, version, digest, parameters, target. The executor revalidates before any side effect.
I expected the interesting part to be the agent’s proposal. It wasn’t. The agent was the least interesting part of its own capability lifecycle.
What actually surprised me is how much deterministic code it took to make the model’s behavior match its appearance. Three concrete things:
Across the original run and three fresh repetitions, the researcher proposed the same kind of unobservable prerequisite every time. An application-owned salvage step removes unobserved prerequisites from the model’s own proposal before the simulated reviewer and hidden-case gate see it; when salvage is impossible, the POC falls back to a clearly labeled reference contract. The model is not learning to stop doing this; the code is catching it.
The first time I ran the before/after eval, the agent opened the promoted record and then cited the same generic health observation anyway. Retrieval changed the citation, but not the evidence selection. Distractor avoidance moved from 0.00 to 1.00 after the opened record explicitly told the model which evidence categories were causal. I then enforced the same scope in application code, so a noncompliant answer fails rather than merely scoring poorly.
The first version of “binding” didn’t bind. Promotion and execution were sequential but not connected; the executed action was still hardcoded. It took a second pass for the proposal to carry the capability id, version, and digest, and for the executor to revalidate the record at execution.
None of that is a failure. It’s the finding. A capable-looking agent is cheap. The expensive part is the code that checks whether the capability is real, at the moment it’s about to be used.
What I didn’t build
Streaming. A tool loop. State management. An eval framework. Deep Agents, LangGraph, and LangSmith ship those, and building them myself would have been sessions spent on plumbing that doesn’t differentiate anything.
What I did build: the governance layer, the evals, the evidence discipline, and the honest limits section. That’s the part that matters now. Not “can the model call a tool” but “what is it allowed to do, who approved that, and can we verify what happened.”
Where it goes next
The ADRs are honest about what’s deferred: a containerized worker variant of the capability, SREGym integration, fleet-level control, registry integrity beyond SQLite. The direction I’d push is binding the same governed lifecycle across more than one owned target, with the same hash-bound approval.
I’m still at the small version: one synthetic worker, one promoted capability, one bounded activation. The next step is more owned targets and a containerized worker — not more autonomy for its own sake.
The question I’m carrying forward is no longer “can the agent discover a new action?” It’s “where does the binding between evidence, reviewed knowledge, approval, and execution break?”
If you’ve built further in this direction, that’s the part I’d like to compare notes on.
Links
- incident-response-agent — the repo this post is about: Deep Agents investigation, LangGraph approval, LangSmith evals, capability registry.
- Evidence and verification record — dated runs, exact commands, honest limits.
- ADR 009: capability registry and one-target activation — the decision record for the binding phase.
- Deep Agents — the LangChain harness at the core of the investigation path.
- LangGraph — the graph runtime behind the approval interrupt.
- LangSmith — the platform behind the datasets, deterministic evaluators, and before/after experiments.