Agent docs

System classes

The kinds of thing a system can be, and what each owes the others.

The owner's frame, 2026-08-18: with agents writing most of the code, the estate can stop stacking onto one codebase and run "a factory approach": parts that each provide a specific value, standard plumbing every part needs, and customer-facing apps that are assembled from a mix of both, each with some one-off, imperfect, customer-specific additions, which is fine and is how every sibling app was built. This doc gives that frame words: eight of them, each with what we mean by it today, the estate read through them, questions that usually help decide which word fits, and the weaknesses we already know about. It is a vocabulary for naming, filing, and planning. It is not a taxonomy: the words overlap, a thing may take two of them, and at least one kind of thing has no word yet. Third pass, 2026-08-18; earlier passes and a skeptical review are logged at the end so the reasoning is auditable. Tagged as working names by the owner on 2026-08-18 after the third naming test; expected to change if a fourth naming strains it.

Audience: anyone naming a thing, filing a doc, planning a build, or deciding where a piece of work belongs.

Why words, and two commitments#

The factory works only if its parts are standard: an agent building the ninth module must not rediscover what a module is, and an agent assembling an app must not read a module's source. Agreeing on a word for a thing is the cheapest way to agree on its contract, owner, version cadence, docs, and callers, which is all this vocabulary is for. Two commitments sit under the frame:

  • The seams are the product. Modules and apps are replaceable; the contracts between them and the runner they share are what compound.
  • Bespoke work is allowed and labelled. Every sibling shipped customer-specific glue. It is a label on code under any word, with rules that keep it bounded (below), not a word in the table.

The words#

One row per word. What we mean is how the word is used in this tree today, written tightly so it can be argued with; it is not a rule of membership. Maturity says how much weight the word can bear: settled (used the same way everywhere, no known strain), working (used consistently here, known to overlap with a neighbour), provisional (kept for now, might fold into another word). Examples are what exists in the estate. Also called are the alternatives considered.

