Dibbla Docs Get started Guides Workflows Changelog
Open Console
Reference

dibbla.yaml schema

Every field of the deployment manifest in one place — services, jobs and support — with which fields vary per environment and which two parsers read the file.

A dibbla.yaml in your project root describes what to deploy: one or more services, any scheduled jobs, and whether the app offers support tickets. It is read by dibbla deploy, and you can see exactly what it resolves to — before deploying anything — with dibbla preview.

It is not related to dibbla-task.yaml, which is a setup pipeline that runs on your machine.

You may not need one

A single-container app deploys without a manifest at all. Write one when you have more than one service, want a cron job, need per-environment values, or want any of the fields below.

A complete file

version: 1                      # required; 1 is the only accepted value

services:                       # required; at least one
  web:
    build: ./web                # path, or a build object (see below)
    port: 3000                  # required when public: true
    public: true                # routes a public URL to this service
    replicas: 2
    cpu: 500m
    memory: 512Mi
    environment:
      API_URL: http://api:8080
    depends_on: [api]
    auth:
      require_login: true
      access_policy: all_members

  api:
    build:
      context: ./api
      dockerfile: Dockerfile.prod
      target: release
      args:
        VERSION: "1.4"
      secrets:
        - id: npm_token         # BuildKit --mount=type=secret,id=npm_token
          source: NPM_TOKEN     # name in the dibbla secrets store
    port: 8080
    healthcheck:
      readiness:
        http_get:
          path: /healthz
        period_seconds: 10

  db:
    image: postgres:16
    stateful: true              # StatefulSet + headless Service
    volumes:
      - path: /var/lib/postgresql/data
        size: 10Gi
    routes:
      - type: tcp
        port: 5432

jobs:                           # optional; cron jobs
  nightly-report:
    schedule: "0 2 * * *"
    build: ./jobs/report
    command: ["node", "report.js"]

support:                        # optional; per-app end-user tickets
  enabled: true
  visibility: app

Top level

FieldTypeRequiredNotes
versionintyes1. Anything else is rejected as MANIFEST_UNSUPPORTED.
servicesmapyesService name → definition. Names become DNS labels inside the deployment.
jobsmapnoJob name → cron job. See Jobs.
supportobjectnoPer-app support tickets. See Support.

Services

FieldTypeEnv-awareNotes
buildstring | objectnoPath to a build context, or the object form shown above. One of build/image is required. The path is resolved inside the uploaded archive, which the platform has already filtered — a per-service context is carved out of what survived, not out of your working tree. A service whose Dockerfile copies a vendored or pre-built directory fails here for the same reason a single-service one does.
imagestringyesA pulled image; must include a tag.
portintnoContainer port. Required when public: true.
publicboolyesRoutes a public URL to this service. More than one public service is allowed — the lexically first keeps the bare app hostname, the others get {alias}-{service}.
replicasintyesPod count, capped by your organisation’s quota.
cpustringyesKubernetes CPU spec: 500m, 1, 2.
memorystringyesKubernetes memory spec: 256Mi, 1Gi.
environmentmapyesPlain environment variables — settings, not secrets; supports ${VAR} substitution. The file is in your source and its history, so a name or value that looks like a secret is a warning for a person and refused for an AI assistant’s deploy or a proposal it wrote, and a name that is one of the app’s secrets is refused. Secrets go in the secret store — see env vars and secrets.
commandlistnoOverrides the image’s CMD.
entrypointlistnoOverrides the image’s ENTRYPOINT.
volumeslistnoPer-service persistent volumes; see Volumes.
statefulboolnoRenders a StatefulSet with a headless Service. Requires at least one volume.
profileslistnoOnly include this service when one of these profiles is active.
depends_onlistnoOrdering for builds and startup.
expose_tolistnoRestrict which other services may reach this one (NetworkPolicy).
initlistnoInit containers; image: only, no build:.
healthcheckobjectnoliveness, readiness, startup; see Health checks. Container probes — not application checks, which live in dibbla-checks.yaml.
domainstring | objectnoA custom domain for this service. See Custom domains.
routeslistnoNon-HTTP entry points; see Routes.
authobjectnoPer-service login gate; see Auth.
mcpstringnoPublishes the tool server this service runs as an MCP of its own, under this name. See MCP.

Env-aware fields

A field marked env-aware takes either a single value or a per-environment map:

