Inspiration

In the past few years, software development has shifted fast: coding agents now generate almost all of our code. The catch is that we can't keep up with how quickly that code gets produced. The agent writes code, we skim it, say "LGTM," and move on. The inevitable result is that we, as developers, lose our mental model of the codebase. And in a code-centric business, losing the map of your codebase means losing your intuition for how your business actually operates. Worse, you may not even know what you don't know, because the agent made the decision for you.

On top of that, we're now handing agents the workflows we were doing by hand just six months ago: deployments, checking production error logs, flipping feature flags. It's like putting an agent in the driver's seat, except the destination isn't a simple address. It's something fuzzier, like "keep customers happy."

It's easy to see how a business run this way becomes a black box to the people who are supposed to manage it. And the thing about a black box is that you never know what comes out of it... until it does. It could be a customer who never gets their refund, a "fixed" issue that's still happening in production, or something as simple as a push to production on a Friday evening.

What it does

We've actually solved this problem before, in code. Developers use assert in places where a failure means their assumptions about the code were wrong.

Needl takes the same idea and zooms out to the level of the business. You assert things that should always be true, and you get notified the moment one isn't, before it turns into churn, unhappy customers, or a hit to the bottom line.

For example, say you track errors in Sentry and ship code through GitLab. You could assert that once a GitLab MR referencing a Sentry issue is merged, that issue shouldn't show up again. If it does, you find out before you tell a customer the fix is live when it actually fixed nothing. That protects more than your reputation and revenue. It protects your relationship with the customer, who comes to see you as the team that knows what it's doing: reliable and trustworthy.

Once a rule is on, nobody has to sit and watch it. Needl listens to the tools' own webhooks, checks each event against every rule as it arrives, and when a rule breaks it saves the evidence and hands the problem straight to a GitLab Duo agent. Nobody has to triage an alert, copy a stack trace into a chat or write a prompt. What the team comes back to is a draft merge request with the evidence behind it.

Here is that loop on the Sentry example. A branch for issue ENG-42 is merged and deployed to production. Needl sees GitLab's deployment event, and from then on it holds Sentry to the rule for that issue. Two days later, Sentry reports an error tagged ENG-42 in production. That one event breaks the rule. Needl stores the break together with the events that led to it, and in the same request starts the GitLab Duo flow the team chose, with that record in the flow's instructions. The flow reads the record and the code, then opens a draft merge request with a fix and explains what it changed and why. The merge request appears on the rule's card. Needl doesn't mark the problem solved because an agent finished; the rule keeps watching.

A person steps in at the point where judgement matters: reviewing the fix. By default the agent is told not to merge or deploy, so its merge request goes through the team's normal review. Teams can rewrite those instructions, or turn automatic starts off and start the agent from a break with one click.

Needl's hands-off loop: set a rule, Needl watches, the rule breaks, a Duo flow starts, a draft merge request opens, the team reviews, and the rule keeps watching

Figure 1. The whole loop. Steps 2 to 5 run without anyone, and the rule keeps watching after the fix. Diagram on GitHub

How I built it

Event pipeline

Needl listens to seven tools: GitLab, Linear, LaunchDarkly, Sentry, PostHog, Intercom and Stripe. On the Connections page, each tool gets its own webhook URL, setup steps and a field for its signing secret, which is stored encrypted. The page shows the result of the latest delivery, so a broken setup is visible straight away.

