Compile your software system
from a definition.
Declare your services, dependencies and ownership once. Rhodd validates the graph, plans every write, runs quality gates, and emits a locked, reproducible baseline — with the ownership boundaries and handoff context humans and AI need to continue safely.
From two services to a dozen — same compiler, same .rhodd/ state.
version: "0.1"
project:
name: fullstack-saas
description: Frontend, backend, a Go service, database, worker, adapters, Docker, and Kubernetes.
preset:
kind: fullstack-saas
quality: production-baseline
frontend:
framework: react
language: typescript
bundler: vite
validation: zod
componentLibrary: radix
state:
client: zustand
server: tanstack-query
backend:
language: typescript
framework: nest
transport: rest
orm: prisma
modules:
- name: postgres
- name: redis
services:
- name: web
kind: app
runtime: react-ts-zod
language: typescript
port: 5173
exposure: cluster
dependencies: [api]
consumes: [http]
env: { VITE_API_BASE_URL: http://api:3000 }
- name: api
kind: app
runtime: node-nest
language: typescript
port: 3000
replicas: 2
exposure: cluster
provides: [http]
dependencies: [postgres, redis]
consumes: [postgres, redis]
env: { DATABASE_HOST: postgres, CACHE_HOST: redis }
- name: audit
kind: app
runtime: go-http
port: 8081
exposure: cluster
provides: [http]
dependencies: [api]
consumes: [http]
env: { API_BASE_URL: http://api:3000 }
- name: jobs
kind: app
runtime: node-worker
language: typescript
port: 9100
exposure: none
dependencies: [api, postgres, redis]
consumes: [http, postgres, redis]
env: { QUEUE_NAME: billing-jobs }
database:
provider: postgres
orm: prisma
targets:
- { name: frontend-react }
- { name: backend-node-nest }
- { name: backend-go-rest }
- { name: prisma-db }
- { name: workers-node }
- { name: docker-compose }
- { name: kubernetes }
- { name: full-project }
infrastructure:
compose: true
kubernetes: true
docs: true
tests: trueA compiler keeps what a copy throws away.
A system, not a folder
A template copies a starting point and forgets it. Rhodd preserves the system around your code — model, graph, plan, lock, ownership and handoff — as machine-readable state.
Compiled, not prompted
AI builders generate from prompts and hope. Rhodd compiles from an explicit definition: same input, same output. Rhodd works without AI — AI becomes safer when Rhodd gives it explicit state.
A lifecycle, not one-shot
A scaffold stops at the first copy. Rhodd keeps the graph, plan and lock so every later change is recalculated against the system — not pasted over it.
Definition in, baseline out
Nine stages run locally and deterministically. Four of them — model, quality, ownership, handoff — are where a compiler does what a template never could.
Your system, drawn
Rhodd reads your spec, resolves a typed acyclic graph, compiles it in stages, and holds the contracts between services — all as inspectable state.
- Root: rhodd.yaml — one spec.
- Service group api (Nest · TypeScript) — generates: HTTP server · main.ts · app.module; security · api-key guard · auth; DB connector · Prisma service · repository; validation · filters · health; modules: users · auth · billing.
- Service group audit (Go · http) — generates: main.go · handler; service · http_client adapter; config · handler_test.
- Service group jobs (Node · worker) — generates: worker · queue (bullmq); processors: billing; http · prisma adapters · logger.
- Service group web (React · Vite) — generates: App · routes · pages; api client · dtos · schemas; components · ui · features; store · hooks · providers.
- Output group system (infra outputs) — generates: docker-compose.yml; k8s/ manifests · k8s-plan; prisma schema · .env.d · docs.
- Output group .rhodd/ (state + handoff) — generates: graph · model · plan · manifest; ownership · quality · lock; ai/ handoff · context · prompts · tasks.
- One spec generates four services with per-runtime layers, system infrastructure, and Rhodd's own state. 228 files, acyclic.
One spec compiles into real, per-runtime code — Nest, Go, a worker, React — plus system infra and Rhodd's own state. 228 files, acyclic.
- Phase 1 understand: stages validate · model · graph. Emits model.json, graph.json.
- Phase 2 build: stages plan · generate · dep-waves. Emits generation-plan, target-matrix, project tree, generated-manifest.
- Phase 3 prove & hand off: stages quality · lock · ownership · handoff. Emits quality.json, lock.json, ownership.json, .rhodd/ai/*.
- Every phase leaves inspectable evidence — the same files in the Files tab.
Understand the system → build it in dependency order → prove it and hand off. Every phase leaves inspectable evidence — the same files in the Files tab.
Illustrative multi-repo system — the single-repo flagship run above emits no system-level artifacts. This is the anatomy of one typed contract: a producer owns the schema; consumers, across repos, depend on it.
- Producer: api in repo processing-platform provides http.
- Typed contract: processing-api (openapi).
- Consumer: web in repo web-platform (cross-repo) consumes http.
- Consumer: audit in repo processing-platform (same repo) consumes http.
- Consumer: jobs in repo processing-platform (same repo) consumes http.
- Declared compatibility policy: a breaking change is blocked; a missing producer is blocked; a missing consumer binding warns.
- Illustrative multi-repo system — the single-repo flagship run emits no system-level artifacts.
One typed contract — one producer owns the schema, consumers depend on it, across repos — and Rhodd's compatibility policy blocks breaking changes.
Every generation leaves a replayable record. These are stripped for readability — the full, untrimmed versions are in the files panel below.
{
"schema_version": "rhodd.full_project.graph.v1",
"system_name": "fullstack-saas",
"nodes": [
{ "name": "web", "kind": "app", "runtime": "react-ts-zod", "provides": ["http"], "consumes": ["http"] },
{ "name": "api", "kind": "app", "runtime": "node-nest", "provides": ["http"], "consumes": ["postgres", "redis"] },
{ "name": "audit", "kind": "app", "runtime": "go-http", "provides": ["http"], "consumes": ["http"] },
{ "name": "jobs", "kind": "app", "runtime": "node-worker", "provides": ["worker"], "consumes": ["http", "postgres", "redis"] },
{ "name": "postgres", "kind": "infra", "runtime": "postgres", "provides": ["postgres"] },
{ "name": "redis", "kind": "infra", "runtime": "redis", "provides": ["redis"] }
],
"edges": [
{ "dependent": "api", "dependency": "postgres" },
{ "dependent": "api", "dependency": "redis" },
{ "dependent": "audit", "dependency": "api" },
{ "dependent": "jobs", "dependency": "api" },
{ "dependent": "jobs", "dependency": "postgres" },
{ "dependent": "jobs", "dependency": "redis" },
{ "dependent": "web", "dependency": "api" }
],
"topological_order": ["postgres", "redis", "api", "audit", "jobs", "web"],
"entities": [
{ "name": "User", "owner": "services/api/src/modules/users" },
{ "name": "Session", "owner": "services/api/src/modules/auth" },
{ "name": "BillingAccount", "owner": "services/api/src/modules/billing" },
{ "name": "AuditEvent", "owner": "services/audit" },
{ "name": "JobRun", "owner": "services/jobs" }
]
}{
"system_name": "fullstack-saas",
"target": "full-project",
"generationIntent": "greenfield",
"inputs": ["docker-compose", "envfiles", "kubernetes-plan", "spec-backed-artifacts", "metadata", "ai-handoff"],
"outputs": [
{ "path": ".env.d/api.env", "sha256": "15b77821ca910b64b0e63365b059e275cdc50c3bc53c6c7804a22777694b4af0", "ownership": "generated-only", "origin": "required-glue" },
{ "path": ".env.d/web.env", "sha256": "eefa6c309d8a400eb284e514a07c900865db9032a01b8999df401db5ae48783f", "ownership": "generated-only", "origin": "required-glue" },
{ "path": "README.md", "sha256": "cd2e13e769b0b00f0275e92cfdcc3f887521f955f5739c31c58165c1f5e2cf68", "ownership": "generated-only", "origin": "required-glue" },
{ "path": "config/integrations.json", "sha256": "b38218fb03b8d6320ff1235d4f1f8d849d8398b10cb6f9fbbc6461ee778db142", "ownership": "generated-only", "origin": "policy-scaffold" },
{ "path": "config/rhodd.local.yaml", "sha256": "0c0fed1a874b2298dc35a6503b89339b27b5207902b51100392fc48a81278469", "ownership": "scaffold-once", "origin": "required-glue" }
],
"_more": "…222 more · 227 outputs total",
"safety": [
"writes only under explicit --out",
"guarded apply uses generated manifest and refuses user-owned overwrites",
"kubernetes apply requires --dry-run or --confirm",
"providers run only through explicit provider run gates"
]
}{
"system_name": "fullstack-saas",
"target": "full-project",
"file_count": 227,
"files": [
{ "path": ".env.d/api.env", "sha256": "15b77821ca910b64b0e63365b059e275cdc50c3bc53c6c7804a22777694b4af0", "ownership": "generated-only", "apply_policy": "create-or-update", "origin": "required-glue" },
{ "path": ".rhodd/ai/context.md", "sha256": "11d5eed17cd28a2329170cddc381eba4908ea4d4acc6ac4ec71154ab2475f738", "ownership": "generated-only", "apply_policy": "create-or-update", "origin": "required-glue" },
{ "path": ".rhodd/ai/graph.json", "sha256": "6b09ef87cc0a2561b1ce3291cbdaf1e0c6d7483c36479c26565cd74bb3b6deaa", "ownership": "generated-only", "apply_policy": "create-or-update", "origin": "required-glue" },
{ "path": "config/integrations.json", "sha256": "b38218fb03b8d6320ff1235d4f1f8d849d8398b10cb6f9fbbc6461ee778db142", "ownership": "generated-only", "apply_policy": "create-or-update", "origin": "policy-scaffold" },
{ "path": "config/rhodd.local.yaml", "sha256": "0c0fed1a874b2298dc35a6503b89339b27b5207902b51100392fc48a81278469", "ownership": "scaffold-once", "apply_policy": "create-if-absent", "origin": "required-glue" }
],
"_more": "…222 more · 227 files (226 generated-only + 1 scaffold-once)"
}{
"schema_version": "rhodd.full_project.ownership.v1",
"system_name": "fullstack-saas",
"classes": [
{ "name": "generated-only", "description": "Rhodd may create or update through generated manifest and guarded apply.", "apply_policy": "create-or-update" },
{ "name": "scaffold-once", "description": "Rhodd creates the file when absent, then preserves existing destination content.", "apply_policy": "create-if-absent" },
{ "name": "managed-with-regions", "description": "Rhodd may update generated structure while preserving protected user-editable regions.", "apply_policy": "create-or-update" },
{ "name": "user-owned", "description": "Files outside generated ownership evidence are not overwritten by guarded apply.", "apply_policy": "refuse-overwrite" },
{ "name": "metadata-only", "description": "Inspectable state used for explainability and gates; repo apply records it but skips writes.", "apply_policy": "metadata-only" }
],
"rules": [
"Generated manifest records are the source of truth for guarded apply eligibility.",
"Secret values are never emitted; generated env, compose, Kubernetes, and AI files use keys or redacted templates.",
"Provider, Docker Compose, and live Kubernetes execution require explicit user gates outside generation."
],
"boundaries": [
{ "path_prefix": "services/", "owner": "rhodd", "class": "generated-only", "apply_policy": "create-or-update" },
{ "path_prefix": "database/", "owner": "rhodd", "class": "generated-only", "apply_policy": "create-or-update" },
{ "path_prefix": "k8s/", "owner": "rhodd", "class": "generated-only", "apply_policy": "create-or-update" },
{ "path_prefix": ".rhodd/", "owner": "rhodd", "class": "generated-only", "apply_policy": "create-or-update" },
{ "path_prefix": "config/rhodd.local.yaml", "owner": "user-after-first-apply", "class": "scaffold-once", "apply_policy": "create-if-absent" },
{ "path_prefix": "k8s-plan.json", "owner": "rhodd", "class": "metadata-only", "apply_policy": "metadata-only" },
{ "path_prefix": "unlisted files", "owner": "user", "class": "user-owned", "apply_policy": "refuse-overwrite" }
]
}{
"schema_version": "rhodd.generated_project_quality.v1",
"system_name": "fullstack-saas",
"checks": [
{ "name": "frontend-tree", "status": "pass" },
{ "name": "backend-tree", "status": "pass" },
{ "name": "db-prisma-tree", "status": "pass" },
{ "name": "worker-tree", "status": "pass" },
{ "name": "ai-handoff", "status": "pass" },
{ "name": "duplicate-paths", "status": "pass" },
{ "name": "typescript-double-extension", "status": "pass" },
{ "name": "manifest-completeness", "status": "pass" }
]
}{
"schema_version": "rhodd.full_project.lock.v1",
"system_name": "fullstack-saas",
"target": "full-project",
"graph_sha256": "6b09ef87cc0a2561b1ce3291cbdaf1e0c6d7483c36479c26565cd74bb3b6deaa",
"model_sha256": "85e201b6559a46d0e37394927e39a5336f05862445033249ec25ae2b47c20570",
"generation_plan_sha256": "15c261ccaa9efe98c4bcaba7c915ce03099cb99ad8d84cbdb870a12e6fccd97a",
"generated_file_count": 130,
"message": "deterministic full-project lock over graph, model, generation plan, and generated file count"
}Rhodd works without AI. AI becomes safer when Rhodd gives it explicit state. The handoff is a bounded consumer of compiled state — never the generator. It is lint-checked with secrets redacted, and providers never run by default (skipped unless you pass --include provider).
# Rhodd handoff — for humans and AI
Read order: context → model → graph → generation-plan → ownership → target-matrix
This system was compiled deterministically. Treat the artifacts under `.rhodd/`
as ground truth. Rhodd works without AI; AI becomes safer when it reads this
explicit state instead of guessing.
.rhodd/ai/
context.md system shape + read order (this file)
prompts/ task-scoped prompts, ready to paste
tasks/ bounded, checkable units of work
graph.json services, modules, edges (acyclic)
model.json the resolved system
generation-plan.json the write set (dry-run clean)
ownership.md generated vs user-owned paths
target-matrix.md targets → emitted files
Safety (code-enforced): the handoff is lint-checked and secrets are redacted —
the linter errors on api_key / token / secret / password patterns and never
prints the value. Providers (openai, anthropic, gemini) never run by default;
they are skipped unless you pass `--include provider`, and the run records
"no provider call was made". A deterministic local `fake` provider is available
for offline validation.# install the rhodd compiler (Go binary — no npm)
sh install.sh --version v0.1.0-rc.1
# or
go install github.com/rhodd-fdn/rhodd-core/cmd/rhodd@v0.1.0-rc.1Define the system once.
Compile the baseline.
A deterministic system architecture compiler for declarative software systems. Local-first, reproducible, and inspectable — install the CLI and compile your first baseline.