WordWhat we mean, todayMaturityExamples in the estateAlso called
PayloadThe authored implementation of one capability: code that takes one item and a context and returns an outcome, using only the runner's verbs, holding no queue, store, credential, or per-tenant state of its own. A capability may have several variants (canon/14); each variant is a payload and the manifest names the default. A judge is a payload when it runs inside the module.working; overlaps with runner at the seam, and a connector's payload is not item-shapedthe enhancement agents in lib/pipeline/methods; speedway's partType, scrape, normalize, content processors; walmart's taxonomy/, scraping/, content/, walmart/ packages; the extractor's scrape laddercapability code, method, step, agent
RunnerThe standard engine that turns payloads into a callable service: it accepts jobs from identified callers for a tenant, dispatches and executes payloads with retries, heartbeat, cancel, and checkpoint, records outcomes and usage and logs, and serves the module surface on the module's behalf. It calls payloads through contracts/runner-verbs.md. Prescriptively one implementation per language, shared by every module.working; by the fitting test it is the largest fitting, promoted for emphasis because two contracts bind ittoday five, none shared, which is the thing the factory changes: versable-runner's app/; speedway's run.server.ts + runs.server.ts + queue.server.ts; walmart's orchestrator.py + jobs.py + worker.py; App V5's worker/ + lib/tasks/; the runner template to be builtengine, harness, worker framework, jig
ModuleA deployed unit that is one capability (its variants and its judges included) mounted on the runner, with a manifest, its own version, identity audience, queue, and storage, exposing contracts/module-surface.md, callable standalone by any app and composable through requires/provides. Co-hosting a second capability in one deployment is the stated exception in canon/14, not the default. A connector is a module whose payload's truth lives in an external system it mirrors and never owns. Prescriptively a module has a manifest; no deployment has one yet, so today's are modules-in-waiting. A judge deployed standalone is a module.working; a deployment, not a kind of code, so it sits at a different level from payload and fitting; connectors strain the job shapemodules-in-waiting: content generation (services-api), extraction (extraction-api, provisional until its source is read); to be built: image generation, part-type matching, attribute normalization; connectors to be built: Walmart Marketplace publish and reconcile (today a payload inside walmart-mvp), a future PIM synccapability service, service, connector (for the external-system kind)
FittingA cross-cutting, standard system every runner and app needs, delivered as a recipe plus library code or one shared service, and authored here rather than bought: replacing it with an equivalent changes nothing about what a customer can do (their screens, their credits, their alerts keep working the same way). Identity verification and tenancy propagation, queue adapters, storage adapters, caching, the credits and usage ledger, observability, configuration and secrets, deployment and environments, notifications, and the UI kit on the app side.working; the broadest word here, and the runner passes its testthe verifier port and the issuer; the queue port with Cloud Tasks, arq, and in-process adapters; the storage port; the metering ledger; the logger and tracer; the config object; deploy.sh; @versable-git/uiplumbing, rigging, substrate, chassis, infrastructure, kit (UI)
AppA customer-facing application that owns users, tenants, tenant configuration, the catalog or other system of record, orchestration, review, and its own outputs, and composes modules and fittings around them. An app is nobody's dependency: no module or other app submits work to it; modules call back into an app that asked them to, and an app may expose its own data API to a customer system.working; app-side engines (orchestrator, review queue, catalog) have no word yet and are filed here for nowthe Workflow Console, walmart-mvp, speedway, App V5, Winhere if revivedshell, product, console, surface
ContractA normative shape that lets things built by different people or agents agree without reading each other's source: the module surface, the manifest and field registry, the runner verbs, the usage event, callbacks, conformance. Versioned rarely; a breaking route change bumps the path prefix, and contract_version in the manifest says which contract a module speaks (canon/11).settledcontracts/* in this treeseam, interface, spec, protocol
Reference dataA published, versioned data artifact that payloads load and never query live: taxonomies, PCdb, AutoCare, a marketplace's spec sheet, accepted-value lists. Has a publisher; the version used is recorded on every outcome.provisional; could fold into a fitting concern plus an artifact typedone as the word asks: services-api/assets/, speedway data/, walmart's spec snapshot; done as the word forbids and listed as the lapse: App V5's second read-only Mongo and walmart's TaxonomyKnowledge in Postgres, both queried live (canon/05)stock, snapshots, feedstock, datasets
CanonThe written knowledge that tells an agent or a person how to build and judge the other kinds: rules with reasoning, guides, instance breakdowns, ADRs, evidence.settledthis tree; versable-builder's design language, guidebook, patterns, breakdownsdocs, doctrine, design language

Eight words. Payload, runner, module, fitting, and app are said of things that run; contract, reference data, and canon of things they are built with. The count is not a claim that the space is covered.

Three notes the words need beside them:

  • Reference data is the only kind of data with a word of its own. The other content buckets in guides/02 (identity data, system config, tenant config, the job snapshot, the record) are owned by an app, a runner, or a module and have no word of their own.
  • A declared output transform (canon/15) has no word either; it is an artifact of the manifest, owned by the module for module-native outputs and by the app for exports.
  • A pure data transform with no vendor, no model, and no state is a function inside whatever calls it, not a payload and not a module (guides/00).

A label that crosses all of them: bespoke#

Bespoke (working name; also trim, custom, one-off) is a label, not a word in the table above. The table answers "what kind of part is this"; bespoke answers "how far may it travel". Bespoke code sits under a word (an app, a payload variant) and carries the label because it exists to meet one customer's exact need, names that customer, and would not belong in a second app. It is allowed, because that is how every sibling shipped, and the label comes with governance because otherwise it spreads:

  • it lives in a named place (bespoke/<customer>/ in an app; a bespoke: tag on a payload variant), never scattered across FE and BE
  • it appears in the owning instance doc's Lapses or a Bespoke section
  • it carries an expiry or a review date; at review it is promoted (to a payload variant, a module, a fitting, or tenant configuration), declared permanent with a reason, or deleted

