Skip to content

/architecture

How the agentactually works.

Five zones, twenty-six components, one rule: content from the outside world is data, never instruction. Every arrow below is a real call in the codebase, and every record it produces is persisted before anyone sees it.

PUBLIC SOURCESTRIGGERSAGENT · THIS SERVERGITHUB · OPTED-IN REPOSPUBLIC EVIDENCE

01

System map

Hover any component to see its inputs, outputs and the trust boundary it enforces. Dashed zones hold untrusted data; the solid zone is the only place code runs.

PUBLIC SOURCESuntrusted inputTRIGGERSwhen work startsAGENT · THIS SERVERtrusted code · no repo code runs hereGITHUB · OPTED-IN REPOSrepo content is data, never instructionPUBLIC EVIDENCEanyone can verifyNVDCVE API 2.0GitHub Advisories/advisories?cve_idCISA KEVknown exploited feedphp.net releasesreleases JSONnode-cron*/15 * * * *Backup cronPOST /api/internal/runInstall webhookinstallation_repositories.addedIngest + normalizeproviders.ts · lookupCve()Fixed-version tablephp-releases.tsSingle-flight runnerrunAgent()Orchestratoragent.ts · processRepo()Matcher / plannerpatcher.ts · planFile()Safety validatorsafety.ts · validateChange()Policy gatepolicy.ts · mayWrite()PR writergithub.ts · openPullRequest()CI + merge trackerwebhooks/github · checkSummary()Postgres (Neon)Prisma · 15 tablesEvent bus → SSE/api/v1/streamHealth probeshealth.tsApp installations/app/installationsRepo tree + blobsgit/trees · git/blobspatch-agent/* PRbranch · commit · pullRepository CIcheck runsSigned webhooksX-Hub-Signature-256/proofREAL-only ledger/status.jsoncomputed health/liveSSE streamllms.txtfor AI evaluators

02

One run, end to end

From a scheduler tick to a verified merge. Steps 01 to 09 happen inside a single run; 10 to 15 arrive later as signed webhooks.

SchedulerAgentNVD / GHSAPostgresGitHub APIRepo CIPublic01 tick · */15 or backup cron02 GET cve record03 record + raw hash04 SourceRecord if hash is new → advisory.ingested05 installations → token → repositories06 git tree + blobs (≤ 40 files)07 planFile → validateChange → mayWrite08 branch patch-agent/* · commit · PR09 Patch(pr_opened) + pr.opened10 SSE + /proof (after persist)11 run checks on PR branch12 check_suite webhook (HMAC)13 Patch.ci = passed/total14 pull_request closed · merged15 pr.merged + merge sha → /proof

03

Patch state machine

A patch's id is a fingerprint of repository, campaign and exact edits. Any fingerprint in a terminal state is skipped on later runs, which is what makes the worker idempotent.

validatedwrites onwebhookwebhookAPI errorci passed/failedplannedgeneratedpr_openedmergedclosedfailed → retryreview_requiredpolicy_blockedreview_required / policy_blocked are terminal: no PR is ever opened from them.

04

Trust boundaries

Where each kind of input is allowed to go, and what stops it going further.

Repository content

Parsed by fixed regexes and a strict schema. Never executed, never sent to a model, never rendered as HTML. A README saying “ignore previous instructions” changes nothing (tested).

Advisory text

Control characters stripped, length capped, rendered as plain text. Raw hash stored so changes are detectable.

Webhooks

HMAC-SHA256 over the raw body with constant-time comparison before JSON is parsed. Only patch-agent/* branches are acted on.

Writes to GitHub

Only after installation + policy + validator. New branch only, never the default branch. One flag disables all writes.

05

Technology

Boring, inspectable choices. No WebGL, no model in the write path.

Web
Next.js 15 · React 19 · Tailwind 4
Server-rendered pages so crawlers and AI evaluators can read everything without running JS.
Realtime
Server-Sent Events
One in-process bus; every event is persisted before it is broadcast.
Data
Postgres (Neon) · Prisma 6
15 tables. Events, patches, source records with raw hashes, authorizations.
Scheduling
node-cron · external cron
*/15 in-process plus a bearer-protected backup trigger; single-flight runs.
GitHub
GitHub App · REST v3
JWT → installation tokens. Serialised, spaced calls with rate-limit back-off.
Advisories
NVD 2.0 · GHSA · CISA KEV · php.net
Merged into one schema, provenance kept per provider.
Validation
zod · yaml (aliases off)
Strict .patchbot schema; unknown keys rejected; no command fields exist.
Treasury
Solana JSON-RPC (read-only)
Public address only. No key material anywhere in the codebase.

06

Data model

