Skip to content

kelpie.json

One file at the root of your repo tells kelpie how the project runs for a feature or a review. Everything in it is optional, and a repo without one still gets the branch, the worktree and the session - just no dev server.

{
"setup": "pnpm install",
"apps": [
{ "name": "api", "command": "pnpm api --port {port}" },
{
"name": "web",
"command": "API_URL=http://localhost:$KELPIE_PORT_API pnpm dev --port {port}",
"proxy": true
}
],
"ready": "/health",
"teardown": "pnpm db:drop"
}
Key
setup Runs once in the new worktree before any app starts. Leave it out and kelpie infers the install from your lockfile; "" runs nothing.
apps The processes to run, each in its own tmux window. {port} is a free port picked for that app.
apps[].env Extra environment for that app, with the same substitutions.
apps[].proxy Marks the app the feature’s link opens. Exactly one app carries it; without a mark, the first one does.
ready The path kelpie knocks on before it shows the link, so the link never opens a server that is still starting. Default /.
teardown Runs in the worktree just before it is removed, for the state kelpie cannot see: a database your dev server created, a volume, a registration.
extraPorts Other ports the dev server picks itself, shared to your phone.

Apps find each other through KELPIE_PORT_<NAME>: every app sees every sibling’s port in its environment. An env value may use {tailnetHost}, this Mac’s Tailscale name, for a dev server that has to be told which host to accept.

A file that does not parse, or an app with no name or no command, reads the same as no file at all, so New keeps working while someone is halfway through an edit.

An older flat form still works, and runs as one app:

{
"setup": "pnpm install",
"dev": "pnpm dev --port {port}",
"url": "http://localhost:{port}",
"ready": "/"
}