The estate's examples: JEGS and Zeder upload and enhancement templates hardcoded across App V5's frontend and backend (owner, evidence/20260817-owner-answers.md §12); walmart's global rate floor standing in for per-seller tiers (walmart_items_rpm, guides/02, evidence/20260818-data-model-split/walmart-mvp.md §7); customer xlsx skeletons committed to App V5's backend repo (evidence/20260818-data-model-split/enhancement-product.md §4).

Three delivery forms, not words in the table#

  • Scaffolds and templates are how a kind of thing is delivered as code to start from: the runner template, a module scaffold, an app starter. A scaffold is a runner or a fitting or an app in template form.
  • Shared services are fittings deployed once and called (the issuer, a shared vendor cache); most fittings are libraries. Same word, two forms.
  • Tools are code that produces or checks an artifact of another kind and runs nowhere at request time: the snapshot tool that publishes reference data, scripts/build-do-nots.py that generates canon, a conformance runner, and a proof surface such as versable-builder's playground (canon tooling that also hosts primitives; vb-fable's warning is that a proof surface out-costs the product if it becomes one). A tool is filed under the word whose artifact it produces.

Questions that usually help decide#

Ask roughly in this order. They are not a test with a single answer; when two questions both say yes, the thing is both, and the doc filing goes with whichever the reader would look under first.

  1. Does it have users and tenants, and does a customer open it? App.
  2. Does it take an item and return an outcome? Payload. (If it would break when the queue or store changed, it is still a payload; it is a leaking one, fix it per canon/01.)
  3. Does it accept jobs, run payloads, and serve /jobs? Runner if it is the shared engine; Module if it is a deployment of it with its own manifest, version, and identity audience.
  4. Is it authored here, would every runner and app need it, and does swapping it for an equivalent leave what the customer can do unchanged? Fitting. Bought infrastructure (Redis, Cloud Tasks, GCS, Langfuse) is not classified; the adapter over it is the fitting.
  5. Is it data with a publisher and a version, loaded rather than queried? Reference data.
  6. Does it exist so two things built by different people agree? Contract.
  7. Does it tell someone how to build one of the above? Canon.

And the label: does it name a customer? Bespoke, on whichever word it sits under.

Confusions the tests catch:

  • A "module" that reads the customer's org table is an app fragment.
  • A "fitting" that changes what a customer sees (a review queue, an export shape) is app.
  • A feature two apps need is a module or a fitting waiting to be extracted; the tell is the second copy.
  • Reference data queried live from another system's database is reference data placed wrongly (canon/05).
  • A payload that imports a queue client, a store client, or a tracing client is a runner leak (canon/01).
  • Bespoke that survives two reviews is promoted or declared permanent.

The estate read through these words#

One line per real thing, to see whether the words are enough to name it. A cell may carry two words.

ThingWord(s)
services-api deploymentmodule-in-waiting (content), whose runner is app/ and whose payloads are lib/pipeline/methods; a module once it serves a manifest
extraction-api + extraction-workerprovisionally a module-in-waiting (extraction); no source read yet (instances/extraction.md), so which parts are runner, payload, and topology is unconfirmed
walmart-mvpapp; inside it a runner (orchestrator.py, jobs.py, worker.py), payloads (taxonomy/, scraping/, content/), and in walmart/ the payload of what would be a connector module
speedwayapp; inside it a runner and four payloads; its extractor client is how an app calls a module
App V5app; inside it a runner (worker/, lib/tasks/), many payloads, and fittings (breakers, retry budget, heartbeat, credits) that the contract lifts out
the issuerfitting, shared-service form
Redis on Renderbought infrastructure, unclassified; the cache and queue adapters over it are fittings
PCdb, AutoCare, the Walmart spec snapshotreference data
deploy.sh, build-do-nots.py, the snapshot tooltools: of the deployment fitting, of canon, of reference data
@versable-git/uifitting, UI side
the Workflow Consoleapp
JEGS and Zeder templates in App V5bespoke, in an app
this tree, versable-builder docscanon

