service.json Becomes a Full Local Stack
Most multi-service setups still force you to maintain Docker Compose files, Tiltfiles, nginx configs, port maps, and health checks by hand. AI coding agents make the application code easy, but they are still bad at keeping the local infrastructure consistent.
TDK CLI solves this by treating a tiny declarative file as the source of truth and generating everything else.
This is essentially all you write for a service:
{
"$schema": "https://tdk-landscape.github.io/schema.service.json",
"schemaVersion": 1,
"appName": "orders-api",
"appType": "backend",
"stack": "shop",
"port": 4000,
"healthCheckPath": "/health",
"dependsOn": []
}
From this single file, TDK generates Dockerfiles, live-reload rules, Traefik routes, shared Postgres wiring, health probes, and the Tilt configuration that actually runs it.
The project is organized as Project → Stack → Resource.
flowchart LR
P[Project<br/>.tdk/project.json] --> S1[Stack: shop]
P --> S2[Stack: billing]
S1 --> R1[orders-api<br/>backend]
S1 --> R2[orders-app<br/>frontend]
S2 --> R3[checkout-api<br/>backend]
The codebase is deliberately split so each part has a clear job:
flowchart TB
subgraph CLI["cli/ (TypeScript)"]
Commands[Commands & validation]
Templates[Handlebars templates]
Ports[Port allocation]
end
subgraph Discovery["discovery/ (Starlark)"]
Scan[Scan service.json]
DAG[Build dependency DAG]
end
subgraph Engine["engine/ (Starlark)"]
LiveUpdate[live_update rules]
Traefik[Traefik routing]
Infra[Postgres + platform]
end
CLI -->|generates Tiltfile + configs| Discovery
Discovery -->|registry + DAG| Engine
Engine -->|docker_build + containers| Docker[(Docker)]
| Subsystem | Language | Responsibility |
|---|---|---|
cli/ |
TypeScript | Commands, validation, port allocation, template generation, launching Tilt |
discovery/ |
Starlark | Scan for service.json files, normalize them, build the dependency DAG |
engine/ |
Starlark | Runs inside Tilt — turns the DAG into realdocker_build ,live_update , Traefik, Postgres, etc. |
The CLI never starts containers itself. The engine never parses CLI flags. Discovery never builds images.
The real glue is the template engine (cli/src/generator/template-engine.ts). It reads .tdk/project.json and emits files into the gitignored .tdk/.tdk-out/ directory:
Tiltfile`` TILT_TECH_STACK.star and TILT_RESOURCE_DEFAULTS.star
spec.master``.tiltignore
These come from Handlebars templates. The CLI also vendors a copy of the engine and discovery code so tdk up works offline.
tdk up
sequenceDiagram
actor Dev
participant CLI as TDK CLI
participant Gen as Template Engine
participant Tilt
participant Engine as Starlark Engine
participant Docker
Dev->>CLI: tdk up shop
CLI->>CLI: Preflight (Docker, schema, drift, ports)
CLI->>Gen: Ensure master configs
Gen-->>CLI: .tdk/.tdk-out/Tiltfile
CLI->>Tilt: tilt up -f Tiltfile -- --focus=shop
Tilt->>Engine: Load discovery + engine
Engine->>Engine: Scan service.json → DAG
Engine->>Docker: docker_build + live_update
Engine->>Docker: Start Traefik + Postgres
Docker-->>Tilt: Containers healthy
Tilt-->>CLI: Ready
CLI-->>Dev: Print URLs + Tilt UI
High-level steps:
pre_alpha phase.tilt up against the generated Tiltfile..autogenerated/ files, registers builds with live-update, and starts shared infrastructure.
TDK is strict about this boundary so AI agents (and humans) cannot silently break the infrastructure:
flowchart LR
subgraph Committed["Committed (source of truth)"]
PJ[.tdk/project.json]
SJ[services/*/*/service.json]
Code[Your app source]
end
subgraph Generated["Generated (gitignored)"]
Out[.tdk/.tdk-out/<br/>Tiltfile, specs]
Auto[services/*/*/.autogenerated/]
Env[.env]
end
Committed -->|tdk project / tdk resource / tdk up| Generated
Generated -->|tdk config regenerate| Committed
| Path | Status | Why |
|---|---|---|
.tdk/project.json |
Committed | Project identity and phases |
services/*/*/service.json |
Committed | Service contract |
| Application source | Committed | Your code |
.tdk/.tdk-out/ |
Generated | Derived from templates |
services/*/*/.autogenerated/ |
Generated | Engine output during Tilt |
.env |
Generated | Local secrets |
TDK is a local development runtime. It does not deploy to staging or production. The project explicitly leaves production to Helm, Argo CD, or whatever you already use. The local environment is optimized for speed and developer experience, not for being a perfect replica of production.
npm install -g @tdk-landscape/tdk-cli-core
tdk doctor
tdk project --yes
tdk resource orders-api --type backend --stack shop --yes
tdk up shop
Or clone the official starter and open it in any cloud IDE.