Schema Reference

v0.5.0https://raw.githubusercontent.com/FoundryMedia/foundry/release/foundry.schema.json

Declarative manifest for a Foundry-managed platform. Defines WHAT the platform is — its topology, services, databases, and CI/CD configuration.

Required Fields

  • $schema
  • schemaVersion
  • name
  • repository
  • ci
  • services

Definitions

foundryConfig

Foundry CLI metadata. Allows manifests to declare minimum CLI version requirements.

PropertyTypeDescription
minCliVersionstringMinimum 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.

PropertyTypeDescription
namestringTemplate identifier (e.g., 'tfw', 'minimal').
versionstringVersion of the template that was used.
generatedAtstringISO-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).

PropertyTypeDescription
organizationstringGitHub organization that owns all platform repositories.
repositoriesobjectMap of related repositories in the ecosystem. Keys are logical names, values describe the repo and its relationship.

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.

PropertyTypeDescription
appsDirstringDirectory containing backend/ and frontend/ service directories (default: 'apps').
ciDirstringDirectory containing db/, scripts/, and iac/ (default: 'ci').
packagesDirstringDirectory 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.

PropertyTypeDescription
organizationstringGitHub organization that owns all platform repositories. Required — this is the anchor for cross-repo discovery and artifact registry scoping.
prefixstringShort prefix derived from the first letter of each word in the platform name (e.g., 'An Average Platform' → 'aap'). Used to discover satellite repos matching '{prefix}-*'. Auto-derived if not set; must be at least 2 characters.
repositoriesobjectMap of related repositories in the ecosystem. Keys are logical names, values describe the repo and its relationship.
apiLib#/definitions/apiLibConfigThe 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.

PropertyTypeDescription
repositorystringRepository name within the organization (e.g., 'aap-api-lib').
relationshipHow this repo relates to the current repo.

apiLibConfig

Configuration for the platform's API library repository.

PropertyTypeDescription
repositorystringRepository name (e.g., 'aap-api-lib').
packageRegistrystringWhere the api-lib packages are published.
groupIdstringMaven groupId or npm scope for published packages.
packagesSecretstringName of the GitHub Actions secret containing a PAT with read:packages scope for cross-repo access.
modulesobjectMap of logical module names to their artifact coordinates.

apiLibModuleConfig

A single module within the api-lib repository.

PropertyTypeDescription
artifactIdstringPublished artifact name.
versionstringCurrent published version of this module.
specPathstringRelative path (within the module) to the OpenAPI spec file.

databaseConfig

Configuration for a database schema managed by this platform.

PropertyTypeDescription
enginestringDatabase engine.
schemastringDefault schema name (primarily for PostgreSQL).
changelogstringRelative path to the Liquibase master changelog file.
propertiesstringRelative path to the Liquibase connection properties file.
credentialsobjectDatabase credential resolution configuration.

environmentConfig

Configuration for a deployment environment. Maps a Git branch to a named environment.

PropertyTypeDescription
branchstringGit branch name that triggers deployment to this environment.
enabledbooleanWhether this environment is active. Disabled environments are excluded from pipeline triggers and deployment. Default: true.
autoApprovebooleanWhether deployments to this environment require manual approval. Default: false (require approval).
iacobjectInfrastructure-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.

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.

PropertyTypeDescription
strategyHow this service is deployed. 'service' = containerized (ECS Fargate), 'static' = S3/CDN static hosting, 'none' = not deployed (packages).
dockerfilestringPath to Dockerfile relative to repo root. Convention: apps/{kind}/{name}/Dockerfile.
buildContextstringDocker build context relative to repo root. Convention: '.' for monorepo (Spring Boot), service dir for standalone (Python).
buildCommandstringBuild command for non-Docker builds (static sites). Convention: derived from type (e.g., 'pnpm build' for nextjs/vite).
secretsarraySecrets to fetch from Secrets Manager before build/deploy. Convention: derived from type (microlith-spring-properties for Spring Boot, {name}-env for others).
compute#/definitions/computeConfigCompute resources for the main container. IAC secret values override these if present.
cdnCDN (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.
dependsOnarrayServices 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.
sidecarsobjectSidecar containers deployed alongside this service in ECS. Convention: derived from role (e.g., auth → OpenFGA sidecar).
iacobjectInfrastructure-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}.

