
Paragraph-to-graph: declaring agent workflows without writing routing code
Been working on a different way to specify agent workflows that I want to throw at this community since most of you have written the manual-routing version more than anyone.
In LangGraph today you write a StateGraph, define nodes as functions, define edges as conditional functions, wire tools_condition or your own router. It's powerful but it's code for what is often, conceptually, a paragraph: "read the config, test the connection, report findings & don't modify anything."
I built a tool called BetterClaw that compiles that paragraph into a workflow graph, then enforces it at the tool-call boundary. Example:
Paragraph:
▎ Diagnose a credential mismatch in our Railway staging environment. Read the service config, test the database connection, and report your findings to me. Do NOT modify, delete, or
▎ write to anything in this workflow.
Compiles to a 3-node graph: read_config => test_connection => report. At runtime, if the agent tries to call railway_delete_volume, the hook returns a deviation error before dispatch. The agent never actually invokes the tool. The graph is the only surface that decides what's reachable.
I wrote about the mechanism here: https://github.com/jfan22/BetterClaw — there's a 90-second demo of it blocking the exact "Claude deleted prod in 9 seconds" scenario from April.
The honest limits, since this audience will spot them anyway:
- Runtime is Claude Code today, not LangChain. This is the obvious gap if you want to use it now. I'd love feedback on whether a LangGraph adapter would actually be useful before I build it: what would the integration need to look like to feel native? ToolNode wrapper? Conditional-edge generator?
- Enforcement is on tool identity, not arguments. delete("staging") and delete("prod") look the same to the hook. Adding argument-shape constraints is on the list but isn't trivial.
- No goal-completion verifier. The agent can walk the graph correctly and still produce wrong output. The graph constrains what tools fire, not what the agent concludes.
So: is paragraph-as-spec a thing you'd actually want for the simpler agents you build, or is the manual control of LangGraph's routing actually the feature you'd never give up?
Curious where the line is for you.