An hour on a food bank's website says one thing. The flyer taped to its door says another. Somebody who needed food that day drives across town and finds it closed. Nobody lied, nobody noticed, and the person who paid for it is the one with the least slack in their week.
beacon is an agent for the people running those organisations. It takes the pages the organisation itself publishes, reads them, and reports only the places where they contradict each other, carrying the exact sentence from both sides so a volunteer can fix the wrong one in a minute.
The hard part is not finding disagreements. It is refusing to invent them. beacon keeps four categories that never merge. A contradiction means both surfaces state the fact and no reading of one can coexist with any reading of the other. An agreement means at least one reading matches. An absence means one surface simply says nothing, which is information for the organisation and not an accusation. Unmeasured means the fetch succeeded and carried nothing, an empty HTTP 200 or a consent wall, and that surface was not read at all. Nine to five can only mean 09:00 to 17:00, so it is pinned. Eight to twelve keeps both readings and is not comparable to anything. Missing a real contradiction costs one finding. Inventing one costs the product.
It is built on Strands Agents 1.54.0, and the interesting part is where it hooks. Every intervention Strands ships asks the same question on before_tool_call: should this call be allowed? Cedar authorization and human in the loop both stop there. Nothing in the shipped set asks what happens when a call was allowed, returned success, and carried nothing in it. An empty success is worse than an error, because an error is visible and an empty success reads as there being nothing to find. beacon adds NullGate on after_tool_call, the hook the vended interventions leave unoccupied, which rewrites empty successes into an explicit unmeasured marker the model cannot mistake for a measurement. EvidenceGate sits on before_tool_call and denies any attempt to publish a finding that lacks a source and a verbatim quote from each side.
Then I ran it against nine real organisations, twenty one surfaces they publish themselves, and it found zero contradictions.
That turned out to be the most useful thing that happened. The first run carried five absences that were my own HTML stripper leaving entities undecoded, plus several hours phrasings the extractor could not read at all. Fixing those took agreements from 43 to 59 and left one real absence instead of five false ones. It also made verification decline two organisations it had previously asserted, because the registry's top hit was a different charity in a different town, and accusing the wrong food bank is exactly the failure this project exists to prevent.
The honest result is that small organisations mostly agree with themselves. beacon's job is to say so rather than manufacture something more interesting.
Bedrock is the default provider and the wiring is tested, but the account could not yet invoke a model, so the real run used Gemini through Strands. The rules require Strands, not Bedrock, and the repository says the same.
Log in or sign up for Devpost to join the conversation.