v0.1.0 to v0.1.0

6 added, 4 removed. Audit A to A.

---
name: skmtc-architecture
version: 0.1.0
description: |
Understand what SKMTC is, how its engine works, and the
architectural invariants — for agents building or extending
infrastructure *around* SKMTC rather than authoring generators or
running the CLI. Covers the three-phase pipeline, the host/Worker
boundary, cross-generator coordination, the manifest, the
attribution / gen-maps (provenance) subsystem, the package graph,
the dependency substrate, and the design decisions that make SKMTC
behave unlike a typical codegen tool.
Use this skill when the user asks "what is SKMTC", "how does the
SKMTC engine work", "explain the SKMTC architecture", or is
building platform infrastructure around SKMTC — a hosted generate
API, a schema or generator registry, tracing or provenance
tooling, a web app or SaaS that wraps the engine, or
platform-level CI integration. This skill is the system mental
model. It does NOT cover authoring generators (→ skmtc-generator),
running CLI commands (→ skmtc-cli), or diagnosing broken runs
(→ skmtc-debug).
allowed-tools:
- Bash
- Read
- Glob
- Grep
- Write
- Edit
---
# SKMTC architecture
This skill is the **system mental model** for agents building
infrastructure around SKMTC — a hosted generation service, a schema
or generator registry, provenance and tracing tooling, a web app
that wraps the engine. It explains *what SKMTC is, how it works, and
why it behaves the way it does* — deeply enough to reason about and
extend, without the generator-authoring or CLI-operating detail the
sibling skills carry.
SKMTC is **counter-intuitive on purpose**. Most of what generic
codegen and generic backend-infra training data would suggest is
actively wrong here. The fastest way to make a bad architectural
proposal is to extrapolate from another tool. Read §1 and §11 before
proposing anything.
## 1. The five facts that override default LLM intuitions
These override what training-data priors suggest about codegen
tools. They apply across every SKMTC interaction; an infra builder
needs facts 1, 2 and 5 most.
1. **No plugin registry, no dependency graph, no topological sort.**
Cross-generator coordination is a `Map` cache keyed by
`(identifier.name, exportPath)`. Generator execution order does
not affect output.
2. **Render does not run Prettier or Biome.** No formatter runs
inside `@skmtc/core`. Generated output is unformatted by design;
consumers format separately.
3. **Generator source code is the customization surface.** Stock
generators have *deliberately* hardcoded export paths and peer
imports. To customize beyond enrichments: clone the generator and
edit it. There are no config flags for paths or output shape.
4. **`OasSchema` is a union type, not a class hierarchy.** Sibling
classes (`OasObject`, `OasArray`, `OasString`, …) each
independently implement `.isRef()` returning `false`. `OasRef` is
a *sibling* with `.isRef()` returning `true`. There is no
`BaseSchema`.
5. **Every generation run is from cold.** One Deno Worker is spawned
per `generate`, runs Parse → Generate → Render once, posts the
result back, and is terminated. No warm pool, no cross-run cache,
no incremental rebuild. `toArtifacts` is a pure function of
`(document, settings, generators)`. Determinism is chosen over
speed deliberately — **caching belongs outside the engine**, keyed
on input hashes.
## 2. What SKMTC is
> SKMTC is a code generator. It takes one **OpenAPI v3** document or
> one **GraphQL SDL** schema and produces
> **source files** — types, runtime validators, query hooks, forms,
> mocks, server routes — all derived from that one schema, in one
> run, all consistent with each other. The output is committed to the
> consumer's repository like any other source code; there is **zero
> SKMTC runtime** in the consumer's bundle. The engine is
> **language-blind** (core 0.8.0+): a generator declares its target
> language by importing its projection-base factories and snippet
> base from a `@skmtc/lang-*` package — the import graph alone
> carries the language; entries have no `lang` field. TypeScript
> (`@skmtc/lang-typescript`) and Kotlin (`@skmtc/lang-kotlin`, proven
> by `gen-kotlin` DTOs + `gen-kotlin-spring` controllers) are the
> production languages; other `lang-*` packages (C#, …) are the
> roadmap.
The crucial reframing for an infrastructure builder: **SKMTC is an
engine with several thin hosts, not a CLI.** The CLI is one host.
The mental decomposition:
| Layer | Package | Role |
|---|---|---|
| **Engine** | `@skmtc/core` | The three-phase pipeline. Entry point: `core/run/toArtifacts.ts`. |
| **Worker host** | `@skmtc/worker` | Wraps the engine in a Deno Worker `postMessage` handler. |
| **CLI host** | `@skmtc/cli` | Local developer surface: scaffold, install, bundle, generate, watch. |
| **HTTP host** | `@skmtc/server` | Hono app — the hosted "Sandbox API". `POST /artifacts`. |
| **MCP host** | `@skmtc/mcp` | Model Context Protocol server surface. |
| **Schema normalizer** | `@skmtc/convert`, `@skmtc/openapi-down-convert` | Swagger 2 / OAS 3.1 → OAS 3.0. Runs *before* the engine. |
| **Generators** | `@skmtc/gen-*` | The actual codegen logic, distributed as JSR packages. |
Every host does the same thing: get a schema, call `toArtifacts`,
do something with `{ artifacts, manifest }`. **A SaaS is just
another host of the same engine.**
## 3. What you get — the benefits
- **Multi-artifact coherence.** One schema yields N artifact types
(types + validators + hooks + forms + mocks + routes) that
reference each other correctly. Add a field, regenerate, every
artifact updates consistently.
- **Output is committed source code.** Reviewable in `git diff`,
grep-able, refactorable. No runtime library, no peer-dependency
package at deploy time. Schema/output drift is visible in version
control.
- **Determinism.** Same inputs → byte-identical output. No hidden
state, no order dependence, no warm-cache effects.
- **Idempotency by construction.** Generators coordinate by
memoization, not by a dependency graph — so they can be written,
tested, and reasoned about in isolation, and order never matters.
- **Clone-to-customize.** Generators are owned source code, not
opaque configured dependencies (the shadcn/ui model).
- **Lenient input, strict diagnostics.** One malformed schema does
not kill the run; it is logged and its dependents pruned. The
`manifest.json` is an exhaustive record even when output is
partial.
- **OAS and GraphQL through one engine.** The GraphQL pipeline reuses
the same DSL, the same renderer, the same manifest.
## 4. When to use SKMTC — and when not to
| Verdict | Situation |
|---|---|
| **Strong fit** | An OpenAPI v3 or GraphQL schema is the contract; you need *multiple* artifact types from it; you want generated code committed to the repo. |
| **Overkill** | You only need types (`openapi-typescript`); you only need a typed fetch client (`@hey-api/openapi-ts`); schemas are dynamic at runtime (use a runtime renderer). |
| **Wrong tool** | Can't run Deno *and* won't use the hosted Sandbox API; you need production output in a language with no `@skmtc/lang-*` package yet (today that is everything except TypeScript — use `openapi-generator`). |
SKMTC's closest peer is `kubb` — multi-target, TypeScript-native.
The distinguishing bet is the **customization model**: clones (source
you own) over plugins (configured packages), plus **coordination by
name** (memoization) over explicit composition. Full landscape:
[`explanation/comparison-to-other-tools.md`](../../explanation/comparison-to-other-tools.md).
## 5. How it works — the pipeline
A generation run is a one-way pipeline of three phases, each
producing an immutable artifact the next consumes:
```
┌─────────────── HOST PROCESS ───────────────┐
│ bootstrap · fetch schema · OAS pre-parse │
└──────────────────────┬──────────────────────┘
│ postMessage(GENERATE)
┌──────────────────────▼──────────────────────┐
│ DENO WORKER (sandboxed) │
│ PARSE ─▶ GENERATE ─▶ RENDER │
│ model files map { path: text } │
│ +issues (in memory) artifacts │
└──────────────────────┬──────────────────────┘
│ postMessage(RESULT)
┌──────────────────────▼──────────────────────┐
│ HOST: write files to disk · write manifest │
└─────────────────────────────────────────────┘
```
- **Parse** — schema → typed object model (`OasDocument` /
`GqlDocument`). Lenient: a per-item parser that throws becomes a
`ParseIssue`; `removeErroredItems` then prunes one hop of `$ref`
consumers of any failed component. Generate can trust every
surviving item.
- **Generate** — walk the configured generators over the parsed
document, producing an in-memory `Map<path, File>`. Generators
produce output via side effects (`register` / `insert*`), never by
return value. Memoized **Drivers** dedupe and coordinate (§6).
- **Render** — serialize each `File` to a string by joining
re-exports, imports, and definitions. **No formatter runs.** Output
is `Record<path, content>`.
Each phase boundary is an immutable hand-off — the next phase reads,
never mutates. Detail:
[`concepts/the-three-phases.md`](../../concepts/the-three-phases.md).
### The host / Worker boundary
The engine physically runs in a **Deno Worker** spawned by the host,
one per run (fact 5). The boundary is `postMessage`, which uses the
structured-clone algorithm — and that shapes a real asymmetry:
- **OAS is parsed host-side.** A plain `OpenAPIV3.Document` is JSON —
it survives structured clone. The host normalizes Swagger 2 / OAS
3.1 to 3.0 via `@skmtc/convert`, then posts the plain document.
- **GraphQL is parsed Worker-side.** A parsed `GqlDocument` has class
instances with cyclic back-references — structured clone strips
methods and prototypes. So the host posts the raw SDL **string**
and the Worker parses it.
The Worker boundary is also the **security boundary**. The Worker is
spawned with Deno permissions `read: true, write: true, env: true,
net: false, run: false`. Generator code (third-party JSR packages or
team-edited clones) cannot make network calls or spawn subprocesses.
It is a *soft sandbox* — it limits the blast radius of a buggy or
compromised generator, not a determined attacker. Schema fetching
happens host-side, before the Worker exists. Detail:
[`concepts/the-worker-runtime.md`](../../concepts/the-worker-runtime.md),
[`explanation/security-model.md`](../../explanation/security-model.md).
### The engine entry point
Every host calls one function:
```ts
toArtifacts({
traceId, spanId, startAt, // run correlation
document, // SkmtcDocumentInput (oas | gql)
settings, // ClientSettings (basePath, enrichments, skip, include)
toGeneratorConfigMap, // () => the registered generators
stackTrail, // position/trace stack
silent,
attribution // optional — turns on gen-maps (§8)
}): { artifacts: Record<string,string>; manifest: ManifestContent;
sidecars?; generationMap? }
```
It is pure with respect to its inputs and does no I/O of its own
beyond reading. `core/run/toArtifacts.ts`, `worker/mod.ts`, and
`server/src/createServer.ts` are three independent callers of it —
study them as the templates for a fourth.
## 6. How it works — cross-generator coordination
This is the single most counter-intuitive piece. There is **no
dependency graph and no topological sort.** Coordination is
**memoization**:
- A generator that needs a peer's output calls
`this.insertOperation(PeerProjection, op)` (or `insertModel` /
`insertNormalizedModel`).
- A **Driver** (`OasOperationDriver`, `GqlOperationDriver`,
`ModelDriver`) computes a cache key `(identifier.name, exportPath)`
— both pure functions of `(operation, enrichments)` via the peer's
static methods.
- **Cache hit** → the existing `Definition` is reused. **Miss** → the
peer's Projection is constructed (which may recurse), wrapped in a
`Definition`, registered, and its import stitched into the calling
file.
Because the key is a pure function of inputs, whichever generator
asks first triggers construction and everyone after gets a cache
hit — so the output `Map<path, File>` is **identical regardless of
generator order**. A `generatorKey` integrity check throws
`"Registered definition mismatch"` if two different
generator-and-input pairs collide on one cache key.
**Why this matters for infra:** order-independence means there is
nothing to schedule or sequence. Determinism means the *correct
caching layer is outside the engine* — cache the whole
`{ artifacts, manifest }` result keyed on a hash of
`(schema, settings, bundle)`. Never try to cache *inside* a run.
Detail:
[`concepts/cross-generator-coordination.md`](../../concepts/cross-generator-coordination.md).
## 7. The DSL in one screen
You do not need to author generators to build infrastructure, but
you should recognize the vocabulary (defer authoring to
`skmtc-generator`):
- A **generator** is a JSR package exporting an *entry* built with
`toOasOperationEntry` / `toGqlOperationEntry` / `toModelEntry`.
Entries are pure pipeline config — no `lang` field; the generator
declares its target language by importing its projection bases
from a `@skmtc/lang-*` package, and the engine's Drivers read it
off the projection class's inherited static.
- The entry's `transform` hook runs once per matched operation/model
and produces output by calling `register` / `insert*` — its return
value is discarded.
- A **Projection** is a *named, file-scope* artifact (`export const
X = …`), wrapped in a `Definition`, cached by `(name, exportPath)`,
reachable by other generators. A **Snippet** is an *anonymous*
fragment embedded into a Projection's body via template-literal
interpolation.
- Templates are TypeScript template literals inside classes — not
`.hbs`/`.mustache` files. Composition is by `${...}` interpolation
of anything `Stringable`. (Generators are *authored* in
TypeScript/Deno regardless of the target language they emit.)
**Vocabulary discipline:** in SKMTC prose use `register`, `insert`,
`render`. Avoid *emit*, *dispatch*, *stitch* — they map to no
exported surface. See
[`reference/glossary.md`](../../reference/glossary.md#skmtc-vocabulary--load-bearing-terms).
## 8. The manifest — the run contract and tracing
Every run writes a `manifest.json` (to
`.skmtc/<project>/.settings/manifest.json` for the CLI host;
returned in-band for the HTTP host). It is the **canonical record of
a run** — written *always, even on failure*. The terminal output is
a summary; the manifest is the full story.
```ts
type ManifestContent = {
deploymentId: string // the run; from DENO_DEPLOYMENT_ID or a timestamp
traceId: string // OpenTelemetry-shaped correlation key
spanId: string // sub-span within the run
region?: string // set only for hosted (Deno Deploy) runs
files: Record<path, { lines, characters, destinationPath }>
results: ResultsItem // nested tree of per-(generator × item) outcomes
previews, mappings // optional UI metadata (per-Definition source descriptors)
parseIssues: ParseIssue[] // every Parse-phase diagnostic
startAt, endAt: number // unix ms; endAt - startAt = worker wall time
}
```
What an infra builder must internalize:
- **Tracing is built in.** `traceId` / `spanId` are
OpenTelemetry-shaped. The `StackTrail` carries them as its root
frames, and the `results` tree is keyed by stack-trail strings —
so an outcome is addressable as
`traceId → spanId → generate → generatorId → item`. `deploymentId`
and `region` come from Deno Deploy env vars on the hosted path.
Wire these straight into an observability backend.
- **Exit / status derives from `parseIssues`, not from throws.** The
CLI returns exit 1 iff any `parseIssue.level === 'error'`. The
engine *fails open* — a bad schema does not throw, it logs. Your
HTTP host must compute status from `manifest.parseIssues`, not from
a `try/catch` around `toArtifacts`.
- **`results` outcomes:** `success` means "the transform ran without
throwing" — **not** "produced output". `notSupported` is normal (a
generator that doesn't apply to an item). `skipped` is filter
exclusion. Diagnose "no output" via the `files` map, not `results`.
- **No history.** The on-disk manifest is overwritten every run. If
you want run history, **persist each manifest yourself** — it is
already the right per-run telemetry payload.
Detail: [`concepts/the-manifest.md`](../../concepts/the-manifest.md),
[`reference/manifest-format.md`](../../reference/manifest-format.md).
## 9. Provenance — the attribution / gen-maps subsystem
- `core/anchors/` is the **provenance layer**. It is **opt-in**: pass
- `attribution: { enabled: true, postPass?: {...} }` to `toArtifacts`.
- When on, the run produces two extra artifact types alongside the
- code:
+ `core/anchors/` is the **provenance layer**. Capture is always on;
+ **emission is opt-in**: pass `attribution: { postPass: {...} }` to
+ `toArtifacts` (the engine-level `AttributionState` has no `enabled`
+ field — the `client.json#settings.anchors.enabled` switch is the
+ user-facing toggle). When emission is on, the run produces two extra
+ artifact types alongside the code:
- **Sidecar** (`<file>.skm.json`) — one per generated file. A
pooled, position-indexed map: byte ranges in the rendered file →
**attribution tuples** `{ genId, srcPtr, variant, defName }`, plus
generator version and source registry. It is a *source map for
provenance* — it answers "which generator, which schema location,
which variant produced *this span* of code?". `srcPtr` is a schema
pointer like `oas:#/components/schemas/User`.
- **Generation map** (`_map.ndjson`) — a project-level, per-Definition
**reverse-query index**: "which files came from refName `User`?",
"which files did `gen-zod` produce?". Wholly rewritten each run.
Both live under `.skmtc/<project>/.maps/` (gitignored by default).
Mechanism: `SnippetBase` instrumentation caches each producer's
rendered text; a post-pass walks the producer tree and AST-resolves
byte spans to landmarks. The AST parser (`oxc-parser`) does not
bundle into a Worker, so **inside the Worker** landmark names come
from `Definition` identifiers and a host-side post-pass can fill AST
detail later.
A lighter, always-on channel exists too: the manifest's `previews`
and `mappings` pair a per-Definition module with a **source
descriptor** (`{ generatorId, operationPath, operationMethod }` etc.)
— enough for a UI to say "this form was generated from `POST
/contacts`".
**If you are building provenance or "trace generated code back to
its schema" tooling, build on this subsystem** (`Sidecar`,
`GenerationMapEntry`, `AttributionState` — exported from
`@skmtc/core/Anchors`). Do not reinvent it.
Full treatment — the four-stage mechanism, the Sidecar v2 format,
the worker-side parser omission, the `doctor` checks:
[`concepts/attribution-and-gen-maps.md`](../../concepts/attribution-and-gen-maps.md).
## 10. The package graph and dependencies
### The `@skmtc/*` packages
```
@skmtc/openapi-down-convert (OAS 3.1 → 3.0, vendored fork)
@skmtc/convert (Swagger 2 / 3.1 → 3.0; YAML/JSON parse)
@skmtc/core ◀───────────────── the engine; depended on by everything
▲ ▲ ▲ ▲
│ │ │ └── @skmtc/gen-* (generators; + peer generators)
│ │ └────── @skmtc/server (Hono HTTP host)
│ └────────── @skmtc/worker (Deno Worker host)
└────────────── @skmtc/cli ──▶ @skmtc/mcp (MCP host wraps the CLI)
```
`cli` also depends on `convert` and `worker`. Exact versions live in
each package's `deno.json` — treat that as canonical, not this skill.
### The substrate
SKMTC's design principle "build on the substrate, don't rebuild it"
means **Deno is the platform**:
- `deno bundle` is the bundler — it compiles a project's `worker.ts`
into `bundle.js`.
- `new Worker(...)` with `deno.permissions` is the sandbox.
- **JSR** is the package registry. Generators and packages are
*ordinary JSR packages* — there is no bespoke registry layer (that
was explicitly rejected). Two registries are in play: `jsr.io`
(public) and `jsr.skmtc.dev` (the SKMTC private registry).
- The hosted Sandbox API runs on **Deno Deploy** (hence
`DENO_DEPLOYMENT_ID` / `DENO_REGION` flowing into the manifest).
The project is **Deno-locked**, and that is an accepted trade. The
*generated output*, however, runs anywhere TypeScript runs.
### Key third-party dependencies
| Dependency | Used for |
|---|---|
| `valibot` | Runtime validation of the manifest, settings, parse issues, generator configs, and sidecars. Each schema is paired with a TS type via an unread `_driftCheck` binding — **do not delete those**. |
| `graphql` | GraphQL SDL parsing (Worker-side). |
| `oxc-parser` | AST parsing for the attribution post-pass (chosen over `tsc` because `tsc` won't bundle into a Worker). |
| `openapi-types` | Type definitions for OpenAPI documents. |
| `hono` | The `@skmtc/server` HTTP framework. |
| `@modelcontextprotocol/sdk` | The `@skmtc/mcp` server. |
| `swagger2openapi` | Swagger 2.0 → OpenAPI 3.0 conversion inside `@skmtc/convert`. |
| `@cliffy/command`, `ink`, `react` | CLI command parsing and terminal UI. |
**Version-pin discipline:** inter-package `@skmtc/*` dependencies are
pinned to **exact JSR versions — no caret ranges** — so a cloned
generator and the engine it compiles against can't silently skew.
`skmtc doctor` checks that a project's `@skmtc/core` pin matches the
CLI's. Pins *can* lag between packages; always read `deno.json`.
## 11. Building infrastructure around SKMTC
The user's context: a **GitHub-like SaaS** for hosting APIs and
generators, running them, and supporting tracing and provenance.
Here is how the engine's concepts map onto that platform — and where
the engine stops and your platform code begins.
### The integration map
| Platform concern | What the engine gives you | What you build |
|---|---|---|
| **Hosting APIs (schemas)** | A schema enters `toArtifacts` as `SkmtcDocumentInput` — `{ type:'oas', value: OpenAPIV3.Document }` or `{ type:'gql', value: sdlString }`. `@skmtc/convert` normalizes Swagger 2 / OAS 3.1 to 3.0 *before* the engine. | Schema storage, versioning, ingest validation, the normalize-on-ingest-or-on-run decision. |
| **Hosting generators** | Generators are ordinary JSR packages (`@skmtc/gen-*`). `jsr.skmtc.dev` is already a JSR-compatible private registry. | A registry UX; discovery, search, featured ranking; the publish pipeline. |
| **Running generators** | A run needs a **bundle** — `worker.ts` (templated from the import map) compiled to `bundle.js`. `toArtifacts` then executes it. Three reference hosts exist: local Worker (CLI), Hono `POST /artifacts` (`@skmtc/server`), the Worker message protocol (`@skmtc/worker`). | The run service: validate → convert → `toArtifacts` → return/store `{ artifacts, manifest }`. Bundle build & cache. Execution pooling if you need throughput. |
| **Tracing** | `traceId` / `spanId` / `deploymentId` / `region` already populate the manifest and `StackTrail`; the `results` tree is trace-addressable. | Shipping them to an observability backend; cross-run dashboards. |
| **Provenance** | The attribution / gen-maps subsystem (§8): `sidecars` + `generationMap`, opt-in via `attribution`. | Persisting and serving them; a viewer that maps generated code ↔ schema ↔ generator version. |
### `@skmtc/server` is the seed of the SaaS
`server/src/createServer.ts` is ~150 lines: a Hono app with
`POST /artifacts` (validate a discriminated body → convert →
`toArtifacts` → `{ artifacts, manifest }`), `GET /generators`, and
`POST /to-v3-json`. A production run service is this pattern with
auth, tenancy, persistence, and bundle management added around it.
The MCP host already calls a deployed instance of this server.
### Where the engine stops — build these at the platform layer
The engine deliberately does **schema in → artifacts out** and
nothing else. It has **no notion of**:
- **Users, identity, auth, multi-tenancy.** A SKMTC "project" is a
*generator configuration*, **not a tenant**. Tenancy is entirely
yours to build.
- **Persistence or run history.** `toArtifacts` returns a value; the
on-disk `manifest.json` is overwritten every run.
- **Result caching.** Determinism makes this safe and easy — cache
`{ artifacts, manifest }` by a hash of `(schema, settings, bundle)`
— but it is *your* layer, never the engine's.
- **A warm execution pool, rate limiting, quotas, streaming.** Fact
5: one cold Worker per run. Pool at the *container/process* level
if you need throughput; never share a context across runs.
- **A plugin / hook API.** There isn't one and it is a rejected
design. Extension happens by cloning generators or by writing a
new host — not by hooking the engine.
## 12. Counter-intuitive facts for infrastructure builders
Beyond the five facts in §1. Left column = a reflex from generic
backend / platform training data; right column = SKMTC reality.
| Infra reflex | SKMTC reality |
|---|---|
| Keep a warm worker pool for throughput | One Worker per run, spawned cold, terminated after `RESULT`. Determinism depends on fresh contexts. Pool *containers*, not engine contexts. |
| Do incremental builds — only regenerate changed operations | There are none. Every run is whole-document and from cold. Cache the *whole result* by input hash instead. |
| Retry a failed run | Runs are deterministic — a retry reproduces the same failure exactly. Fix the input; don't retry. |
| Wrap `toArtifacts` in try/catch and 500 on throw | It fails *open* — a bad schema logs a `ParseIssue`, it does not throw. Derive status from `manifest.parseIssues`, not from exceptions. |
| Stream artifacts for large outputs | The Worker batch-`postMessage`s the whole result. No streaming protocol; structured clone handles typical sizes. |
| Format the output before returning it | Output is unformatted *by design*. Formatting is the consumer's separate step. |
| Let generators fetch schemas / templates at run time | The Worker has `net: false`. Everything a generator needs must already be in its inputs. Fetching is host-side, pre-engine. |
| The on-disk `manifest.json` is the run record | It is overwritten every run. Persist each manifest yourself for history. |
| Add an engine plugin/hook API for the platform | Rejected design. Extend by cloning generators or adding a host. |
| A "project" is a tenant / a customer | A project is a *generator configuration*. It is not a unit of tenancy, identity, or billing. |
| Generated code needs the SKMTC runtime at deploy time | Zero runtime. Output is plain committed source; the engine never ships to the consumer's bundle. |
## 13. Boundaries with other skills
- **skmtc-generator** — authoring and editing generators (Projections,
Snippets, the DSL, customization seams). Load when *writing
generator code*.
- **skmtc-cli** — running the CLI, configuring `client.json`,
enrichments, skip/include. Load when *operating* SKMTC.
- **skmtc-debug** — diagnosing broken runs (no output, wrong output,
errors). Verify-first stance. Load when *something is broken*.
- **skmtc-retro** — end-of-session reflection / friction capture.
- **This skill (skmtc-architecture)** — the system mental model for
reasoning about and building infrastructure *around* the engine.
If the question is *how the system works* or *how to build a service
around it*, this skill. If it is *how to write a generator*, *how to
run a command*, or *why a run is broken*, hand off.
## 14. Cross-references
**Concepts** —
[`the-three-phases.md`](../../concepts/the-three-phases.md) ·
[`the-worker-runtime.md`](../../concepts/the-worker-runtime.md) ·
[`the-manifest.md`](../../concepts/the-manifest.md) ·
[`the-stack-trail.md`](../../concepts/the-stack-trail.md) ·
[`cross-generator-coordination.md`](../../concepts/cross-generator-coordination.md) ·
[`generators-as-packages.md`](../../concepts/generators-as-packages.md) ·
[`attribution-and-gen-maps.md`](../../concepts/attribution-and-gen-maps.md)
**Explanation** —
[`design-philosophy.md`](../../explanation/design-philosophy.md) ·
[`security-model.md`](../../explanation/security-model.md) ·
[`comparison-to-other-tools.md`](../../explanation/comparison-to-other-tools.md) ·
[`status-and-roadmap.md`](../../explanation/status-and-roadmap.md)
**Reference** —
[`glossary.md`](../../reference/glossary.md) ·
[`manifest-format.md`](../../reference/manifest-format.md) ·
[`llms.md`](../../llms.md) (consolidated operational reference)
**Source landmarks** — `core/run/toArtifacts.ts` (engine entry) ·
`worker/mod.ts` (Worker host) · `server/src/createServer.ts` (HTTP
host) · `core/context/` (the three context classes) · `core/anchors/`
(attribution / gen-maps).