Two things the reading exposed. The sibling apps each contain a runner and payloads and fittings inside one repo, which is exactly the App V5 assumption the factory replaces (guides/00), and the words give that extraction a vocabulary: lift the runner out as the shared one, lift payloads into modules, lift fittings into recipes, and the app keeps what is left. And several things needed two words or a note, which is the honest signal that this is a vocabulary and not a partition.

Known weaknesses#

Written here so the tidiness above is not read as finality. Each is real; none is fixed yet; the trigger for fixing them is at the end.

  1. Three kinds of distinction in one list. Payload, runner, module are nested (a module is a payload mounted on the runner, deployed); fitting is cross-cutting; app is a deployment; contract, reference data, canon are artifacts. A cleaner shape is two axes, artifact kind (running code, deployment, data, spec, knowledge) by role (produces value, carries value, composes, assembles), with these words as cells. A flat list was kept because folders and plans are named by single words.
  2. The runner passes the fitting test. Authored here, every module needs it, swapping it for an equivalent changes nothing a customer can do. It has its own word because two contracts bind it and the owner named workers as primary; that is an emphasis, not a difference in kind.
  3. Module is a level, not a kind. "Deployment of runner plus payload with a manifest" puts module at a different level from payload and fitting, which is why the manifest became the discriminator and why today's deployments had to be called modules-in-waiting.
  4. Connectors strain the job shape. The contract is N items in, N outcomes out; a marketplace's reconcile and unpublish sweep are long-lived sync loops over state the app does not own. Calling a connector "a kind of module" may bend the job envelope to fit. This is likely the first place the runner needs a second primary shape (a sync loop with a cursor and a reconcile).
  5. App-side engines have no word. The orchestrator loop, the review queue engine, and the catalog as system of record are filed under app, and the "a feature two apps need is waiting to be extracted" test will fire on all three once Winhere, walmart, and the console share them. They are neither modules (not item to outcome) nor fittings (not every app needs an orchestrator). A word is missing here.
  6. Bespoke is a wish without a mechanism. A label with a folder, a review date, and a promotion path binds only if something enforces it; nothing does yet, and the label will be skipped exactly when it matters.
  7. The wire field was renamed to protect a word. payload became input on the wire so the word means one thing. Cheap now; still the vocabulary bending the contract rather than the reverse.
  8. Reference data is borderline. It is the only data word beside two document words; it earns its place because every sibling placed it differently, and it folds into a fitting concern plus an artifact type without loss if fewer words are wanted.

When to restructure: use these words to name the next three real things (the runner template, the content module upgrade, the console plan). If the third one does not fit without a note, move to the two-axis shape and add the app-engine word then. Do not polish the list before that.

Names#

The owner asked for a name for the plumbing word and for the choice to be tagged. Working names; expiry is the same trigger as above. Candidates and reasoning:

CandidateWhy it fitsWhy it might not
Fittingsplain word, extends the plumbing metaphor, pairs with "kit" (@versable-git/ui) as the two things every app is fitted with; standard, replaceable, nobody's productslightly quaint
Riggingthe bolted-and-riveted metaphor; holds the load without being the cargoreads as ropes
Substrateprecise: what everything sits onabstract, no verb
Chassisvehicle metaphor; the app is the bodyclose to "shell", which was dropped for implying empty
Plumbingthe owner's word, zero explanationpejorative in a customer deck

Recommendation: Fittings. Full vocabulary: payloads, runner, modules (and connectors), fittings, apps, contracts, reference data, canon, plus the bespoke label. All plain words. Collisions inside the estate, and which reading wins where:

