config. It never contains shell scripts that touch the cluster, kubectl, Helm charts, Kubernetes objects or secret values: charts belong to the catalog, and values are set by people through a secret request. Every field maps to a catalog entry or the file is refused before anything is built, with a message that says what to change. This schema is catalog-independent; the control plane also checks the file against the cluster’s catalog (which types, sizes, runtimes, audiences and healer levels are offered, and how many of each an app may have).
The file is checked twice: against this schema, and against your cluster’s catalog. A value this page allows can still be refused if your IT team’s catalog does not offer it. Every problem is reported at once; see Refusal messages.
Example
gliss.yaml
Top-level fields
gliss.dev/v1
required
Always gliss.dev/v1 for this version of the contract.
string
required
The app’s name. Lowercase letters, digits and single hyphens, 2 to 30 characters, starting with a letter; no double hyphen, because Preview addresses use
-- to separate the builder from the app. It names the app’s namespaces, so keep it short and stable; renaming it creates a new app. platform and backups are reserved, because Gliss’s own buckets use those names.If refused: use 2 to 30 lowercase letters, digits or single hyphens, starting with a letter, for example expense-tracker; platform and backups are reserved.string
required
Email address of the person who owns the app. Secret requests, findings and publish approvals go to them. Use the builder’s work email, not a team alias.If refused: use the owner’s work email address, for example dana@customer.com.
object
required
The parts of the app that Gliss builds from this repository, keyed by a short component name such as web, api or worker (not preview: images CI builds from a work branch live under the app’s preview/ repositories). Each component is built from its own folder with a Dockerfile, by the customer’s CI, and runs as its own container. How many components an app may have is set by the catalog.If refused: add at least one component, for example web: { build: ./frontend, port: 8080 }.
object
What the app needs from the platform, chosen from the catalog menu. Each key is a name you choose (database, files, cache, auth, …) and each value names a catalog type with
type. The key secrets is reserved for declaring secret names and types. Leave a capability out and the app does not get it.object
Plain, non-secret settings the app reads as environment variables, as NAME: value, for example LOG_LEVEL: info or MAX_UPLOAD_MB: 25. Values are text, numbers or true/false, and reach the app as text. Anyone who can read the repository can read them, so never put a token, password or key here: declare it under capabilities.secrets instead. Names the platform sets (GLISS_, AWS_, DATABASE_URL, <CAPABILITY>_BUCKET, <CAPABILITY>_URL for a cache, …), names that change how a runtime loads code or trusts TLS certificates, and values that look like secrets are refused. stages.<stage>.config overrides a value for one stage. The catalog sets how many values an app may have and their total size.At most 100 entries.If refused: keep at most 100 config values.
string[]
The outside services the app may call, as hostnames, for example api.openai.com or login.salesforce.com. Everything else is blocked by network policy, at every stage. The platform’s own services (the database, the cache, the app’s buckets and AWS endpoints) are always reachable and must not be listed. The catalog decides which hostnames are approved; wildcards (*.example.com) and IP addresses are refused unless the catalog allows them.At most 50 items.
object
Commands that run on a schedule, keyed by a short name such as nightly-report or refresh-cache. Each one runs in a component’s image, with the same config, secrets, database and network rules as that component, as a short-lived job; it never serves traffic. Schedules run in Beta and Live, never in a Preview (use
gliss test or a one-off command there). Times are UTC unless timeZone says otherwise. A run that fails is reported, and the next scheduled run is the retry; at most one run of a schedule is active at a time.At most 10 entries.If refused: keep at most 10 schedules.object
Optional per-stage overrides. The app always runs in three stages: Preview (only the builder and people they invite), Beta (invited testers, built from main) and Live (the real app). The top-level settings apply to every stage. Each stage may override config values. Preview and Beta may also choose how each declared secret is handled; Live may not, because every secret declared for Live must be set before Publish.If refused: the stages are preview, beta and live.
Components
Each entry undercomponents is one container.
One container that Gliss builds and runs. The catalog chart runs it as non-root with the restricted pod-security level, so it must listen on a port of 1024 or above and must not need root.
string
required
Folder, relative to the repository root, that holds this component’s Dockerfile. Start with ./ and stay inside the repository, for example ./frontend or ./backend.If refused: use a folder inside the repository that starts with ./, for example ./backend.
integer
Port the component listens on for HTTP. Leave it out for a background worker that serves no traffic. Must be 1024 to 65535, because containers run as non-root under the restricted pod-security level; 8080 and 8000 are common choices.From 1024 to 65535.If refused: containers run as non-root under the restricted pod-security level, so listen on 1024 to 65535, for example 8080.
string
The language runtime of this component, from the catalog’s runtimes, for example python, node or vite. Runtimes with a dev variant in the catalog (python and vite at the MVP) reload in Preview in about 5 to 10 seconds when the builder saves a change, instead of a full rebuild. Leave it out and Preview rebuilds on every change.The cluster’s catalog decides which values are offered (
runtimes).If refused: name a runtime from the catalog, for example python or vite.string
Command that upgrades the database schema, run inside this component’s image before each release at every stage, for example
alembic upgrade head. One line, no shell pipelines that reach outside the container. Migrations must be backward-compatible (expand, then contract) so Undo publish can return Live to the previous release. A migration that fails in Beta blocks Publish.At most 500 characters.If refused: use one command line, for example alembic upgrade head.string
Command that runs this component’s own tests inside its image, for example
pytest -q. gliss test runs it as a short-lived job in the Preview namespace, so the builder needs no local runtime. One line.At most 500 characters.If refused: use one command line, for example pytest -q.Capabilities
What the app needs from the platform, chosen from the catalog menu. Each key is a name you choose (database, files, cache, auth, …) and each value names a catalog type withtype. The key secrets is reserved for declaring secret names and types. Leave a capability out and the app does not get it.
The catalog entry: postgres (a database), redis (an in-cluster cache), bucket (object storage), hostname (the app’s web address), sso (sign-in in front of the app) or healer (a bot that watches the app and proposes fixes). The cluster’s catalog may offer fewer. Email (SES), connections to SaaS accounts and managed Postgres (RDS) are not offered in v1.
postgres
A Postgres database for the app (catalog postgres@1). Live gets its own CloudNativePG cluster with backups; Preview and Beta get their own database on a shared Postgres of the same version. The app receives the connection string as DATABASE_URL; nobody types a database password.small | standard
Live database size. small is one instance; standard is two instances for high availability. Leave it out to use the catalog default (small). Preview and Beta use the shared stage database whatever the size.The cluster’s catalog decides which values are offered (
postgres.sizes).string[]
Postgres extensions the app needs, by the name CREATE EXTENSION uses, for example vector (pgvector), pg_trgm or uuid-ossp. Only extensions the catalog lists for the cluster’s Postgres version are offered. The platform creates them; the app’s migrations must not.At most 20 items.
bucket
Object storage for files the app keeps (catalog bucket@1): an S3 bucket in the customer’s account, one per stage. The app reaches it through its own AWS role, so there are no access keys; it receives the bucket name in an environment variable named after the capability key, for example FILES_BUCKET for a capability called files.hostname
The app’s web address (catalog hostname@1). Live is served at <name>.<customer domain>, Beta at <name>.beta.<customer domain>, and each builder’s Preview at <builder>--<name>.preview.<customer domain>, one label below preview so that one wildcard certificate covers every Preview. Only Live gets the clean name. Leave the capability out for an app that serves no web traffic, such as a worker.
string
required
The first label of the Live address, for example expenses for expenses.acme.com. 2 to 30 lowercase letters, digits or single hyphens; no double hyphen, which separates builder and name in Preview addresses. Some names are reserved by the catalog (secrets, preview, beta).If refused: use 2 to 30 lowercase letters, digits or single hyphens, for example expenses.
string
Which component receives the traffic. Leave it out when only one component has a port, or when the one that serves the browser is called web; otherwise name it. The component it names can call the others inside the namespace.
sso
Sign-in enforced by Gliss in front of the app. People sign in with the customer’s own identity provider; requests from outside the audience never reach the app. The app receives verified, signed identity headers (email, name, groups and app roles) and must not write login code, embed a sign-in SDK or add a bypass flag.string | array
required
Who may use the Live app: org (everyone in the customer’s organisation), group:<name> (members of an identity-provider group, for example group:finance), a list of groups ([group:finance, group:ops], anyone in any of them), or public (anyone; needs IT approval before Publish). Preview and Beta are always limited to the builder and the people they invite.At most 10 items. The cluster’s catalog decides which values are offered (
sso.audiences).object
Optional mapping from app role names to who holds them: org, one group:<name>, or a list of groups, for example admin: group:finance-leads, approver: [group:finance-leads, group:controllers] and viewer: org. The app owner can also assign roles to people in the console. The effective roles reach the app in the identity headers.
healer
App maintenance: a healer bot watches the app’s health and findings and acts on them. It is off unless the app asks for it. The catalog sets the levels IT allows, and auto is only available with the managed maintenance package.observe | propose | auto
required
How far the healer may go. observe: it reports findings and diagnoses only. propose: it also opens pull requests for the owner to review. auto (managed maintenance package only): its pull requests merge on green checks and deploy to Beta; Live still follows the publish approval policy.The cluster’s catalog decides which values are offered (
healer.levels).redis
An in-cluster Redis cache (catalog redis@1), one per stage. It is a cache: data can be lost on restart or eviction, so keep nothing there that the database does not also have. The app receives its address in an environment variable named after the capability key, for example CACHE_URL for a capability called cache.small | standard
Memory for the cache, set by the catalog (small and standard). Leave it out to use the catalog default.The cluster’s catalog decides which values are offered (
redis.sizes).secrets
secrets is the one reserved key under capabilities. It maps each secret’s name to its type.
Third-party secrets the app needs, as NAME: type. Declare names and types only, never values: a person sets each value through a single-use secret request. The app reads each secret as an environment variable of the same name and must work in mock mode while it is missing; GLISS_MISSING_SECRETS lists the ones not set yet. Database passwords, tokens between the app’s own components and AWS access are created by the platform and must not be declared.
credential | endpoint
credential: a token or key; a guest with a link may set it, because a guest can only write it. endpoint: an address that decides where the app sends data, such as a URL; only a signed-in member may set it, and using one means Publish needs IT approval.If refused: declare only the type, credential (a guest may set it) or endpoint (only a signed-in member may set it), never the value; the value is set by a person through a secret request.
Config values
Plain, non-secret settings the app reads as environment variables, as NAME: value, for example LOG_LEVEL: info or MAX_UPLOAD_MB: 25. Values are text, numbers or true/false, and reach the app as text. Anyone who can read the repository can read them, so never put a token, password or key here: declare it under capabilities.secrets instead. Names the platform sets (GLISS_, AWS_, DATABASE_URL, <CAPABILITY>_BUCKET, <CAPABILITY>_URL for a cache, …), names that change how a runtime loads code or trusts TLS certificates, and values that look like secrets are refused. stages.<stage>.config overrides a value for one stage. The catalog sets how many values an app may have and their total size. One value: text (one line, at most 1024 characters), a number, or true/false. Some names and values are refused even though they fit the schema. See Config rules.Schedules
One scheduled command.string
required
The component whose image, config, secrets and database the command runs with, for example api or worker.If refused: name one of the components, for example api.
string
required
When it runs, as a five-field cron expression (minute hour day-of-month month day-of-week), for example
0 2 * * * for 02:00 every day or */15 * * * * every 15 minutes, or @hourly, @daily, @weekly or @monthly. At most once every 5 minutes.At most 100 characters.If refused: use five cron fields separated by spaces, for example 0 2 * * * (02:00 every day), or @daily.string
required
The command to run inside the component’s image, for example
python -m app.jobs.nightly_report. One line. It must finish before timeoutMinutes, exit 0 on success, and be safe to run again (a failed run is not retried until the next scheduled time).At most 500 characters.If refused: use one command line, for example python -m app.jobs.refresh.string
The time zone the cron expression is read in, as an IANA name such as Europe/Berlin or Asia/Jerusalem. Leave it out for UTC.At most 64 characters.If refused: use an IANA time zone name such as Europe/Berlin, or leave it out for UTC.
integer
How long one run may take before it is stopped and reported as failed, in minutes. Default 30, at most 120.From 1 to 120.If refused: use a whole number of minutes from 1 to 120.
Stages
Optional per-stage overrides. The app always runs in three stages: Preview (only the builder and people they invite), Beta (invited testers, built from main) and Live (the real app). The top-level settings apply to every stage. Each stage may override config values. Preview and Beta may also choose how each declared secret is handled; Live may not, because every secret declared for Live must be set before Publish.stages.preview and stages.beta
Overrides for Preview or Beta.object
How each declared secret is handled in this stage. mock: no secret request is sent for this stage and the app runs that integration in mock mode. request: a secret request is sent for this stage’s value (for Beta, often a sandbox credential). Defaults come from the catalog: Preview mock, Beta request.
any
Config values for this stage only. They replace the top-level value with the same name, or add a name only this stage has (for example FLASK_DEBUG in Preview).
stages.live
Overrides for Live. Only config values: every secret declared for Live must be set before Publish, so Live has no secrets override.any
Config values for Live only. Debug switches that expose an interactive console (FLASK_DEBUG, WERKZEUG_DEBUG_PIN, …) are refused here.
More examples
Gliss accepts each of these files when checked against the example catalogacme@3.
Minimal
Minimal
The smallest useful file: one component, reachable at its own address.
Adr 004 example
Adr 004 example
The example from without its comments. The hostname goes to web, the component that serves the browser.
Worker no hostname
Worker no hostname
A background worker: no port, no web address, two buckets, one credential.
Group audience roles
Group audience roles
Sign-in limited to two groups, with app roles mapped from identity-provider groups.
Stage overrides
Stage overrides
Per-stage secret handling: Preview asks for a sandbox token, Beta stays in mock mode.
Public endpoint go
Public endpoint go
Accepted with notices: a public audience and an endpoint secret need IT approval at Publish, and a Go component rebuilds in Preview instead of reloading.Notices returned with it:
Full stack
Full stack
Three components with dev variants, migrations, tests and every capability type.
Config per stage
Config per stage
Plain settings, with per-stage values. None of these values may look like a secret, and the debugger switch is set for Preview only.
Cache extensions egress
Cache extensions egress
A cache, Postgres extensions from the catalog’s list, and the outside services the app calls.
Schedules
Schedules
Scheduled jobs: a nightly report in the api’s image, in its own time zone, and a cache refresh every 15 minutes in the worker’s. They run in Beta and Live, never in a Preview.