Backed by Y Combinator

ClaudeCodexCursorCopilotClaude writes your code.Canary tests it.

Canary is the independent tester for code your agents write. It runs your app, tries to break every change, and reports what would have reached production.

One line for your agent.
Claude Codepocketbase
Database-aware health endpoint
Add a database-aware health endpoint: GET /api/health should ping the data and auxiliary databases and answer 503 when either cannot run SELECT 1.
apis/health.goUpdated
Done. GET /api/health runs SELECT 1 against the data and the auxiliary database before answering. If either probe fails, the endpoint logs the error and returns HTTP 503 with code 503 and message "API is unhealthy." Each probe is bounded by a 3 second timeout derived from the request context. The successful response, including the superuser-only fields, is unchanged.
∞ Agent Claude Code
@@ -1,9 +1,12 @@
package apis
import (
+ "context"
"net/http"
"slices"
+ "time"
+ "github.com/pocketbase/dbx"
"github.com/pocketbase/pocketbase/core"
"github.com/pocketbase/pocketbase/tools/router"
)
@@ -14,7 +17,12 @@ func bindHealthApi(app core.App, rg *router.RouterGroup[*core.RequestEvent]) {
subGroup.GET("", healthCheck)
}
-// healthCheck returns a 200 OK response if the server is healthy.
+// healthCheckDBTimeout is the max time the health check waits for each database ping.
+const healthCheckDBTimeout = 3 * time.Second
+
+// healthCheck returns a 200 OK response if the server is healthy
+// (aka. the HTTP server is up and the data and aux databases answer a trivial query),
+// otherwise a 503 Service Unavailable response.
func healthCheck(e *core.RequestEvent) error {
resp := struct {
Message string `json:"message"`
@@ -25,6 +33,16 @@ func healthCheck(e *core.RequestEvent) error {
Message: "API is healthy.",
}
+ if err := pingHealthDBs(e); err != nil {
+ e.App.Logger().Error("Health check database ping failed", "error", err)
+
+ resp.Code = http.StatusServiceUnavailable
+ resp.Message = "API is unhealthy."
+ resp.Data = map[string]any{}
+
+ return e.JSON(http.StatusServiceUnavailable, resp)
+ }
+
// @todo evaluate whether it is worth removing the extra info from the health endpoint
if e.HasSuperuserAuth() {
resp.Data = make(map[string]any, 3)
@@ -52,3 +70,30 @@ func healthCheck(e *core.RequestEvent) error {
return e.JSON(http.StatusOK, resp)
}
+
+// pingHealthDBs runs a trivial query against the data and aux databases
+// and returns the first error it encounters.
+//
+// Each database gets its own healthCheckDBTimeout budget (derived from
+// the request context so that a client cancellation still stops the probe).
+func pingHealthDBs(e *core.RequestEvent) error {
+ if err := pingHealthDB(e.Request.Context(), e.App.DB()); err != nil {
+ return err
+ }
+
+ if err := pingHealthDB(e.Request.Context(), e.App.AuxDB()); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// pingHealthDB runs SELECT 1 against the provided db within healthCheckDBTimeout.
+func pingHealthDB(parent context.Context, db dbx.Builder) error {
+ ctx, cancel := context.WithTimeout(parent, healthCheckDBTimeout)
+ defer cancel()
+
+ var result int
+
+ return db.NewQuery("SELECT 1").WithContext(ctx).Row(&result)
+}
0K+
bugs found before merge
0K+
engineer hours saved
0%+
fix rate
0%
rated P0 / P1
01 / Install

Get started in under 2 minutes.

Works with Claude Code, Cursor, Codex and any of your agents
01
Paste the prompt
02
Connect your stack
03
Catch failures
Paste this into your coding agent
Install the Canary CLI with `npm i -g @runcanary/cli`, then run `canary skills` and follow its instructions to onboard this repository.
02 / The problem

The blast radius is the unknown unknown.

  1. 01

    Your agents raise more PRs than your team can review. Review turned into a skim.

  2. 02

    The tests pass. The same agent wrote them, and nobody on your team reads them. Nor should they.

  3. 03

    The bug shows up as a Slack message from a customer, or a page that wakes your on-call at 2am.

  4. Teams on Canary have seen bug reports on new code go down, and on-call pages with them.
03 / How it works

Release the flock.

One loop. From your coding agent, and on every pull request.

Reviewers read the diff. Canary runs the app, tries to break the diff, and reports the blind spots you missed.

01

Canary reads the diff and your codebase and maps every flow the change can reach.

▸ diff: apis/health.go · +46 −1
▸ reach: GET /api/health · backups page · superuser page · proxy header
▸ 5 tests queued
$
04 / Where it runs

Runs where you write code.

Two triggers. One loop. Every run ends in a report.

01

Before your agent calls a task done. Canary snapshots the uncommitted tree, boots it in a clean sandbox and tests it. No commit, no PR.

$ canary verify
▸ snapshot: working tree · 4 files · nothing committed
▸ sandbox: clean boot · pocketbase
▸ 5 tests queued … running
$
05 / Integrations

Works where you work.

Canary reads the context you already have, and files every break back to your coding agent.

GitHub
Linear
Sentry
Datadog
Notion
Slack
CANARYtests
Claude Code
PR · CLI · MCP
06 / Examples

Every failure arrives with proof.

Four failures Canary caught on real customer pull requests.

test replay · api/documentsREPLAY
test · api/documents
auth as Org A · request a review image by storageId
swap storageId → a document owned by Org B
server resolves it · Org B's private file returned to Org A
· one customer can open another customer's file
$
Case file · api/documentsP0
staging · found autonomously in 6m 09s
Test
swap storageId to another org's document
Break
another org's private file opens for the caller
Root cause
image-URL resolver looks up by storageId with no org-ownership check
+
Suggested fix
resolveImage(storageId)
+ resolveImage(storageId, { orgId: caller.orgId })
Regression armed
cross-org.storageId reruns on every PR
07 / Research

Field notes from the frontier.

We publish what we learn measuring AI against real, messy codebases.

Benchmark15 min read · March 2026

QA-Bench v0: measuring how AI models handle code verification

Given a real pull request on a production codebase, can a model find every affected user flow and catch what breaks? We put a purpose-built agent against the frontier models across 35 PRs on four production-scale repos.

Read the benchmark →
Overall accuracy · QA-Bench v0
Canary
83.1
GPT-5.4
80.2
Claude Code
78
Sonnet 4.6
73.2
08 / Your move

Find it before your users do.

Put the flock on your next pull request. It runs on every one after.

One line for your agent.