A preview environment per git worktree
Create a branch, and the environment is already running at a URL of its own. Made to be driven by an agent as readily as by you.
curl -fsSL https://kobune.1024.works/install.sh | shCreate a branch, and the environment is already running at a URL of its own. Made to be driven by an agent as readily as by you.
curl -fsSL https://kobune.1024.works/install.sh | shkobune.toml
One file, committed, and read by every worktree the repository grows.
kobune initWrites the file above. Nothing else in the repository changes.
kobune new feature/user-authCreates the worktree, and brings the environment up with it.
https://web.feature-user-auth.myapp.localhostOpen it. Nobody picked a port, and the name is the same after a restart.
The services are the ones you already have. What changes is that they are described per worktree rather than per checkout, and that a service can say it belongs to the project instead of the branch.
docker-compose.yml
kobune.toml
kobune init --from-compose writes the right-hand file from the left-hand one. Read the TODOs it leaves before the first kobune up — a docker compose file says things Kobune has no key for, and it marks them rather than guessing.
Nothing here is a recording. It is the output the commands print, drawn as text.
Two branches, two URLs, both still running. Nobody picked a port.
── shell-a ── $ kobune init ╭ init ─────────────────────────────────────╮ │ created ~/myapp/kobune.toml │ │ project myapp │ │ │ │ › bring the environment up with kobune up │ ╰───────────────────────────────────────────╯ $ kobune up ✓ preparing the network ✓ pulling image node:22 ✓ starting web ✓ waiting for web ╭ myapp / (main) ───────────────────────────╮ │ main ~/myapp │ │ │ │ ● web ready https://web.myapp.localhost │ ╰───────────────────────────────────────────╯ $ kobune new feature/user-auth ✓ creating worktree feature/user-auth ✓ starting web ✓ waiting for web ╭ myapp / feature-user-auth ──────────────────────────────────╮ │ feature/user-auth ~/myapp.wt/feature-user-auth │ │ │ │ ● web ready https://web.feature-user-auth.myapp.localhost │ ╰─────────────────────────────────────────────────────────────╯ ── web-a ── https://web.feature-user-auth.myapp.localhost ── shell-a ── $ cd ~/myapp.wt/feature-user-auth $ kobune logs -f web │ ready in 412 ms │ GET /sign-in 200 ── shell-b ── $ kobune new fix/checkout-total ✓ creating worktree fix/checkout-total ── shell-a ── │ GET /assets/app.js 200 ── shell-b ── ✓ starting web ✓ waiting for web ╭ myapp / fix-checkout-total ──────────────────────────────────╮ │ fix/checkout-total ~/myapp.wt/fix-checkout-total │ │ │ │ ● web ready https://web.fix-checkout-total.myapp.localhost │ ╰──────────────────────────────────────────────────────────────╯ ── web-b ── https://web.fix-checkout-total.myapp.localhost ── shell-a ── │ POST /sign-in 302 ── shell-b ── $ kobune ls ╭ workspaces ──────────────────────────────────────╮ │ WORKSPACE SERVICES BRANCH │ │ (main) 1/1 main │ │ feature-user-auth 1/1 feature/user-auth │ │ fix-checkout-total 1/1 fix/checkout-total │ ╰──────────────────────────────────────────────────╯
The same commands, with --json for the parts a program reads. A failure exits with a code that says what kind it was, so an agent gets a reason rather than an empty response.
Working with AI agentsOne of these goes in [runtime] default, in kobune.toml. Kobune arranges the containers; the runtime is what actually starts them.
dockerThe default, and the better supported of the two.Kobune calls the Docker API rather than the docker command, so Docker Desktop, OrbStack and colima all work.appleSupported. Needs macOS 26 or later, with container system start already run.Every container gets its own address, so nothing is published to the host and two worktrees cannot collide on a port.firecrackerPlanned.