Docs

How PartKit works

The shared mental model — for a developer evaluating PartKit and for an AI agent working inside a PartKit-locked repo. Read this once and the CLI, the /panel, and the lock all make sense.

This doc describes mechanisms honestly: what the lock guarantees today, and what is still roadmap. If a sentence here ever stops matching the code, the code is right and this doc is a bug.


The one-sentence version

PartKit vendors verified backend parts into your repo and locks them, so the infrastructure your AI agent depends on can't be changed without it showing up — as a red diff in your editor and a failed check in CI. The parts stay legible and accountable; your agent wires the seams and builds the product on top.

The value isn't the code (it's commodity). The value is that the backend stays legible and under control while an agent works fast on top of it.


The four nouns

Everything in PartKit is one of these. Keep them straight and the rest follows.

Noun What it is Example
Capability An abstract contract — what a slice of backend does, pinned to a major version. A commons; vendor-neutral. billing.subscription, email.transactional, auth.session
Part A concrete, verified implementation of a capability. This is what gets vendored into parts/<name>/. the billing.subscription@1.2.0 part
Adapter / vendor The swappable provider inside a part. One capability, one interface, N vendors. stripepaddle; resendpostmarkses
Seam The single typed surface your app imports — parts/<name>/src/index.ts. The only legal way to use a part. Everything behind it is sealed. import { sendEmail } from "@parts/email.transactional"

So: you pick capabilities, each resolves to a part, each part runs on a chosen adapter/vendor, and your app touches it only through the seam. A vendor flip (stripepaddle) changes the adapter behind the seam; your app code doesn't move.


The lock — what it is and what it actually guarantees

Every vendored part directory is content-hashed (parts.lock pins the hash; each part carries an ATTESTATION.json recording the hash it was verified at). Three things check it:

  • partkit guard — a pre-commit hook. Refuses a commit that changed a part's bytes without going through a sanctioned command.
  • partkit audit — runs in CI. Re-hashes every part, fails the build on any drift, and checks attestations + wiring.
  • partkit conform — also in CI. The spec-loop (next section).

What this guarantees today, honestly:

Legibility / no silent drift. If anything edits a part's interior — most often a helpful agent "fixing" something mid-task — the hash changes and guard (local) and audit (CI) go red. The change cannot land quietly. This is real, mechanical, and not downgradeable to a warning. It's the common, important failure mode, and the lock stops it cold.

⚠️ Not yet cryptographic tamper-proofing. Today's attestations are dev:unsigned and every trust artifact (parts.lock, ATTESTATION.json, parts.spec.json) lives in the repo. A determined actor with write access who also rewrites the lock and the attestation can re-bless an edited part. So the guarantee today is "infra changes are legible and reviewable," not "an adversary cannot alter a part." Closing that gap needs a root of trust outside the repo — real signing, and server-side hash enforcement — which is the cross-repo / team direction, not the in-repo free tier.

The honest framing: the lock is a strong, real tripwire against drift (the thing agents actually do), and the path to hard integrity is the cross-repo product.

