How a keystroke becomes a production signal — and how the system stays swappable
Search PRs, rules, files…⌘K
The five-layer pipeline
Shift-left in practice: the same rules run everywhere, just later and deeper each layer down.
runs on developer's deviceruns automated on the server
Layer 1 · IDE< 1 sec
Linter + type checker run as a language server the moment you type. Config lives in the repo, not on anyone's machine.
ESLintTypeScript strictRuffmypy
Layer 2 · Pre-commit< 10 sec
Format + auto-fix on changed files only — never the whole repo, or developers will route around it.
Huskylint-stagedpre-commit
Layer 3 · Pull request< 10 min
SAST, tests + coverage, dependency scan and AI review run in parallel — nothing waits on anything else.
SemgrepCodeQLClaude reviewSnyk
Layer 4 · Quality gateinstant
Clean-as-you-code: only the new diff is judged. Fail one required check and merge is locked — including for admins.
Branch protectionRequired checks
Layer 5 · Post-mergescheduled
The slow, deep checks that would make a PR wait too long — run nightly instead, and feed findings back as new rules.
FuzzingMutation testingSentry
Why five layers, not one big check?
The earlier a layer catches something, the cheaper it is to fix. A typo caught in the IDE costs a keystroke; the same typo caught in production costs an incident.
System architecture — four independent layers
Each layer only talks to its neighbor. Swap what's inside a layer and nothing above or below has to change — that's how the platform absorbs whatever tooling comes next.
InterfaceHow teams reach the platformChanges freely — nothing below it notices
Web UIThis dashboard — Next.js, static-exportable
IDE pluginVS Code · JetBrains, real-time squiggles
CLIzcv scan for local & CI use
APIREST / gRPC, for third-party integration
WebhookGitHub · GitLab · Bitbucket receivers
Primary surface today:Web UIIDE pluginCLIHeadless API
The three services never call each other directly — they publish and subscribe over a message bus (NATS or Kafka), so any one can be redeployed or rewritten without the other two noticing.
SAST engine:SemgrepCodeQLSonarQube+ next engine
AI reviewer:ClaudeOpenAILocal model+ next provider
Every provider implements one AIReviewer interface — adding a new one is a new adapter class, never a change to the pipeline that calls it.
DataPolyglot persistenceThe stable core — the piece that changes least often
PostgreSQL 16+Issues · rules · users · projects
ACID + pgvector, ready for future AI features
TimescaleDB 2.xMetrics · trend · coverage over time
100× faster than plain SQL for time-series
Redis / Valkey 7+Job queue · cache · session
Fast, simple, open-source fork of Redis
S3-compatible · API v4SBOMs · artifacts · raw scan results
Tracing & logsOpenTelemetry + Jaeger · Loki or ELK
Cloud target:AWSGCPAzureOn-prem
Built to outlive today's tools
A new SAST engine, a different LLM provider, a new cloud, even a new interface (say, a chat surface or an agentic reviewer) —
each is a swap at one layer. The contract between layers is the API, not the implementation, so the rest of the stack never has to know.