services:
  web:
    replicas:
      prod: 3
      dev: 1
    public: true

The environment comes from --env at deploy time. An environment with no entry falls back to the platform default, not to another environment’s value.

Auth

auth:
  require_login: true           # env-aware
  access_policy: invite_only    # env-aware: all_members | invite_only
  google_scopes: [profile]
  microsoft_scopes: []

Unset fields fall back to the deploy-level --require-login / --access-policy flags. The email_domain policy is console-only — it needs a domain list that neither the flag nor this block carries. See SSO & access control.

MCP

services:
  tools:
    build: .
    mcp: my-tools               # https://mcp.<domain>/platform/servers/my-tools
    auth:
      require_login: true
      access_policy: invite_only
    environment:
      SERVER_NAME: my-tools     # the name the worker registers under

mcp: publishes the tool server a service runs — a Go worker built with the Go SDK — as an MCP at /platform/servers/<name>. The walkthrough is Publish an MCP; the rules are:

  • The value is the tool server’s name, the one the worker registers under (SERVER_NAME, or WithServerName in code). 1–64 characters of letters, digits, ., _ and -; anything else is rejected as MANIFEST_INVALID at services.<name>.mcp. One service per name.
  • Whoever may deploy the app may publish. No organization admin is involved, and the worker needs no API token: a deployed service connects with the app’s workload identity.
  • Who gets the tools follows the app’s access list — auth.access_policy and the app’s Access tab in the console — never a per-function exposure. The address always requires a Dibbla sign-in, also for an app with require_login: false. See who gets in.
  • The whole server is published. Every function that can be a tool is one; agents and engine-internal functions are left out.
  • The deploy never fails over this line and never stays silent about it. It reports the server as published, or says why it was not (a name another app owns, an invalid name, per-server addresses switched off on the installation, or a publish that should be retried). See Deploy and read the answer.
  • Removing the line and deploying unpublishes. So does deleting the app. A service behind an inactive profile publishes nothing.

The field is not env-aware.

Volumes

volumes:
  - path: /data
    size: 10Gi
    access: rwo                 # rwo (default) | rwx

Health checks

Each of liveness, readiness and startup takes one probe — http_get (path, optional port), tcp_socket (port) or exec — plus optional initial_delay_seconds, period_seconds, timeout_seconds and failure_threshold.

These are the Kubernetes probes: they ask the container to prove its process is up, and a failing probe restarts the pod. They are not application checks — the scheduled, user-journey-shaped assertions a deployment ships in a separate dibbla-checks.yaml, which run against the public route and never restart anything. A pod can pass every probe and still serve error pages; the two files answer different questions on purpose.

Routes

routes:
  - type: tcp                   # tcp | https | http
    port: 5432
    tls: edge                   # edge | none (TCP always terminates at the proxy)
    hostname: my-db             # subdomain label; defaults to {alias}-{service}

Jobs

FieldTypeRequiredNotes
schedulestringyesStandard cron expression, e.g. 0 2 * * *.
build / imagestring | objectone ofSame shapes as a service.
commandlistnoOverrides the image’s CMD.
environmentmapnoEnvironment variables for the job.
cpu, memorystringnoResource requests.
successful_jobs_history_limitintnoHow many completed runs to keep.
failed_jobs_history_limitintnoHow many failed runs to keep.

See Scheduled jobs for the walkthrough.

Support

support:
  enabled: true
  visibility: app               # app (default) | own

Turns on support tickets for this app’s end users. Support can also be switched on from the console without a manifest — an explicit support: block here always wins while it is present; in its absence the console setting governs and survives redeploys.

Two fields are parsed but do not change behaviour

assignees and attachments are accepted and validated, and neither changes what the app does. Assignment is done in the console.

attachments is deprecated: files on a ticket are live, and they follow support.enabled, so this key switches nothing on or off. It still parses — a manifest that already carries it keeps deploying — and dibbla preview reports it as having no effect. Remove it at your convenience.

Two parsers read this file

The CLI is deliberately more permissive than the server

The CLI validates the shape it needs to build and upload; deploy-api validates the whole schema and is the authority. A field the CLI passes through can still be rejected on the server — and an older CLI ignores keys it has never heard of rather than erroring, which is what lets a new manifest field ship without breaking every installed binary.

The consequence worth knowing: dibbla preview asks the server, so it shows you the real resolution. Trust it over what the local parser accepted.