Convert Compose To Fibe
This skill is the master playbook. It does not duplicate exact rules — it tells you which surgical skills to load for each step. Load the listed skills on demand; do not preload all of them.
The contract (read first)
A Fibe template is valid Docker Compose plus:
- Service-level Fibe behavior expressed through
fibe.gg/*labels underservices.<name>.labels. - Optional
x-fibe.ggblock withvariablesandmetadata. Put job, schedule and trigger settings undermetadatafor current launch/import behavior. - No other Fibe-specific top-level keys.
services:is still required.
Validation runs in three stages — schema is a first pass, runtime owns final compile. Load reference-validation-pipeline to see what each stage catches.
High-level decision tree
input: a docker-compose.yml + intent (one of)
├─ HTTP service(s) → "long-running web template"
├─ background workers + DB only → "long-running app template"
├─ one-shot task that exits → "job-mode template" (Trick)
├─ cron-style recurring → "job-mode + schedule_config"
└─ git push / PR triggered → "job-mode + metadata.trigger_config"
→ Load decide-job-mode if uncertain which one.
Conversion steps
Do them in this order. Each step links to one or more surgical skills.
Step 1 — Classify every service
For each service, decide static (use a prebuilt image) or dynamic (Fibe clones/builds from a Git repo, can be source-mounted).
→ Load decide-static-vs-dynamic.
The signal is the fibe.gg/repo_url label. A Compose build: block requires fibe.gg/repo_url. So does fibe.gg/source_mount.
Step 2 — Resolve build: into Fibe labels
If the service has a build: block, you have a dynamic service. Add fibe.gg/repo_url + (optional) fibe.gg/dockerfile, fibe.gg/branch, fibe.gg/build_target, fibe.gg/build_args, fibe.gg/source_mount.
→ Load recipe-build-to-repo-url and recipe-build-args-and-target.
Step 3 — Replace ports: with fibe.gg/expose
User-facing HTTP is always fibe.gg/expose. Never use Compose ports: for public traffic — Traefik handles routing.
→ Load recipe-ports-to-expose.
Then choose how the public URL is shaped:
- subdomain only: recipe-add-subdomain
- path prefix on the same host: recipe-add-path-rule
- internal-only auth-protected: decide-exposure-strategy
Step 4 — Strip Compose keys that Fibe forbids or owns
Remove ports:, container_name, hostname: lines (compiler strips hostname: automatically; the others are surfaced as errors when combined with fibe.gg/zerodowntime). Keep everything else (depends_on, volumes, environment, healthcheck, networks, restart) — pass-through.
→ Load recipe-strip-incompatible-keys. Adjust supporting bits: recipe-named-volumes for persistence volumes, recipe-depends-on for startup ordering, recipe-anchors-and-aliases for shared config blocks, recipe-configs-block for inline config files.
Step 5 — Decide zero-downtime
For exposed HTTP services that can scale horizontally and respond to a health endpoint, enable rolling updates.
→ Load decide-zero-downtime and recipe-zero-downtime-healthcheck.
Step 6 — Extract launch-time variables
Anything the launcher should set (subdomain, image tag, replica counts, credentials defaults) becomes a x-fibe.gg.variables.<NAME> entry. Two interpolation idioms:
- whole-node value:
path:/paths:→ recipe-whole-node-paths - inline-string fragment:
$$var__NAMEinside a Compose string → recipe-inline-variables
Sources of variables to extract:
${ENV_VAR}references already in the input compose → recipe-extract-env-variables- Anything that should differ between launches: hostname, port, replicas, branch, secrets.
Generated/secret values: → Load recipe-random-and-secrets and decide-secrets-and-randoms.
Step 7 — Decide and apply execution mode
If long-running HTTP → done. Otherwise:
- one-shot job → mode-job-trick
- recurring cron → mode-schedule-cron
- on git push/PR → mode-trigger-vcs
Step 8 — Add metadata
x-fibe.gg.metadata.description and x-fibe.gg.metadata.category are required for publishable templates. source_defaults: true is useful for triggered/source-backed templates; runtime will fill trigger_config.repo_url/branch from the source Prop when set.
→ Load recipe-add-metadata for the field details, reference-x-fibe-gg-namespace for full namespace shape.
Step 9 — Validate
- YAML parses.
- Root has
services:. - JSON Schema passes — no unknown
fibe.gg/*labels, all values match label regexes, variable names match^[A-Za-z0-9_]+$, paths match^[A-Za-z0-9_./\[\]-]+$. - Runtime API (
fibe_schema(resource: "compose", operation: "validate", payload: {...})) passes — declared-vs-referenced variables match, prop/marquee/repo URLs resolvable.
→ Load reference-validation-pipeline, then templates-publish-checklist if publishing.
Minimum viable conversion
The smallest valid Fibe template is:
services:
web:
image: nginx:alpine
labels:
fibe.gg/expose: external:80
That gives you a public HTTP route under the Marquee root domain at subdomain web (the default — service name). Add fibe.gg/subdomain to override.
"Just give me the labels I need" cheatsheet
| Intent | Add these labels |
|---|---|
| Public HTTP from prebuilt image | fibe.gg/expose: external:PORT |
| Internal-only (basic auth) HTTP | fibe.gg/expose: internal:PORT |
| Build from my repo | fibe.gg/repo_url, optional fibe.gg/dockerfile, fibe.gg/branch |
| Live-edit dev mode | fibe.gg/repo_url, fibe.gg/source_mount: /app, fibe.gg/start_command, fibe.gg/production: "false" |
| Zero-downtime rollouts | fibe.gg/zerodowntime: "true" on an exposed HTTP service, with optional fibe.gg/healthcheck_* overrides when defaults do not match the app; forbids ports:/container_name |
| One-shot job that defines success | fibe.gg/job_watch: "true" on the watched service + x-fibe.gg.metadata.job_mode: true |
| Pick subdomain at launch | fibe.gg/subdomain: $$var__SUBDOMAIN + variable declared in x-fibe.gg.variables |
| Pick image tag at launch | image: ghcr.io/owner/repo:$$var__TAG + variable declared |
→ For exact value rules of any label above, load reference-fibe-labels.
Worked examples
If the input compose matches one of these shapes, jump straight to the matching playbook — it shows the input/output diff and explains every line:
| Input shape | Playbook |
|---|---|
| Wiki.js (Node app + Postgres) | playbook-wikijs |
| nginx serving static HTML | playbook-nginx-static |
| Ruby on Rails + Postgres + Redis + jobs + websocket | playbook-rails-app |
| Node app with hot-reload dev server | playbook-nodejs-dev |
| Python web (FastAPI/Django/Flask) | playbook-python-app |
| WordPress + MariaDB | playbook-wordpress |
| Generic web app + Postgres | playbook-postgres-app |
| Many services sharing config | playbook-multi-service |
| Scheduled cron job | playbook-cron-scheduled |
| Test runner on every push | playbook-test-runner |
After conversion
- Run
fibe_schema(resource: "compose", operation: "validate", payload: {"compose_yaml": "..."})from MCP. - Then
fibe_templates_launchfor a test launch, orfibe_resource_mutate(resource: "playspec", operation: "create", ...)to import. - Watch for errors against common-errors-and-fixes.
What this skill is NOT
- It is not a YAML linter — use schema/runtime validation.
- It does not cover deploy/operate concerns after a Playground is already running; use the appropriate runtime tool or environment guide for that stage.