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.
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
installhandles one-time dependency setup.migratehandles repeatable work such as applying a database schema.- Wait for readiness
depends_onwaits 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.
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.
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: truegives 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.
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: portparameter 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.
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.
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.
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.
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.
- 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: memoryto 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.
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 workUse 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.