WordAlso meansRuling
payloadthe per-item input on the wire ({item_id, payload} in versable-runner; payload.json in its bucket)the class wins; the wire field is input in the contract as of 2026-08-18, and versable-runner's payload.json is a lapse to rename on upgrade
modulea speedway stage file (app/lib/modules/*.server.ts); App V5 and the kit use "module" for a UI or product modulethe class wins in this tree; speedway's files are payloads under it
runnerversable-runner, the service name; pipeline_runner.py, a CLIthe class wins; the service is a module-in-waiting whose runner is app/
appthe app/ directory in versable-runner (the runner) and in speedway (the whole app)folder names are not classes; the class wins in prose
kit@versable-git/uikept as the UI fitting's proper name

Tagged 2026-08-18 by the owner: working names, "just tagging", no restructure. The eight words above and the bespoke label stand as the working vocabulary, with the restructure trigger unchanged (naming test three, the console plan, passed with the one friction noted in plans/v6-decision-set.md D10). Two more working names joined at the same ruling, at the estate level rather than the class level:

WordMeansOwner's words
forgethe product app: App V6 (versable-forge-v6) and its successors, the thing customers use"forge for the final customer main app with big balls"
foundryversable-builder (the kit, the templates, the toolkit) plus this contract tree: what the forge is built from"foundry for the builder / contract stuff"

versable-builder currently describes itself as "a monorepo forge" (its ADR-001 context); under this tag it is the foundry, and that relabel is the versable-builder lane's to carry. Still to tag in adr/006 and the versable-builder glossary when those files are next touched.

What the words change in this tree#

  • canon/01 is the payload/runner seam; the other canon docs each bind one or two words (02 fittings and apps, 03 and 04 runner, 05 to 09 fittings, 10 module and app, 11 module, 12 and 13 fittings, 14 module, 15 module and app); contracts/ is the seams; patterns/ is how to build each kind; guides/ are the decisions that cut across kinds; instances/ breaks down every shipped app and module; v6/ is the canon for the first app.
  • Repo and folder names carry the word: modules/content, runner/py, fittings/identity, apps/console; reference data is a published artifact in object storage, so its folder, if any, holds the publisher tool, not the snapshot.
  • A plan for a new thing starts by saying which word it takes, and says so if it takes two or none; a "none" is a finding for this doc.
  • Every app gets a bespoke/<customer>/ folder and a Bespoke section in its instance doc.

Third pass: the skeptical review, 2026-08-18#

A fresh reviewer read the second draft against the whole tree (evidence/20260818-class-model-review.md, 29 findings). All were folded above except where noted; the dispositions are in that file. The ones that changed the model: the fitting clause now discriminates on what a customer can do, not what they see, and requires "authored here" so bought infrastructure exits the test; the ordered test's second question now returns a word; tools became a third delivery form; the manifest is stated as prescriptive and today's deployments as modules-in-waiting; the module is one capability by default with co-hosting as the canon/14 exception, reconciled with the charter; the wire field payload was renamed input so the word means one thing; the "no collisions" claim was replaced by a collision table.

Changes from the first draft, and why#

First draftNowReason
workers and queues listed as a fittingRunner is a class; the queue adapter stays a fittingthe runner is the standard machine bound by two contracts, not swappable plumbing; owner: "workers seems way more primary than just fittings"
Jigs as a classscaffolds are a delivery forma template is a runner or fitting in code form, not a kind of system
ShellsApps"shell" says empty; the console owns the orchestrator and the system of record
Trim as a classbespoke as a label across classesit is a property of code that any class can carry; making it a class hid that
Connectors as a peer classa kind of modulesame manifest, jobs, runner verbs; what differs is a mirroring pattern, which is a guide
StockReference data, kept, foldablethe only non-code runtime class; every sibling placed it differently, which argues for a name; plain word over the cute one
no payload classPayload addedit is what a module builder writes, and the seam between it and the runner is the tree's foundation
definitions mixed with examplesseparate columnsowner: the "in one line" column "devolved soon into just listing out what all can come under this"
@versable-git/ui · reference, canon, and method, read in place