The two promises, kept separate: Legibility (every infra change is a reviewable diff) is real in your repo today. Enforced integrity (a change can't be merged at all) needs an out-of-repo authority and is the team tier. We don't conflate them.


The spec-loop — "built to spec"

The lock protects the parts. The spec-loop protects your intent.

  • parts.spec.json records what you configured: which capabilities you chose and which vendor each runs on. It's the captured intent — the bus between the configurator, the CLI, and the panel.
  • partkit conform diffs intent against reality and reports "built to spec": every specified capability is installed, locked, on the vendor you picked, and not silently re-implemented by hand.

This is what catches an agent that, say, swaps your billing vendor or hand-rolls a capability instead of using the verified part. (Hand-roll detection today is import-based — it sees a part being bypassed by an SDK import; raw-HTTP reimplementations are a known blind spot we're widening.)

conform is the moat: not just "the parts are intact," but "the backend is the one you asked for."


The /panel — control made visible

Every PartKit app ships a local /panel route: the control panel for your backend.

  • Read-only legibility: which parts are verified, what your agent can touch (nothing, behind the seam), whether the build is built to spec, and what each part costs to run.
  • The editable vault: swap a vendor, add a capability, customize (eject), or remove — each runs the real operation locally, then shows you the git diff, re-locks, and re-runs conform. You watch your backend get rewritten safely: intent and code move together, so the lock stays green.

The panel's write actions are local-dev only — gated to loopback requests, so a deployed app never rewrites its own tree from an HTTP call. (Set PARTKIT_PANEL_ALLOW_REMOTE=1 only if you knowingly run dev on a remote box.) The gate is header-based, so don't bind the dev server to 0.0.0.0 on an untrusted network — see trust-and-security.md for the exact limits.


The lifecycle — from nothing to deployed

npx create-partkit-app          # a running, locked backend on a zero-config DB (pglite) — boots in seconds
  ↓
partkit add <capability>      # vendor a verified part in (or `add <pack>` for a whole kit)
partkit wire <part>           # scaffold the route/seam wiring
partkit doctor                # is it actually wired and reachable?
  ↓
partkit provision db          # a real Postgres on YOUR Neon, migrated, wired
partkit provision <part>      # guided steps to set up the vendor's credentials (working ≠ on-spec)
  ↓
partkit push                  # your repo on GitHub — CI runs `partkit audit` + `partkit conform` on every push & PR
partkit deploy                # a live URL on YOUR Vercel, DB connected

Every rung lands on your accounts (your GitHub, your Neon, your Vercel). PartKit AI never hosts your backend. The in-repo experience — parts, lock, panel, the whole loop above — is free. The cross-repo layer (a team dashboard across all your repos, private registries, server-enforced integrity, governance) is the paid tier.


For your AI agent — working inside a locked repo

If you are an AI agent in a PartKit-locked repo, here is the contract:

  • parts/** is not yours to edit. Import only from a part's seam (parts/<name>/src/index.ts, usually aliased @parts/<name>). Everything behind the seam is sealed; editing a part's interior changes its hash and the build goes red. This is by design — you don't have to re-derive auth, billing, or webhooks; they're verified and done.
  • Wire seams, build the product. Your job is the app: routes, UI, business logic, and the glue that calls the parts through their seams.
  • Change parts through the sanctioned verbs, never by hand: partkit add (new capability), partkit upgrade (new version / vendor swap), partkit eject (take ownership — see below). add and remove move the lock and the spec (parts.spec.json) together; upgrade and eject move the lock only — after an upgrade --adapter vendor flip, update the spec to the new vendor (the /panel does this) or partkit conform flags a VENDORS mismatch.
  • Eject is the honest exit. If a part genuinely can't meet a need, partkit eject <part> moves it to ejected/, drops its lock, and hands you the code to own. It's loud and reviewable on purpose — the legitimate way out, not a bypass.
  • Keep it built to spec. After any backend change, partkit conform should stay green. If you swapped a vendor, the new vendor needs credentials (partkit provision <part>) — on-spec is not the same as working.

The scaffolded AGENTS.md in each app is the in-repo, enforced version of this contract.


What "verified" means (precisely)

When the panel or CLI says a part is verified, it means, today:

  • its bytes match the attested content hash (no drift since it was issued), and
  • the app is built to spec (the right capabilities, on the right vendors, not hand-rolled).

It does not yet mean a trusted third party cryptographically signed it — attestations are dev:unsigned today; real signing (and server-side hash enforcement) is the integrity work that belongs to the cross-repo tier. We say exactly what we check, and nothing more.


Where to go next

  • Anatomy of a part (contract, conformance, attestation, versioning) → docs/02-part-specification.md (contributor-facing; being refreshed).
  • The registry, resolver, and CLI internalsdocs/03-architecture.md (contributor-facing; being refreshed).
  • Per-part docs → each part ships SPEC.md (what it does) and seams.md (how to wire it).