PropertyTypeDescription
sourcestringSecrets Manager secret name. Supports interpolation: {prefix}-{env}/microlith-spring-properties.
targetstringWhere to write the secret value. Relative path from repo root. Supports interpolation: apps/backend/{service}/src/main/resources/application-{env}.yml.
formatHow to process the secret value before writing. 'raw' = write as-is, 'dotenv' = parse as dotenv, 'extract-key' = extract a specific key from JSON.
extractKeystringWhen 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.

PropertyTypeDescription
distributionIdOutputstringJSON path within iac-outputs.json to find the CloudFront distribution ID. Convention: derived from service name and IaC output structure.
invalidationPathsarrayPaths to invalidate in CloudFront after deployment. Default: ['/*'].

sidecarDeployConfig

Configuration for a sidecar container deployed alongside a service in ECS.

PropertyTypeDescription
imagestringDocker image for the sidecar (e.g., 'openpolicyagent/opa:latest-static').
portintegerContainer port for the sidecar.
cpuintegerCPU units for the sidecar container. Default: 128.
memoryintegerMemory (MiB) for the sidecar container. Default: 256.
essentialbooleanWhether the task should stop if this sidecar dies. Default: false.
commandarrayCommand override for the sidecar container.
environmentobjectEnvironment variables for the sidecar container.
healthCheck#/definitions/containerHealthCheckECS container health check configuration.

containerHealthCheck

ECS container health check configuration.

PropertyTypeDescription
commandstringShell command to run for health check (will be wrapped in CMD-SHELL).
intervalintegerSeconds between health checks. Default: 30.
timeoutintegerSeconds before health check times out. Default: 5.
retriesintegerNumber of retries before marking unhealthy. Default: 3.
startPeriodintegerGrace 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.

PropertyTypeDescription
cpuintegerCPU units for the container. 256 = 0.25 vCPU, 512 = 0.5 vCPU, 1024 = 1 vCPU, 2048 = 2 vCPU, 4096 = 4 vCPU.
memoryintegerMemory (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).

PropertyTypeDescription
scopeVisibility scope of the service: 'public' (internet-facing) or 'internal' (private/platform-only).
stack#/definitions/stackConfigTechnology stack of the service — what it's built with.
deploy#/definitions/deployConfigHow the service is deployed. Mandatory for deployable services. Packages (stack.type='package') don't need this.
run#/definitions/runConfigHow the service behaves with 'foundry run'. Defines ports, arguments, health checks, and environment variables for local development.
databaseDatabase 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.
typestring[DEPRECATED in v0.5.0 — use stack.framework instead] The runtime/framework.
rolestring[DEPRECATED in v0.5.0 — use scope instead] Semantic role of the service.
strategystring[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.

PropertyTypeDescription
typeThe stack category. Must match the physical directory: 'backend' → apps/backend/<name>/, 'frontend' → apps/frontend/<name>/, 'package' → packages/<name>/.
frameworkThe runtime/framework that determines how the service is built and started.
languagePrimary 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.

PropertyTypeDescription
portintegerApplication port for local development.
actuatorPortintegerActuator/health-check port for local development (Spring Boot).
argsarrayStartup 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.
envobjectEnvironment variables for local development.
healthCheckstringHealth check endpoint path for local development (e.g., '/actuator/health').

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.5.0",
  "required": [
    "$schema",
    "schemaVersion",
    "name",
    "repository",
    "ci",
    "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., 'An Average Platform' → 'aap'). 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"
          }
        }
      },
      "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., 'An Average Platform' → 'aap'). 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., 'aap-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., 'aap-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": "Configuration for a deployment environment. Maps a Git branch to a named environment.",
      "required": [
        "branch"
      ],
      "properties": {
        "branch": {
          "description": "Git branch name that triggers deployment to this 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"
        }
      },
      "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. 'service' = containerized (ECS Fargate), 'static' = S3/CDN static hosting, 'none' = not deployed (packages).",
          "enum": [
            "service",
            "static",
            "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"
          ]
        },
        "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"
        },
        "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 path for local development (e.g., '/actuator/health').",
          "type": "string"
        }
      },
      "additionalProperties": false
    }
  }
}