Schema Reference
https://raw.githubusercontent.com/FoundryMedia/foundry/release/foundry.schema.jsonDeclarative manifest for a Foundry-managed platform. Defines WHAT the platform is — its topology, services, databases, and CI/CD configuration.
Required Fields
schemaVersionnameservices
Definitions
foundryConfig
Foundry CLI metadata. Allows manifests to declare minimum CLI version requirements.
| Property | Type | Description |
|---|---|---|
minCliVersion | string | Minimum Foundry CLI version required to work with this manifest. |
templateConfig
Records which template was used to generate this platform. Informational — the CLI does not enforce template constraints after init.
| Property | Type | Description |
|---|---|---|
name | string | Template identifier (e.g., 'tfw', 'minimal'). |
version | string | Version of the template that was used. |
generatedAt | string | ISO-8601 timestamp of when the platform was generated. |
githubConfig
GitHub organization and cross-repo configuration. Replaces 'ecosystemConfig' in v0.4.0 — focused on GitHub-specific concerns (org, repos).
| Property | Type | Description |
|---|---|---|
organization | string | GitHub organization that owns all platform repositories. |
repositories | object | Map of related repositories in the ecosystem. Keys are logical names, values describe the repo and its relationship. |
apiLib | #/definitions/apiLibConfig | The API library repository — contract-first source of truth for API specs, generated code, and shared models. |
structureConfig
Directory layout overrides. Foundry enforces a canonical structure (apps/backend, apps/frontend, ci/db, ci/scripts, ci/iac, packages/) but allows the top-level directory names to be customized.
| Property | Type | Description |
|---|---|---|
appsDir | string | Directory containing backend/ and frontend/ service directories (default: 'apps'). |
ciDir | string | Directory containing db/, scripts/, and iac/ (default: 'ci'). |
packagesDir | string | Directory containing shared workspace packages (default: 'packages'). |
ecosystemConfig
Describes the broader platform ecosystem — the GitHub organization, related repositories, shared libraries, and cross-cutting concerns. Only the primary platform repo has a foundry.json — satellite repos are referenced here.
| Property | Type | Description |
|---|---|---|
organization | string | GitHub organization that owns all platform repositories. Required — this is the anchor for cross-repo discovery and artifact registry scoping. |
prefix | string | Short prefix derived from the first letter of each word in the platform name (e.g., 'Acme Cloud Platform' → 'acp'). Used to discover satellite repos matching '{prefix}-*'. Auto-derived if not set; must be at least 2 characters. |
repositories | object | Map of related repositories in the ecosystem. Keys are logical names, values describe the repo and its relationship. |
apiLib | #/definitions/apiLibConfig | The API library repository — the contract-first source of truth for API specs, generated code, and shared models. |
repositoryReference
A reference to a related repository within the platform ecosystem.
| Property | Type | Description |
|---|---|---|
repository | string | Repository name within the organization (e.g., 'acp-api-lib'). |
relationship | — | How this repo relates to the current repo. |
apiLibConfig
Configuration for the platform's API library repository.
| Property | Type | Description |
|---|---|---|
repository | string | Repository name (e.g., 'acp-api-lib'). |
packageRegistry | string | Where the api-lib packages are published. |
groupId | string | Maven groupId or npm scope for published packages. |
packagesSecret | string | Name of the GitHub Actions secret containing a PAT with read:packages scope for cross-repo access. |
modules | object | Map of logical module names to their artifact coordinates. |
apiLibModuleConfig
A single module within the api-lib repository.
| Property | Type | Description |
|---|---|---|
artifactId | string | Published artifact name. |
version | string | Current published version of this module. |
specPath | string | Relative path (within the module) to the OpenAPI spec file. |
databaseConfig
Configuration for a database schema managed by this platform.
| Property | Type | Description |
|---|---|---|
engine | string | Database engine. |
schema | string | Default schema name (primarily for PostgreSQL). |
changelog | string | Relative path to the Liquibase master changelog file. |
properties | string | Relative path to the Liquibase connection properties file. |
credentials | object | Database credential resolution configuration. |
environmentConfig
A named environment: a Git-branch mapping for CI, and/or dev-run overlays consumed by 'foundry run dev --env <name>'. An environment without 'branch' is dev-only — invisible to the CI generators.
| Property | Type | Description |
|---|---|---|
branch | string | Git branch name that triggers deployment to this environment. Required for CI environments; omit for a dev-only overlay environment. |
enabled | boolean | Whether this environment is active. Disabled environments are excluded from pipeline triggers and deployment. Default: true. |
autoApprove | boolean | Whether deployments to this environment require manual approval. Default: false (require approval). |
iac | object | Infrastructure-specific configuration for this environment. Contains provider-specific details (AWS region, account, domain, global resources like lambdas and bastion). Supports {name_prefix}, {prefix}, {env} template variables resolved at generation time. |
run | object | Dev-run overlay: shallow-merged over the service's base run block when this environment is selected (port/actuatorPort/script/args replace; run.env layers in). Read only by 'foundry run dev'. |
env | object | Dev-run overlay: env vars layered into the service's environment when this environment is selected. |
sshTunnels | object | Dev-run overlay: merged BY TUNNEL NAME over the service's tunnels — an existing name field-merges (only the given keys change), a new name is a full tunnel config, null removes the tunnel. Give each environment distinct localPorts so environments can run side by side. |
deployConfig
Deployment configuration. In v0.5.0, this is a mandatory block for deployable services (strategy is required). The convention engine derives defaults for other fields from stack + scope.
| Property | Type | Description |
|---|---|---|
strategy | — | How this service is deployed — the single selector the orchestrator dispatches on (absorbs the former foundry-ops 'kind'). 'service' = containerized (ECS Fargate), 'static' = S3/CDN static hosting (SPA/site), 'desktop' = Tauri desktop release (signed installers + updater manifest), 'game-publisher' = UE5 game build/publish, 'none' = not deployed (libraries/packages). |
dockerfile | string | Path to Dockerfile relative to repo root. Convention: apps/{kind}/{name}/Dockerfile. |
buildContext | string | Docker build context relative to repo root. Convention: '.' for monorepo (Spring Boot), service dir for standalone (Python). |
buildCommand | string | Build command for non-Docker builds (static sites). Convention: derived from type (e.g., 'pnpm build' for nextjs/vite). |
secrets | array | Secrets to fetch from Secrets Manager before build/deploy. Convention: derived from type (microlith-spring-properties for Spring Boot, {name}-env for others). |
compute | #/definitions/computeConfig | Compute resources for the main container. IAC secret values override these if present. |
cdn | — | CDN (CloudFront) configuration. true = auto (read distribution ID from IaC outputs), false = none, object = custom config. Convention: true for s3-static, true for nextjs ECS, false for backend. |
dependsOn | array | Services or phases that must complete before this service deploys. Convention: all services depend on 'iac'; services with databases depend on 'database:{db-name}'; services with sidecars get 'sidecar:{name}' dependencies. |
sidecars | object | Sidecar containers deployed alongside this service in ECS. Convention: derived from role (e.g., auth → OpenFGA sidecar). |
iac | object | Infrastructure-specific deployment configuration for this service. Contains provider-specific details (compute, ALB, security groups, IAM policies, database, sidecars). Passed through to the tfvars generator. Supports {name_prefix}, {iac_name}, {manifest_name}, {prefix}, {env} template variables. |
secretMapping
Maps a secret from Secrets Manager to a file in the build context. Supports interpolation: {prefix}, {env}, {service}.
| Property | Type | Description |
|---|---|---|
source | string | Secrets Manager secret name. Supports interpolation: {prefix}-{env}/microlith-spring-properties. |
target | string | Where to write the secret value. Relative path from repo root. Supports interpolation: apps/backend/{service}/src/main/resources/application-{env}.yml. |
format | — | How to process the secret value before writing. 'raw' = write as-is, 'dotenv' = parse as dotenv, 'extract-key' = extract a specific key from JSON. |
extractKey | string | When format is 'extract-key', the JSON key to extract from the secret value. |
cdnConfig
CDN configuration for static or frontend deployments. When specified as an object, allows customizing CDN behavior beyond the auto-detected defaults.
| Property | Type | Description |
|---|---|---|
distributionIdOutput | string | JSON path within iac-outputs.json to find the CloudFront distribution ID. Convention: derived from service name and IaC output structure. |
invalidationPaths | array | Paths to invalidate in CloudFront after deployment. Default: ['/*']. |
sidecarDeployConfig
Configuration for a sidecar container deployed alongside a service in ECS.
| Property | Type | Description |
|---|---|---|
image | string | Docker image for the sidecar (e.g., 'openpolicyagent/opa:latest-static'). |
port | integer | Container port for the sidecar. |
cpu | integer | CPU units for the sidecar container. Default: 128. |
memory | integer | Memory (MiB) for the sidecar container. Default: 256. |
essential | boolean | Whether the task should stop if this sidecar dies. Default: false. |
command | array | Command override for the sidecar container. |
environment | object | Environment variables for the sidecar container. |
healthCheck | #/definitions/containerHealthCheck | ECS container health check configuration. |
containerHealthCheck
ECS container health check configuration.
| Property | Type | Description |
|---|---|---|
command | string | Shell command to run for health check (will be wrapped in CMD-SHELL). |
interval | integer | Seconds between health checks. Default: 30. |
timeout | integer | Seconds before health check times out. Default: 5. |
retries | integer | Number of retries before marking unhealthy. Default: 3. |
startPeriod | integer | Grace period (seconds) before health checks start. Default: 60. |
computeConfig
Compute resource allocation for a container. CPU units follow AWS ECS conventions (1024 = 1 vCPU). Memory is in MiB.
| Property | Type | Description |
|---|---|---|
cpu | integer | CPU units for the container. 256 = 0.25 vCPU, 512 = 0.5 vCPU, 1024 = 1 vCPU, 2048 = 2 vCPU, 4096 = 4 vCPU. |
memory | integer | Memory (MiB) for the container. Must be compatible with CPU allocation per AWS Fargate limits. |
serviceConfig
Declaration of a single service or package in the platform. v0.5.0 groups concerns into structured blocks: scope (visibility), stack (technology), deploy (shipping), run (local dev).
| Property | Type | Description |
|---|---|---|
scope | — | Visibility scope of the service: 'public' (internet-facing) or 'internal' (private/platform-only). |
repository | string | Multi-repo (v0.7.0): the GitHub 'owner/repo' this service lives in. Omit for a service that lives in the same repo as the manifest (monorepo). |
path | string | Multi-repo (v0.7.0): the service's path within its repository. Omit or '.' = repo root (multi-repo); a subdir (e.g. 'apps/backend/x') = monorepo layout. |
environments | object | Multi-repo (v0.7.0): per-service override of the platform-wide ci.environments (env→branch). Lets services living in repos with different branch models deploy from different branches. Falls back to ci.environments when an env is omitted here. |
stack | #/definitions/stackConfig | Technology stack of the service — what it's built with. |
deploy | #/definitions/deployConfig | How the service is deployed. Mandatory for deployable services. Packages (stack.type='package') don't need this. |
run | #/definitions/runConfig | How the service behaves with 'foundry run'. Defines ports, arguments, health checks, and environment variables for local development. |
enabled | boolean | Whether the service participates in 'foundry run'. Disabled services stay declared but are not started. |
sshTunnel | #/definitions/sshTunnelConfig | LEGACY single SSH tunnel opened before the service starts in prod-target dev. Keeps the implicit DB_HOST/DB_PORT + default-credentials injection. Prefer 'sshTunnels' for new services; declaring both is an error. |
sshTunnels | object | Named SSH tunnels opened (in parallel, all-or-nothing) before the service starts in prod-target dev. Keys are tunnel names (label logs and config.yml/env overrides). Map entries inject ONLY what they declare via 'env'/'injectEnv' — no implicit DB_* injection. The entry named 'db' (or the sole entry with a credentialsSecret) is treated as the database tunnel by 'foundry db' and the migration wrapper. |
sidecars | object | Local sidecar processes started alongside the service by 'foundry run' (e.g. OpenFGA, Redis). Keys are sidecar names. |
devProdGuard | object | Env vars injected ONLY when the service runs locally against the prod target — safety overrides (e.g. disabling schedulers) that must never apply in real deployments. |
database | — | Database this service uses. An inline config object (engine, changelog, properties) or a string referencing a key in the top-level 'databases' map (deprecated). |
kind | — | [DEPRECATED in v0.5.0 — use stack.type instead] The stack category. |
type | string | [DEPRECATED in v0.5.0 — use stack.framework instead] The runtime/framework. |
role | string | [DEPRECATED in v0.5.0 — use scope instead] Semantic role of the service. |
strategy | string | [DEPRECATED in v0.5.0 — use deploy.strategy instead] How this service is deployed. |
stackConfig
Describes the technology stack of a service — what category it falls into, what framework it uses, and what language it's written in.
| Property | Type | Description |
|---|---|---|
type | — | The stack category. Must match the physical directory: 'backend' → apps/backend/<name>/, 'frontend' → apps/frontend/<name>/, 'package' → packages/<name>/. |
framework | — | The runtime/framework that determines how the service is built and started. |
language | — | Primary programming language of the service. |
runConfig
Local development runtime configuration — how the service behaves with 'foundry run'. Defines ports, arguments, health checks, and environment overrides.
| Property | Type | Description |
|---|---|---|
port | integer | Application port for local development. |
actuatorPort | integer | Actuator/health-check port for local development (Spring Boot). |
args | array | Startup arguments for local development (e.g., ['-Dspring-boot.run.profiles=local']). Args starting with -D are passed as Maven system properties; others as application arguments. |
env | object | Environment variables for local development. |
healthCheck | — | Health check endpoint for local development. Object form is what 'foundry run' consumes ({path, port?, expectedStatus?}); the bare-string form is legacy and ignored by the runner. |
script | string | Explicit start command for local development, overriding the framework's default runner. Spring Boot services run this VERBATIM (nothing injected or dropped; run.args are appended; 'debug'/'strictHealthPorts' injection is skipped with a warning). Node services (anything with a package.json): if the value names a package.json script it runs via the package manager (`npm run <name>`); otherwise it is run VERBATIM from the service directory with node_modules/.bin on PATH (e.g. "nx serve enterprise"). A service with no detected runtime and no package.json runs it verbatim. A declared service is never silently skipped: without a runnable script it shows up FAILED with the reason. |
debug | — | Remote-debugger attachment for local development: a port number, or {port, suspend?} (JDWP for Java, --inspect for Node). |
strictMode | — | Strict-mode behavior for 'foundry run': a boolean, or {enabled?, strictHealthPorts?}. |
sshTunnelConfig
SSH port-forward opened before a service starts in prod-target local dev. String values support ${VAR} environment expansion.
| Property | Type | Description |
|---|---|---|
localPort | integer | Local port the tunnel listens on (what the service's DB config points at). |
remoteHost | string | Destination host as seen FROM the bastion (e.g. the private RDS endpoint). Supports ${VAR}. |
remotePort | integer | Destination port (e.g. 5432). |
host | string | Bastion host/IP to SSH through. Supports ${VAR}; when unset/unresolved, 'bastionTag' resolves it by EC2 Name tag. |
user | string | SSH user on the bastion. |
password | string | Path to the SSH private key file (relative paths resolve against the service's repo root). OPTIONAL: when omitted, authentication falls back to the SSH agent — the right choice for passphrase-encrypted keys, which are not supported as a file path (there is no passphrase field). Auto-fetched from 'keySecret' when missing. Keep it git-ignored — the CLI ensures an ignore entry when it writes the key. |
bindAddress | string | Local address the tunnel listens on. Default (omitted): loopback only — 127.0.0.1 plus a ::1 relay, so nothing on the network can reach the tunnelled service. Set "0.0.0.0" ONLY when something off-host must connect (e.g. a Docker container via host.docker.internal) — this exposes the tunnel to the local network and logs a warning. IPv4 only. |
bastionTag | string | EC2 tag:Name used to resolve the bastion's public IP when 'host' is unset or its ${VAR} is unresolved. |
keySecret | string | AWS Secrets Manager secret id holding the SSH key (JSON field 'private_key_pem'), fetched into 'password''s path when the file is missing. |
credentialsSecret | string | AWS Secrets Manager secret id with DB credentials injected as env into the service process (never written to disk). |
injectEnv | object | Override/extend the injected credential env-var mapping: ENV_VAR -> secret field (e.g. {"PGUSER": "username"}). Requires 'credentialsSecret'. |
env | object | Plain env vars this tunnel contributes to the service in prod-target dev, with ${localPort}/${localHost} placeholder expansion (e.g. {"AUTH_BASE_URL": "http://localhost:${localPort}"}). The explicit replacement for the legacy implicit DB_HOST/DB_PORT injection. |
awsRegion | string | Region for the bastion lookup and secret fetches. |
localSidecarConfig
A local sidecar process 'foundry run' starts alongside the service (e.g. OpenFGA, Redis via docker).
| Property | Type | Description |
|---|---|---|
command | string | |
args | array | |
cwd | string | Working directory, relative to the manifest directory. |
port | integer | |
env | object | |
enabled | boolean | |
healthPath | string | HTTP health endpoint (e.g. '/health') polled for readiness. |
readyPatterns | array | Log substrings indicating the sidecar is ready. |
Raw Schema
View full JSON schema
{
"$id": "https://raw.githubusercontent.com/FoundryMedia/foundry/release/foundry.schema.json",
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Foundry Platform Manifest",
"description": "Declarative manifest for a Foundry-managed platform. Defines WHAT the platform is — its topology, services, databases, and CI/CD configuration.",
"schemaVersion": "0.7.0",
"required": [
"schemaVersion",
"name",
"services"
],
"properties": {
"$schema": {
"description": "URI for the JSON Schema used to validate this manifest.",
"type": "string",
"format": "uri"
},
"schemaVersion": {
"description": "Version of the Foundry manifest specification.",
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+$"
},
"name": {
"description": "Human-readable name of the platform.",
"type": "string",
"minLength": 1
},
"repository": {
"description": "Name of the root repository folder for this platform (used by Foundry CLI).",
"type": "string",
"pattern": "^[a-z0-9-]+$"
},
"foundry": {
"description": "Foundry CLI metadata — minimum version requirements and tool-level config.",
"$ref": "#/definitions/foundryConfig"
},
"template": {
"description": "Records which template generated this manifest. Informational — not enforced after init.",
"$ref": "#/definitions/templateConfig"
},
"prefix": {
"description": "Short prefix derived from the platform name (e.g., 'Acme Cloud Platform' → 'acp'). Used for AWS resource naming, secret prefixes, and satellite repo discovery ('{prefix}-*'). Auto-derived from name if not set.",
"type": "string",
"pattern": "^[a-z0-9-]+$",
"minLength": 2
},
"structure": {
"description": "Enforced directory layout for the platform. Foundry requires a canonical structure: apps/{backend,frontend}, ci/{db,scripts,iac}, packages/. This block allows overriding the top-level directory names if needed, but the internal shape is fixed.",
"$ref": "#/definitions/structureConfig"
},
"github": {
"description": "GitHub organization and cross-repo configuration. v0.4.0 replacement for the 'ecosystem' block.",
"$ref": "#/definitions/githubConfig"
},
"ecosystem": {
"description": "[DEPRECATED in v0.4.0 — use 'github' instead] Cross-repository ecosystem topology.",
"$ref": "#/definitions/ecosystemConfig"
},
"databases": {
"description": "[DEPRECATED in v0.4.0 — declare inline per-service instead] Top-level database schemas. In v0.4.0, prefer declaring 'database' as an inline object within each service.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/databaseConfig"
}
},
"services": {
"description": "Service declarations for this platform. Keys are service directory names within apps/backend/, apps/frontend/, or packages/. Defines WHAT exists — runtime/launch configuration lives in .foundry/runtime.yml.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/serviceConfig"
}
},
"ci": {
"description": "Continuous Integration and infrastructure orchestration configuration.",
"type": "object",
"required": [
"iac",
"provider"
],
"properties": {
"iac": {
"description": "Tool used for infrastructure as code. OpenTofu is the recommended default — same HCL syntax and provider ecosystem as Terraform, but genuinely open source under MPL 2.0.",
"enum": [
"opentofu",
"terraform",
"pulumi",
"cloudformation",
"other"
]
},
"iacDir": {
"description": "Relative path to the IaC directory (default: 'ci/iac').",
"type": "string",
"default": "ci/iac"
},
"provider": {
"description": "Primary infrastructure provider for this platform.",
"enum": [
"aws",
"gcp",
"azure",
"other"
]
},
"pipeline": {
"description": "Relative path to the CI/CD pipeline definition (e.g., '.github/workflows/ci-cd-pipeline.yml').",
"type": "string"
},
"environments": {
"description": "Maps deployment environments to the Git branch that triggers them. Foundry CLI defaults: prod→release, dev→develop, test→qa.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/environmentConfig"
}
}
},
"additionalProperties": false
}
},
"definitions": {
"foundryConfig": {
"type": "object",
"description": "Foundry CLI metadata. Allows manifests to declare minimum CLI version requirements.",
"properties": {
"minCliVersion": {
"description": "Minimum Foundry CLI version required to work with this manifest.",
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?$"
}
},
"additionalProperties": false
},
"templateConfig": {
"type": "object",
"description": "Records which template was used to generate this platform. Informational — the CLI does not enforce template constraints after init.",
"properties": {
"name": {
"description": "Template identifier (e.g., 'tfw', 'minimal').",
"type": "string"
},
"version": {
"description": "Version of the template that was used.",
"type": "string"
},
"generatedAt": {
"description": "ISO-8601 timestamp of when the platform was generated.",
"type": "string",
"format": "date-time"
}
},
"additionalProperties": false
},
"githubConfig": {
"type": "object",
"description": "GitHub organization and cross-repo configuration. Replaces 'ecosystemConfig' in v0.4.0 — focused on GitHub-specific concerns (org, repos).",
"properties": {
"organization": {
"description": "GitHub organization that owns all platform repositories.",
"type": "string"
},
"repositories": {
"description": "Map of related repositories in the ecosystem. Keys are logical names, values describe the repo and its relationship.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/repositoryReference"
}
},
"apiLib": {
"description": "The API library repository — contract-first source of truth for API specs, generated code, and shared models.",
"$ref": "#/definitions/apiLibConfig"
}
},
"additionalProperties": false
},
"structureConfig": {
"type": "object",
"description": "Directory layout overrides. Foundry enforces a canonical structure (apps/backend, apps/frontend, ci/db, ci/scripts, ci/iac, packages/) but allows the top-level directory names to be customized.",
"properties": {
"appsDir": {
"description": "Directory containing backend/ and frontend/ service directories (default: 'apps').",
"type": "string",
"default": "apps"
},
"ciDir": {
"description": "Directory containing db/, scripts/, and iac/ (default: 'ci').",
"type": "string",
"default": "ci"
},
"packagesDir": {
"description": "Directory containing shared workspace packages (default: 'packages').",
"type": "string",
"default": "packages"
}
},
"additionalProperties": false
},
"ecosystemConfig": {
"type": "object",
"description": "Describes the broader platform ecosystem — the GitHub organization, related repositories, shared libraries, and cross-cutting concerns. Only the primary platform repo has a foundry.json — satellite repos are referenced here.",
"properties": {
"organization": {
"description": "GitHub organization that owns all platform repositories. Required — this is the anchor for cross-repo discovery and artifact registry scoping.",
"type": "string"
},
"prefix": {
"description": "Short prefix derived from the first letter of each word in the platform name (e.g., 'Acme Cloud Platform' → 'acp'). Used to discover satellite repos matching '{prefix}-*'. Auto-derived if not set; must be at least 2 characters.",
"type": "string",
"pattern": "^[a-z0-9-]+$",
"minLength": 2
},
"repositories": {
"description": "Map of related repositories in the ecosystem. Keys are logical names, values describe the repo and its relationship.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/repositoryReference"
}
},
"apiLib": {
"description": "The API library repository — the contract-first source of truth for API specs, generated code, and shared models.",
"$ref": "#/definitions/apiLibConfig"
}
},
"additionalProperties": false
},
"repositoryReference": {
"type": "object",
"description": "A reference to a related repository within the platform ecosystem.",
"required": [
"repository",
"relationship"
],
"properties": {
"repository": {
"description": "Repository name within the organization (e.g., 'acp-api-lib').",
"type": "string"
},
"relationship": {
"description": "How this repo relates to the current repo.",
"enum": [
"contracts",
"extracted-service",
"package",
"docs",
"infra",
"other"
]
}
},
"additionalProperties": false
},
"apiLibConfig": {
"type": "object",
"description": "Configuration for the platform's API library repository.",
"required": [
"repository"
],
"properties": {
"repository": {
"description": "Repository name (e.g., 'acp-api-lib').",
"type": "string"
},
"packageRegistry": {
"description": "Where the api-lib packages are published.",
"type": "string",
"enum": [
"github-packages",
"maven-central",
"npm",
"pypi"
]
},
"groupId": {
"description": "Maven groupId or npm scope for published packages.",
"type": "string"
},
"packagesSecret": {
"description": "Name of the GitHub Actions secret containing a PAT with read:packages scope for cross-repo access.",
"type": "string",
"default": "PACKAGES_READ_TOKEN"
},
"modules": {
"description": "Map of logical module names to their artifact coordinates.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/apiLibModuleConfig"
}
}
},
"additionalProperties": false
},
"apiLibModuleConfig": {
"type": "object",
"description": "A single module within the api-lib repository.",
"required": [
"artifactId",
"version"
],
"properties": {
"artifactId": {
"description": "Published artifact name.",
"type": "string"
},
"version": {
"description": "Current published version of this module.",
"type": "string",
"pattern": "^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?$"
},
"specPath": {
"description": "Relative path (within the module) to the OpenAPI spec file.",
"type": "string"
}
},
"additionalProperties": false
},
"databaseConfig": {
"type": "object",
"description": "Configuration for a database schema managed by this platform.",
"required": [
"engine",
"changelog"
],
"properties": {
"engine": {
"description": "Database engine.",
"type": "string",
"enum": [
"mariadb",
"postgresql",
"mysql",
"sqlite"
]
},
"schema": {
"description": "Default schema name (primarily for PostgreSQL).",
"type": "string"
},
"changelog": {
"description": "Relative path to the Liquibase master changelog file.",
"type": "string"
},
"properties": {
"description": "Relative path to the Liquibase connection properties file.",
"type": "string"
},
"credentials": {
"description": "Database credential resolution configuration.",
"type": "object",
"properties": {
"secretId": {
"description": "AWS Secrets Manager secret ID containing database credentials (JSON with engine, host, port, dbname, username, password).",
"type": "string"
}
},
"additionalProperties": false
}
},
"additionalProperties": false
},
"environmentConfig": {
"type": "object",
"description": "A named environment: a Git-branch mapping for CI, and/or dev-run overlays consumed by 'foundry run dev --env <name>'. An environment without 'branch' is dev-only — invisible to the CI generators.",
"properties": {
"branch": {
"description": "Git branch name that triggers deployment to this environment. Required for CI environments; omit for a dev-only overlay environment.",
"type": "string"
},
"enabled": {
"description": "Whether this environment is active. Disabled environments are excluded from pipeline triggers and deployment. Default: true.",
"type": "boolean",
"default": true
},
"autoApprove": {
"description": "Whether deployments to this environment require manual approval. Default: false (require approval).",
"type": "boolean",
"default": false
},
"iac": {
"description": "Infrastructure-specific configuration for this environment. Contains provider-specific details (AWS region, account, domain, global resources like lambdas and bastion). Supports {name_prefix}, {prefix}, {env} template variables resolved at generation time.",
"type": "object"
},
"run": {
"description": "Dev-run overlay: shallow-merged over the service's base run block when this environment is selected (port/actuatorPort/script/args replace; run.env layers in). Read only by 'foundry run dev'.",
"type": "object"
},
"env": {
"description": "Dev-run overlay: env vars layered into the service's environment when this environment is selected.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"sshTunnels": {
"description": "Dev-run overlay: merged BY TUNNEL NAME over the service's tunnels — an existing name field-merges (only the given keys change), a new name is a full tunnel config, null removes the tunnel. Give each environment distinct localPorts so environments can run side by side.",
"type": "object"
}
},
"additionalProperties": false
},
"deployConfig": {
"type": "object",
"description": "Deployment configuration. In v0.5.0, this is a mandatory block for deployable services (strategy is required). The convention engine derives defaults for other fields from stack + scope.",
"required": [
"strategy"
],
"properties": {
"strategy": {
"description": "How this service is deployed — the single selector the orchestrator dispatches on (absorbs the former foundry-ops 'kind'). 'service' = containerized (ECS Fargate), 'static' = S3/CDN static hosting (SPA/site), 'desktop' = Tauri desktop release (signed installers + updater manifest), 'game-publisher' = UE5 game build/publish, 'none' = not deployed (libraries/packages).",
"enum": [
"service",
"static",
"desktop",
"game-publisher",
"none"
]
},
"dockerfile": {
"description": "Path to Dockerfile relative to repo root. Convention: apps/{kind}/{name}/Dockerfile.",
"type": "string"
},
"buildContext": {
"description": "Docker build context relative to repo root. Convention: '.' for monorepo (Spring Boot), service dir for standalone (Python).",
"type": "string"
},
"buildCommand": {
"description": "Build command for non-Docker builds (static sites). Convention: derived from type (e.g., 'pnpm build' for nextjs/vite).",
"type": "string"
},
"secrets": {
"description": "Secrets to fetch from Secrets Manager before build/deploy. Convention: derived from type (microlith-spring-properties for Spring Boot, {name}-env for others).",
"type": "array",
"items": {
"$ref": "#/definitions/secretMapping"
}
},
"compute": {
"description": "Compute resources for the main container. IAC secret values override these if present.",
"$ref": "#/definitions/computeConfig"
},
"cdn": {
"description": "CDN (CloudFront) configuration. true = auto (read distribution ID from IaC outputs), false = none, object = custom config. Convention: true for s3-static, true for nextjs ECS, false for backend.",
"oneOf": [
{
"type": "boolean"
},
{
"$ref": "#/definitions/cdnConfig"
}
]
},
"dependsOn": {
"description": "Services or phases that must complete before this service deploys. Convention: all services depend on 'iac'; services with databases depend on 'database:{db-name}'; services with sidecars get 'sidecar:{name}' dependencies.",
"type": "array",
"items": {
"type": "string"
}
},
"sidecars": {
"description": "Sidecar containers deployed alongside this service in ECS. Convention: derived from role (e.g., auth → OpenFGA sidecar).",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/sidecarDeployConfig"
}
},
"iac": {
"description": "Infrastructure-specific deployment configuration for this service. Contains provider-specific details (compute, ALB, security groups, IAM policies, database, sidecars). Passed through to the tfvars generator. Supports {name_prefix}, {iac_name}, {manifest_name}, {prefix}, {env} template variables.",
"type": "object"
}
},
"additionalProperties": false
},
"secretMapping": {
"type": "object",
"description": "Maps a secret from Secrets Manager to a file in the build context. Supports interpolation: {prefix}, {env}, {service}.",
"required": [
"source",
"target"
],
"properties": {
"source": {
"description": "Secrets Manager secret name. Supports interpolation: {prefix}-{env}/microlith-spring-properties.",
"type": "string"
},
"target": {
"description": "Where to write the secret value. Relative path from repo root. Supports interpolation: apps/backend/{service}/src/main/resources/application-{env}.yml.",
"type": "string"
},
"format": {
"description": "How to process the secret value before writing. 'raw' = write as-is, 'dotenv' = parse as dotenv, 'extract-key' = extract a specific key from JSON.",
"enum": [
"raw",
"dotenv",
"extract-key"
],
"default": "raw"
},
"extractKey": {
"description": "When format is 'extract-key', the JSON key to extract from the secret value.",
"type": "string"
}
},
"additionalProperties": false
},
"cdnConfig": {
"type": "object",
"description": "CDN configuration for static or frontend deployments. When specified as an object, allows customizing CDN behavior beyond the auto-detected defaults.",
"properties": {
"distributionIdOutput": {
"description": "JSON path within iac-outputs.json to find the CloudFront distribution ID. Convention: derived from service name and IaC output structure.",
"type": "string"
},
"invalidationPaths": {
"description": "Paths to invalidate in CloudFront after deployment. Default: ['/*'].",
"type": "array",
"items": {
"type": "string"
},
"default": [
"/*"
]
}
},
"additionalProperties": false
},
"sidecarDeployConfig": {
"type": "object",
"description": "Configuration for a sidecar container deployed alongside a service in ECS.",
"required": [
"image"
],
"properties": {
"image": {
"description": "Docker image for the sidecar (e.g., 'openpolicyagent/opa:latest-static').",
"type": "string"
},
"port": {
"description": "Container port for the sidecar.",
"type": "integer"
},
"cpu": {
"description": "CPU units for the sidecar container. Default: 128.",
"type": "integer",
"default": 128
},
"memory": {
"description": "Memory (MiB) for the sidecar container. Default: 256.",
"type": "integer",
"default": 256
},
"essential": {
"description": "Whether the task should stop if this sidecar dies. Default: false.",
"type": "boolean",
"default": false
},
"command": {
"description": "Command override for the sidecar container.",
"type": "array",
"items": {
"type": "string"
}
},
"environment": {
"description": "Environment variables for the sidecar container.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"healthCheck": {
"description": "ECS container health check configuration.",
"$ref": "#/definitions/containerHealthCheck"
}
},
"additionalProperties": false
},
"containerHealthCheck": {
"type": "object",
"description": "ECS container health check configuration.",
"required": [
"command"
],
"properties": {
"command": {
"description": "Shell command to run for health check (will be wrapped in CMD-SHELL).",
"type": "string"
},
"interval": {
"description": "Seconds between health checks. Default: 30.",
"type": "integer",
"default": 30
},
"timeout": {
"description": "Seconds before health check times out. Default: 5.",
"type": "integer",
"default": 5
},
"retries": {
"description": "Number of retries before marking unhealthy. Default: 3.",
"type": "integer",
"default": 3
},
"startPeriod": {
"description": "Grace period (seconds) before health checks start. Default: 60.",
"type": "integer",
"default": 60
}
},
"additionalProperties": false
},
"computeConfig": {
"type": "object",
"description": "Compute resource allocation for a container. CPU units follow AWS ECS conventions (1024 = 1 vCPU). Memory is in MiB.",
"properties": {
"cpu": {
"description": "CPU units for the container. 256 = 0.25 vCPU, 512 = 0.5 vCPU, 1024 = 1 vCPU, 2048 = 2 vCPU, 4096 = 4 vCPU.",
"type": "integer",
"default": 256
},
"memory": {
"description": "Memory (MiB) for the container. Must be compatible with CPU allocation per AWS Fargate limits.",
"type": "integer",
"default": 512
}
},
"additionalProperties": false
},
"serviceConfig": {
"type": "object",
"description": "Declaration of a single service or package in the platform. v0.5.0 groups concerns into structured blocks: scope (visibility), stack (technology), deploy (shipping), run (local dev).",
"properties": {
"scope": {
"description": "Visibility scope of the service: 'public' (internet-facing) or 'internal' (private/platform-only).",
"enum": [
"public",
"internal"
]
},
"repository": {
"description": "Multi-repo (v0.7.0): the GitHub 'owner/repo' this service lives in. Omit for a service that lives in the same repo as the manifest (monorepo).",
"type": "string"
},
"path": {
"description": "Multi-repo (v0.7.0): the service's path within its repository. Omit or '.' = repo root (multi-repo); a subdir (e.g. 'apps/backend/x') = monorepo layout.",
"type": "string"
},
"environments": {
"description": "Multi-repo (v0.7.0): per-service override of the platform-wide ci.environments (env→branch). Lets services living in repos with different branch models deploy from different branches. Falls back to ci.environments when an env is omitted here.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/environmentConfig"
}
},
"stack": {
"description": "Technology stack of the service — what it's built with.",
"$ref": "#/definitions/stackConfig"
},
"deploy": {
"description": "How the service is deployed. Mandatory for deployable services. Packages (stack.type='package') don't need this.",
"$ref": "#/definitions/deployConfig"
},
"run": {
"description": "How the service behaves with 'foundry run'. Defines ports, arguments, health checks, and environment variables for local development.",
"$ref": "#/definitions/runConfig"
},
"enabled": {
"description": "Whether the service participates in 'foundry run'. Disabled services stay declared but are not started.",
"type": "boolean",
"default": true
},
"sshTunnel": {
"description": "LEGACY single SSH tunnel opened before the service starts in prod-target dev. Keeps the implicit DB_HOST/DB_PORT + default-credentials injection. Prefer 'sshTunnels' for new services; declaring both is an error.",
"$ref": "#/definitions/sshTunnelConfig"
},
"sshTunnels": {
"description": "Named SSH tunnels opened (in parallel, all-or-nothing) before the service starts in prod-target dev. Keys are tunnel names (label logs and config.yml/env overrides). Map entries inject ONLY what they declare via 'env'/'injectEnv' — no implicit DB_* injection. The entry named 'db' (or the sole entry with a credentialsSecret) is treated as the database tunnel by 'foundry db' and the migration wrapper.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/sshTunnelConfig"
}
},
"sidecars": {
"description": "Local sidecar processes started alongside the service by 'foundry run' (e.g. OpenFGA, Redis). Keys are sidecar names.",
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/localSidecarConfig"
}
},
"devProdGuard": {
"description": "Env vars injected ONLY when the service runs locally against the prod target — safety overrides (e.g. disabling schedulers) that must never apply in real deployments.",
"type": "object",
"properties": {
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"additionalProperties": false
},
"database": {
"description": "Database this service uses. An inline config object (engine, changelog, properties) or a string referencing a key in the top-level 'databases' map (deprecated).",
"oneOf": [
{
"type": "string"
},
{
"$ref": "#/definitions/databaseConfig"
}
]
},
"kind": {
"description": "[DEPRECATED in v0.5.0 — use stack.type instead] The stack category.",
"enum": [
"backend",
"frontend",
"package"
]
},
"type": {
"description": "[DEPRECATED in v0.5.0 — use stack.framework instead] The runtime/framework.",
"type": "string"
},
"role": {
"description": "[DEPRECATED in v0.5.0 — use scope instead] Semantic role of the service.",
"type": "string"
},
"strategy": {
"description": "[DEPRECATED in v0.5.0 — use deploy.strategy instead] How this service is deployed.",
"type": "string"
}
},
"additionalProperties": false
},
"stackConfig": {
"type": "object",
"description": "Describes the technology stack of a service — what category it falls into, what framework it uses, and what language it's written in.",
"required": [
"type"
],
"properties": {
"type": {
"description": "The stack category. Must match the physical directory: 'backend' → apps/backend/<name>/, 'frontend' → apps/frontend/<name>/, 'package' → packages/<name>/.",
"enum": [
"backend",
"frontend",
"package"
]
},
"framework": {
"description": "The runtime/framework that determines how the service is built and started.",
"enum": [
"spring-boot",
"uvicorn",
"gunicorn",
"nextjs",
"vite",
"react",
"vue",
"angular",
"express",
"django",
"flask",
"other"
]
},
"language": {
"description": "Primary programming language of the service.",
"enum": [
"java",
"python",
"typescript",
"javascript",
"other"
]
}
},
"additionalProperties": false
},
"runConfig": {
"type": "object",
"description": "Local development runtime configuration — how the service behaves with 'foundry run'. Defines ports, arguments, health checks, and environment overrides.",
"properties": {
"port": {
"description": "Application port for local development.",
"type": "integer"
},
"actuatorPort": {
"description": "Actuator/health-check port for local development (Spring Boot).",
"type": "integer"
},
"args": {
"description": "Startup arguments for local development (e.g., ['-Dspring-boot.run.profiles=local']). Args starting with -D are passed as Maven system properties; others as application arguments.",
"type": "array",
"items": {
"type": "string"
}
},
"env": {
"description": "Environment variables for local development.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"healthCheck": {
"description": "Health check endpoint for local development. Object form is what 'foundry run' consumes ({path, port?, expectedStatus?}); the bare-string form is legacy and ignored by the runner.",
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"required": [
"path"
],
"properties": {
"path": {
"type": "string"
},
"port": {
"type": "integer"
},
"expectedStatus": {
"type": "integer",
"default": 200
}
},
"additionalProperties": false
}
]
},
"script": {
"description": "Explicit start command for local development, overriding the framework's default runner. Spring Boot services run this VERBATIM (nothing injected or dropped; run.args are appended; 'debug'/'strictHealthPorts' injection is skipped with a warning). Node services (anything with a package.json): if the value names a package.json script it runs via the package manager (`npm run <name>`); otherwise it is run VERBATIM from the service directory with node_modules/.bin on PATH (e.g. \"nx serve enterprise\"). A service with no detected runtime and no package.json runs it verbatim. A declared service is never silently skipped: without a runnable script it shows up FAILED with the reason.",
"type": "string"
},
"debug": {
"description": "Remote-debugger attachment for local development: a port number, or {port, suspend?} (JDWP for Java, --inspect for Node).",
"oneOf": [
{
"type": "integer"
},
{
"type": "object",
"required": [
"port"
],
"properties": {
"port": {
"type": "integer"
},
"suspend": {
"type": "boolean",
"default": false
}
},
"additionalProperties": false
}
]
},
"strictMode": {
"description": "Strict-mode behavior for 'foundry run': a boolean, or {enabled?, strictHealthPorts?}.",
"oneOf": [
{
"type": "boolean"
},
{
"type": "object",
"properties": {
"enabled": {
"type": "boolean"
},
"strictHealthPorts": {
"type": "boolean"
}
},
"additionalProperties": false
}
]
}
},
"additionalProperties": false
},
"sshTunnelConfig": {
"type": "object",
"description": "SSH port-forward opened before a service starts in prod-target local dev. String values support ${VAR} environment expansion.",
"required": [
"localPort",
"remoteHost",
"remotePort",
"host"
],
"properties": {
"localPort": {
"description": "Local port the tunnel listens on (what the service's DB config points at).",
"type": "integer"
},
"remoteHost": {
"description": "Destination host as seen FROM the bastion (e.g. the private RDS endpoint). Supports ${VAR}.",
"type": "string"
},
"remotePort": {
"description": "Destination port (e.g. 5432).",
"type": "integer"
},
"host": {
"description": "Bastion host/IP to SSH through. Supports ${VAR}; when unset/unresolved, 'bastionTag' resolves it by EC2 Name tag.",
"type": "string"
},
"user": {
"description": "SSH user on the bastion.",
"type": "string",
"default": "ec2-user"
},
"password": {
"description": "Path to the SSH private key file (relative paths resolve against the service's repo root). OPTIONAL: when omitted, authentication falls back to the SSH agent — the right choice for passphrase-encrypted keys, which are not supported as a file path (there is no passphrase field). Auto-fetched from 'keySecret' when missing. Keep it git-ignored — the CLI ensures an ignore entry when it writes the key.",
"type": "string"
},
"bindAddress": {
"description": "Local address the tunnel listens on. Default (omitted): loopback only — 127.0.0.1 plus a ::1 relay, so nothing on the network can reach the tunnelled service. Set \"0.0.0.0\" ONLY when something off-host must connect (e.g. a Docker container via host.docker.internal) — this exposes the tunnel to the local network and logs a warning. IPv4 only.",
"type": "string"
},
"bastionTag": {
"description": "EC2 tag:Name used to resolve the bastion's public IP when 'host' is unset or its ${VAR} is unresolved.",
"type": "string"
},
"keySecret": {
"description": "AWS Secrets Manager secret id holding the SSH key (JSON field 'private_key_pem'), fetched into 'password''s path when the file is missing.",
"type": "string"
},
"credentialsSecret": {
"description": "AWS Secrets Manager secret id with DB credentials injected as env into the service process (never written to disk).",
"type": "string"
},
"injectEnv": {
"description": "Override/extend the injected credential env-var mapping: ENV_VAR -> secret field (e.g. {\"PGUSER\": \"username\"}). Requires 'credentialsSecret'.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"env": {
"description": "Plain env vars this tunnel contributes to the service in prod-target dev, with ${localPort}/${localHost} placeholder expansion (e.g. {\"AUTH_BASE_URL\": \"http://localhost:${localPort}\"}). The explicit replacement for the legacy implicit DB_HOST/DB_PORT injection.",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"awsRegion": {
"description": "Region for the bastion lookup and secret fetches.",
"type": "string"
}
},
"additionalProperties": false
},
"localSidecarConfig": {
"type": "object",
"description": "A local sidecar process 'foundry run' starts alongside the service (e.g. OpenFGA, Redis via docker).",
"required": [
"command"
],
"properties": {
"command": {
"type": "string"
},
"args": {
"type": "array",
"items": {
"type": "string"
}
},
"cwd": {
"description": "Working directory, relative to the manifest directory.",
"type": "string"
},
"port": {
"type": "integer"
},
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"enabled": {
"type": "boolean",
"default": true
},
"healthPath": {
"description": "HTTP health endpoint (e.g. '/health') polled for readiness.",
"type": "string"
},
"readyPatterns": {
"description": "Log substrings indicating the sidecar is ready.",
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
}
}