
Agents for Humans: Why One Node in My Strands Graph Makes No Model Call
Quorum is a Strands Graph that watches Baltimore City Council records for bills that come back under a new number. Four nodes are agents on Amazon Bedrock, and one deliberately runs plain code with no model call. Here is why, and what testing it proved.
In July 2023, Baltimore's city council took up a bill to rezone a small block on East Cold Spring Lane. The bill died at the end of the council term without a vote. In February 2026 the same council member filed it again, under a new file number, with a differently written title and one lot fewer. The public hearing is on 24 September 2026.
Nothing told the people on that block that this was the same request coming back. Baltimore publishes everything, so the information was never hidden. It just never arrived in one piece.
That is the problem I built Quorum for during the Agents for Humans hackathon. Quorum watches Baltimore City Council's legislative record, matches each item to a parcel, decides whether a new bill continues an issue it has already seen, explains what changed, and drafts a public comment with the correct file number and hearing date. Then it stops. It never sends anything on a person's behalf.
This post is about one design choice that shaped the whole project: one of the five nodes in our Strands Graph makes no model call at all.
Why a Graph and not a Swarm
Every council record passes through the same five stations in the same order:
- Civic Analyst (agent) reads the record into structured facts.
- Resolution (code) turns an address into a parcel id.
- Continuity (agent) decides whether this is the same issue as an earlier record.
- Relevance (agent) checks whether it touches an address someone watches.
- Action (agent) writes the notice and drafts the comment.
No station ever needs to hand control back to one behind it, so this is exactly what the Strands GraphBuilder is for. A Swarm is built for agents deciding among themselves who works next. Quorum has no such decision to make, and adding that freedom would make a civic tool harder to audit.
b = GraphBuilder()
b.add_edge("civic_analyst", "resolution")
b.add_edge("resolution", "continuity")
b.add_edge("continuity", "relevance")
b.add_edge("relevance", "action")
b.add_edge("civic_analyst", "resolution")
b.add_edge("resolution", "continuity")
b.add_edge("continuity", "relevance")
b.add_edge("relevance", "action")
The node with no model
Resolution is a custom MultiAgentBase node. It lives in the same graph and shows up on the same run screen as the agents, but it runs plain code against Baltimore's own parcel layer of 237,092 parcels.
I built it that way on purpose. Turning "205 to 209 E Cold Spring Lane" into a block and lot is a solved problem. A language model asked to do it will occasionally return an answer that is plausible and wrong, and a made up parcel id is the one error in this system a resident could never catch. They would just see an address that looks right. So the model budget goes only where judgment is actually needed.
Evidence in, reasons out
The same idea shapes the Continuity Agent. The naive version asks a model "are these two bills the same?" and takes the answer on faith. That answer cannot be questioned, and neither can a similarity score.
Here is why a similarity score is not enough. The titles of the Cold Spring Lane bills, 23-0411 and 26-0148, have a title similarity of 0.943. Two bills for 701 and 702 Mura Street, which are completely different properties, score 0.944. Higher, for the wrong answer.
So Quorum computes a feature table in code: parcel match, sponsor overlap, zoning transition, prior status, committee progression, time gap and title similarity. The Continuity Agent receives that table as evidence and must return a decision plus what it relied on and what it set aside. For Cold Spring Lane it relies on the exact parcel, the same sponsor and the bill that failed, and it explicitly sets aside the title similarity because rezoning titles are boilerplate. A resident, or a judge, can check that line by line.
Is the prompt just a rule in disguise?
I had to test this, because a tuned two clause rule also scores 50 out of 50 on our hand labeled pairs. So I deleted every domain hint from the Continuity prompt and kept only the task, the output schema and an instruction not to invent facts.
The agent still scored 47 of 50, above the 84% of the best single deterministic feature. If the prompt were only restating a rule, accuracy should have collapsed to the rule's level. It did not. The three misses were a liquor license tied to its own zoning approval, a charter amendment returning after a failed term, and one street condemnation split across two file numbers. A feature table alone does not flag those as one issue.
And the parcel lookup has a blind spot a model does not: 11 of the 19 true continuations in the set name no property at all, and a parcel lookup finds none of them.
What I took away
The honest description is a hybrid. Code does the parcel matching and the feature math, exactly. Across all 1,679 records, the 8 exact parcel pairs are always the same project. A model reasons over that evidence for the cases a lookup cannot see, and it has to show its work.
Four agents and one deterministic node. Not five agents, and not zero.
The Continuity Agent is deployed on Amazon Bedrock AgentCore Runtime, and anyone can run it live from the site.
Live demo: https://quorum-peach.vercel.app
Code: https://github.com/Rickygole/Quorum
Demo video: https://youtu.be/d4mJJAkWwK8
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article