Starting a project locally should take one command.

fed.yaml is the executable setup for your project. fed installs dependencies, applies migrations, starts native processes and containers in dependency order, waits for health checks, and gives every service and task the ports, URLs, and credentials it needs.

Run tasks with the services they need

Define Studio, seed, reset, and test commands under scripts. fed starts missing dependencies, passes their ports and credentials to the task, then stops what it started.

Isolate every worktree

Run fed isolate enable once. Each checkout gets its own declared ports, container names, named volumes, generated secrets, and state.

Sync dev secrets through the optional team vault

Add the secrets once and link the repo with fed link org/project. Teammates sign in with GitHub, then fed start injects the values their local services need.

Read the getting-started guide

Put local setup in fed.yaml.

Define native processes, Docker containers, existing Compose services, dependencies, health checks, and typed values in one graph. Every checkout runs the same setup with fed start.

Install once, migrate on every start
install handles one-time dependency setup. migrate handles repeatable work such as applying a database schema.
Wait for readiness
depends_on waits for the healthcheck to pass, not just for the container to exist. fed starts the API only after Postgres reports healthy.
Resolve typed values once
{{API_PORT}} is declared one time. It reaches the process environment, the healthcheck URL, and any script that needs it. That is what lets fed hand a different port to each worktree without you editing a line.
Configuration reference
fed.yamla complete local stack
parameters:
  API_PORT: { type: port, default: 8080 }
  DB_PORT: { type: port, default: 5432 }
  DB_PASSWORD: { type: string, default: dev-password }
  DATABASE_URL:
    type: string
    default: "postgres://app:{{DB_PASSWORD}}@localhost:{{DB_PORT}}/app"

services:
  database:
    image: postgres:16-alpine
    ports: ["{{DB_PORT}}:5432"]
    volumes: ["app-data:/var/lib/postgresql/data"]
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: "{{DB_PASSWORD}}"
      POSTGRES_DB: app
    healthcheck:
      command: pg_isready -U app -d app

  api:
    process: npm run dev
    depends_on: [database]
    install: npm install
    migrate: npm run db:migrate
    startup_message: "API running on http://localhost:{{API_PORT}}"
    environment:
      PORT: "{{API_PORT}}"
      DATABASE_URL: "{{DATABASE_URL}}"
    healthcheck:
      http_get: "http://localhost:{{API_PORT}}/health"

scripts:
  db:studio:
    depends_on: [database]
    environment:
      DATABASE_URL: "{{DATABASE_URL}}"
    script: npm run db:studio

entrypoint: api

Give every local task the services it needs.

Put database tools, seed and reset commands, and tests under scripts. A task can reuse the running stack or request fresh dependencies. For example, fed run test:integration can start an isolated database, pass its URL to the test process, and remove it afterward.

fed.yamlan isolated integration test
scripts:
  test:integration:
    isolated: true
    depends_on: [database]
    environment:
      DATABASE_URL: "{{DATABASE_URL}}"
    script: npm run test:integration
Reuse running services
A normal script leaves existing services alone. If it had to start a dependency, it stops that dependency when the script finishes.
Start a separate stack
isolated: true gives direct image-backed services fresh ports, containers, and named volumes without disturbing your development stack.
Clean up automatically
The throwaway stack is removed after success, failure, or Ctrl+C.

For isolated scripts, use direct image: services. Compose-backed services cannot run as a second isolated Compose project inside the same checkout.

Scripts and isolated test runs

Give every worktree its own local stack.

Run agents in parallel without port or container collisions. fed uses the checkout directory as the isolation boundary, so no editor plugin or agent integration is required.

Declared ports
Every type: port parameter gets a fresh value in an isolated checkout, and the commands that use it receive the new one.
Containers, volumes, and state
Direct Docker container names, named volumes, generated secrets, and fed’s own state are scoped to the checkout.
Your main checkout is untouched
It keeps its ports and its data. Enabling isolation in a worktree does not migrate or disturb anything already running.
AGENTS.mdor CLAUDE.md
Run `fed isolate enable` before any other fed command in a new worktree.
Run project tasks through fed so they receive this worktree's ports and credentials.
Run `fed clean` before removing the worktree.

fed cannot remap a port hardcoded inside a command, URL, or Compose file. Declare it as a type: port parameter to make it isolatable. Convert only the ports that collide.

Worktrees and coding agents

Use your existing compose.yaml.

You don’t have to repeat its services in fed.yaml. Include the file once and fed adds its services to the same graph as your native application.

fed.yamlreusing an existing compose.yaml
compose:
  - ./compose.yaml

services:
  api:
    process: npm run dev
    depends_on: [postgres]

Hardcoded host ports work for one checkout. To run the same service in two checkouts, replace the host port with ${VAR} and declare that variable as type: port in fed.yaml. Pass it through the Compose import; Compose substitutes the allocated value without rewriting the file. Leave the port hardcoded and the second checkout stops on the bind instead of sharing the first checkout’s container.

One fed.yaml can include as many Compose files as you like. Add a namespace when two projects use the same service names; fed still starts them together as separate Compose projects.

Using fed with Docker Compose

Share development secrets through the team vault.

A missing API key can stop a new checkout from starting. Add development secrets once, link the repo with fed link org/project, and have your teammate sign in with GitHub. After that, fed start resolves the values from your team’s vault.

$ fed login
Signed in as you@example.com · org: acme
$ fed start
resolved 4 secrets from acme/web
  • Values stay out of the repository, server logs, and list responses.
  • Fetched values are cached in an owner-only, Git-ignored file so the stack still starts offline. Set secret_cache: memory to keep nothing on disk.
  • The CLI can read secrets but cannot write them. Secret writes are dashboard actions. Removing a member blocks new fetches immediately.
  • Removal cannot erase values already cached on that person’s machine, so rotate anything they had access to.
Free for three people then €8 per seat per month

Built for development credentials. It is not a production secrets manager, an end-to-end encrypted vault, or a compliance product. The open-source CLI and local secret generation work without an account; team sync is optional.

How team secrets work

Use fed when:

  • New teammates have to follow manual setup instructions in a README.
  • Your stack mixes native processes with containers and Compose services.
  • Your services must start in order based on health, not sleep 5.
  • Local tasks need databases, queues, or other services to be running first.
  • You run more than one checkout of the same project at once: worktrees, branches, or agents.

fed runs development environments. It does not deploy applications.

Why I built fed.

I built fed because I want local development to be painless. I hope that’s how you find it too. If not, open an issue or fork it. The CLI is MIT licensed.