Everything the public pages show is a query over these tables. See prisma/schema.prisma.

  • AgentEventid · timestamp · eventType · dataMode · message · cveId · repositoryId · patchId · metadata · verificationUrl
  • Patchid (fingerprint) · stage · repository · cveIds · changes · branch · prUrl · commitSha · ci · detected/matched/generated/prOpened/merged
  • CVE / SourceRecordid · severity · cvss · firstSeenAt ⟶ provider · providerRecordId · sourceUrl · retrievedAt · rawHash
  • Repository / Authorizationowner/repo · installationId ⟶ source (github-app | patchbot) · active · policy · granted/revoked
  • TreasuryTransaction / ComputeExpensesignature · direction · lamports ⟶ category · amount · period · evidence

07

Every component, in text

The same information as the system map, for screen readers, crawlers and anyone who prefers a list.

NVD CVE API 2.0

Authoritative CVE records: description, CVSS, references. Untrusted text, stored and rendered as plain text only.

GitHub Advisories /advisories?cve_id

Ecosystem-level affected packages and version ranges. Untrusted; merged with provenance kept per provider.

CISA KEV known exploited feed

Flags whether a CVE is known to be exploited in the wild. Untrusted; hashed per entry.

php.net releases releases JSON

Latest release per branch. Confirms fixed versions exist. Never lowers a fixed version.

node-cron */15 * * * *

In-process scheduler started from instrumentation.ts. Single instance only.

Backup cron POST /api/internal/run

External cron with a bearer token, in case the in-process timer stalls. Constant-time token check; 503 if unset.

Install webhook installation_repositories.added

Runs immediately for newly added repositories. HMAC-verified before parsing.

Ingest + normalize providers.ts · lookupCve()

Queries every provider, merges into one schema, diffs raw hashes against stored SourceRecords. Provider failures become agent.error events; nothing is guessed.

Fixed-version table php-releases.ts

Branch → first fixed release (8.5.12, 8.4.27, 8.3.36, 8.2.35), cross-checked with php.net. Seed table labelled as SEED when php.net is unreachable.

Single-flight runner runAgent()

One run at a time. Overlapping triggers return immediately. Errors in one repo never stop the run.

Orchestrator agent.ts · processRepo()

Lists installations, mints installation tokens, walks each repo's git tree (≤ 40 files, ≤ 256 KB). Only repos inside an App installation are ever read.

Matcher / planner patcher.ts · planFile()

Finds explicit php:X.Y.Z pins in Dockerfile, compose, CI and composer config.platform.php. Floating tags are ignored. Fixed regexes only. Repository text never reaches a model.

Safety validator safety.ts · validateChange()

File allowlist, unchanged line count, ≤ 20 changed lines, secret and dangerous-content scan. Rejected changes become patch.rejected events.

Policy gate policy.ts · mayWrite()

App installed? .patchbot valid and enabled? Severity and patch type allowed? Invalid .patchbot fails closed. Schema has no command fields.

PR writer github.ts · openPullRequest()

Creates a patch-agent/* branch, one commit per file, opens a PR with the exact diff and sources. Never pushes to the default branch. Disabled unless GITHUB_WRITES_ENABLED=true.

CI + merge tracker webhooks/github · checkSummary()

Aggregates check runs for agent branches; records merges and closes. Only branches under patch-agent/* are considered.

Postgres (Neon) Prisma · 15 tables

Events, patches, source records, authorizations. Every record is written before it is broadcast. DEMO rows are rejected before reaching the database.

Event bus → SSE /api/v1/stream

In-process pub/sub fan-out to every open browser. Same events the ledger stores, nothing extra.

Health probes health.ts

Live probes of NVD, GitHub, App, RPC, plus SELECT 1 on Postgres and last worker run. Nothing is reported operational unless a probe passed.

App installations /app/installations

The opt-in list. Installation is the authorization. Least privilege: metadata r, contents rw, PRs rw, checks r.

Repo tree + blobs git/trees · git/blobs

Read-only fetch of candidate files and .patchbot. Content treated as data; prompt-injection text has no effect.

patch-agent/* PR branch · commit · pull

The only write the agent makes. Maintainers review and merge; the agent never merges.

Repository CI check runs

The repo's own tests run on the PR branch, in the repo's own CI. No repository code executes on the agent's server.

Signed webhooks X-Hub-Signature-256

Installation, PR, check_suite and check_run events back to the agent. Unsigned requests are rejected with 401.

/proof REAL-only ledger

Every action with an external link: PR, checks, NVD. DEMO can never appear here.

/status.json computed health

Machine-readable service state and capabilities. Computed per request (30 s cache).

/live SSE stream

Watch transitions as they happen. Read-only.

llms.txt for AI evaluators

Plain facts and evidence URLs for external agents. No marketing.

Next: methodology · security model · live status