Every delivery is checked for authenticity (the tool's signature or secret token) before it's parsed, then turned into an observation that keeps the tool's own event name, such as gitlab.deployment or stripe.invoice.paid. Duplicates are dropped per workspace, event time is kept separate from receipt time, and nothing is acknowledged until it's stored. Needl doesn't guess how events relate. A deployment and a Sentry error are linked only through an explicit shared key, such as the issue key ENG-42 in a branch name and a Sentry tag.

Needl's event pipeline: seven tools send webhooks; Needl checks each is genuine, keeps the tool's event name, checks live rules, stores the event once and answers the tool

Figure 2. One webhook from arrival to a stored, checked observation, and the answer the tool gets back. Diagram on GitHub

Assertion engine

A rule has one English sentence, the inputs a person sets (an environment, a time limit) and the rule itself, written in a small language over each tool's native events. Underneath, it's linear temporal logic (LTL). A progression monitor updates each rule as events arrive, and bind tracks each issue or customer separately. When a rule breaks, the event trace and the counterexample are saved in one transaction.

These are the kinds of promise a rule can express today. Every example is one of the rules in Needl's docs, written over events Needl actually receives.

Kind of rule Example It breaks when
Something must never happen Production must never record a successful test-mode charge The forbidden event arrives
After X, Y must never happen Once a fix for an issue is deployed to production, errors tagged with that issue must never appear there again Y arrives for the same issue or customer after X
After X, Y must happen within a time limit When a pipeline on main fails, a passing pipeline on main must follow within an hour The time limit passes without Y
For a while after X, Y must not happen For 30 minutes after a flag is turned on in production, no critical metric alert may fire Y arrives inside the window
Y must not happen before Z A customer conversation must never be closed before a teammate has replied Y arrives while Z still hasn't
Something may only happen once An invoice must never be paid by a second payment It happens a second time for the same invoice

Needl only runs safety properties: rules that a single event, or an expired time limit, can break. "Eventually" with no deadline can never be caught failing, so the checker asks for a time limit. Time limits must also fail when nothing arrives, so the server sends clock ticks to monitors whose window has closed, after a short grace period for late webhooks.

People can describe a rule in plain English and let an authoring agent (an OpenAI model) write it. A typed checker sends errors back to the model with line, column and a "did you mean" suggestion, for up to three attempts. Only a rule that passes comes back, and it starts paused for review. The checker also makes sure the sentence shows the values the monitor really uses, and "Show exact reading" puts the word-for-word logic next to it.

How a rule is written and monitored: you describe it, the authoring model writes it, the typed checker sends errors back, the rule waits paused for review, then monitoring runs per issue or customer with signed events and clock ticks, and a break is saved with its evidence

Figure 3. Writing a rule happens once and nothing runs until it passes the checker. Monitoring then never stops, and clock ticks let silence break a rule too. Diagram on GitHub

Short traces are checked exhaustively against a separately written evaluator. The 16 business rules in the docs run as tests that send signed webhooks through the real adapters and monitor, and a simulator can send any catalogue event as the provider's real signed payload.

Handing a break to GitLab Duo

The response runs on the GitLab Duo Agent Platform. A workspace pastes a GitLab personal access token and a project on the Connections page. Needl checks that the token has the api scope and isn't a bot, because GitLab ignores flow triggers from bots, then lists the AI Catalog flows enabled in that project. The person picks a flow, writes its instructions and chooses whether it starts automatically. The token stays sealed on the server.

The default instruction is: "Open a draft merge request that fixes the cause of this violation. Explain what you changed and why in the merge request description. Do not merge or deploy." When a webhook breaks a rule, the same request that stores the break starts the flow through GitLab's Flows API, at most once per violation. The violation record goes into the instructions: the rule and its version, the issue or customer it concerns, and the last twenty events with links back to each tool. A break caused by a missed deadline, where nothing arrives, starts the flow on the next clock tick instead. The flow runs without stopping to ask for input, so a break at 3 a.m. doesn't wait for someone to wake up before work on it starts. On each clock tick Needl asks GitLab's GraphQL API how running flows are doing, then shows the merge requests the flow opened and its final answer on the rule. A launch that times out is recorded as unknown rather than retried, so one break can't start two agents.

Handing a break to GitLab Duo: the break is saved, Needl starts the chosen flow through the Flows API, the Duo flow runs and opens a draft merge request, Needl tracks the flow and shows the result on the rule, and you review the merge request

Figure 4. From a stored break to a draft merge request, with nobody triaging or prompting in between. Review stays with the team. Diagram on GitHub

Across the GitLab workflow

Needl's main work is in monitoring and governance: it watches live signals all the time and turns a team's expectations into checked, versioned rules that leave an evidence trail when they break. Because rules are written over GitLab's own events, they also reach into earlier stages. Pipeline events let a rule hold verification to account: "a failed pipeline on main must be followed by a passing one within an hour". Deployment events tie a release to what happens after it, like the ENG-42 rule. Issue events from GitLab and Linear connect planned work to shipped work: "once a branch for an issue is deployed, that issue must be completed within a day". And when a rule breaks, the Duo flow does the create step itself by writing the fix as a draft merge request.

Product

Needl runs at needl.dev with allowlisted sign-up. Rules sit as cards on a board. Opening one slides in a drawer with four tabs: overview, breaks with their event timelines, the investigation, and the activity the rule watches.

Running on Google Cloud

Needl is served from Google Cloud Run. One container, built from the Dockerfile in the repository, runs the web app and the whole API in us-east4, close to the Neon Postgres database. Cloud Run scales the service to zero between requests, so Needl can't count on a background timer to notice a missed deadline. Instead, every request advances the clock, and a Cloud Scheduler job calls Needl's tick route every hour, so a rule whose time limit runs out still breaks when nobody is on the site.

Challenges

Working out what matters after code generation. A lot of the time went into thinking rather than building. I wanted to understand what developers will actually need as agents take over more of the coding, and what is really missing once writing code is almost solved. Where I landed is the problem in the Inspiration: teams lose track of what's true about their own product. So the thing worth building was a way to state those truths and have them checked all the time, not another way to generate code.

Finding the right primitives. In the first version, people wrote the logic themselves. Rules were LTL formulas built from a few templates, such as "a linked issue must not recur after a deployed fix" or "an order must not be fulfilled before payment". A person filled in the template or edited the formula directly, and the language model could only pick which template fit. The templates were the wrong building blocks: they matched related events by position and couldn't be triggered by real webhook data, so I rebuilt them around bind, which captures an issue key or customer from one event and follows it. Even then, templates limited what a team could say, which led me to replace them with a small rule language over each tool's own events and add natural language on top: you describe the rule, a model writes it, and the checker sends it back until it passes. Finally, each rule gained its own sentence and typed inputs, so it reads as plain English while the logic underneath stays exact.

Choosing the services and connecting them. A rule is only as good as the events behind it, so I had to pick tools whose webhooks together describe how a software business runs: GitLab for code, pipelines and deployments, Linear for planned work, Sentry for errors, LaunchDarkly for feature flags, PostHog for product analytics, Stripe for billing and Intercom for support. Each one signs its webhooks differently, names its events its own way and uses its own identifiers. Connecting them meant one adapter per tool, and an explicit shared key, like the issue key in a branch name and a Sentry tag, wherever a rule spans two tools. I kept each tool's own event names instead of forcing everything into one generic shape, because that's what lets a rule say exactly what it means.

Accomplishments

  1. Turning a broad worry into one coherent product. The sense that agents are turning our own software into a black box is easy to feel and hard to act on. Needl makes it concrete: say what must stay true, check it against what your tools really report, and hand a break straight to an agent with the evidence.
  2. A loop that runs on real events. A push to main sent a real webhook to Needl, and the GitLab Duo agent started from it. That's the core idea working outside a test: something that happens in the team's own tools reaches Needl and gets an agent working on it.
  3. Six of the seven tools connected live. GitLab, Linear, LaunchDarkly, Sentry, PostHog and Stripe all sent real events to needl.dev, with the Duo flow set to start automatically on new violations. Intercom is the one still to connect. That breadth is what lets rules reach across code, planned work, errors, feature flags, product analytics and billing, instead of watching one tool at a time. Since then, needl.dev has moved to Google Cloud Run with the same webhook addresses and the same database.
  4. Formal logic that anyone can use. Temporal logic is usually something only specialists write. In Needl you describe a rule in plain English and get back a checked rule that still reads as one sentence, with the exact logic one click away. A rule written by an LLM never runs unchecked.

What I learned

Coding agents have made writing code cheap, but they haven't made it any easier to know whether the software still does what the business needs. If anything, they've made it harder: the more code arrives without anyone reading it closely, the less any one person can say how the product behaves. And the code alone can't answer that question, because the behaviour that matters shows up after a change ships, in a deployment, an error, a payment or a ticket that's still open.

Those signals are spread across tools. The deployment is in GitLab, the error is in Sentry, the planned work is in Linear and the money is in Stripe, and none of them on its own can tell you that a fix didn't work. The answer only appears when you follow one issue or one customer through all of them. That's why joining events through shared keys, like an issue ID in a branch name and a Sentry tag, turned out to be where most of the value is. It's also what an agent needs: with the joined story in hand, it starts from what actually happened instead of from a single alert.

Once that context is gathered, it has to reach someone who can act on it, and that's where GitLab made the idea practical. Its webhooks already report the pipelines and deployments a rule needs to watch. The Duo Agent Platform can start a flow through an API, so a break can hand its evidence to an agent with nobody in between. And because the agent answers with a merge request, its work arrives where the team already reviews changes. I didn't have to invent a new place for an agent's work to go: the path from a broken rule to a reviewed fix runs through the workflow the team already uses.

What’s next

  1. Warnings before a rule breaks. Track how close each rule is to breaking, such as a deadline that's almost up with no sign of the event it needs, and warn the team while there's still time to act. Later, predictive analysis over past events could flag the rules most likely to break next.
  2. A dedicated investigation flow. Publish a read-only Needl flow in the AI Catalog so the agent can investigate a break before proposing a fix.
  3. Talk to an issue in Slack. A Slack integration so a team can talk to a break live as it unfolds: ask what happened, see the evidence, and follow the agent's progress without leaving the conversation.
  4. Rules about what support tells customers. For example: when a support agent tells a customer an issue is fixed, the fix must already be live. Today Needl reads events like "a conversation was closed", not what a message says, so this needs a step that reads the reply and recognises that it promises a fix.
  5. Rules that tune themselves. Use false alarms to adjust inputs that a person changes by hand today.

Built With

Share this project:

Updates

Submission history