carte 0.6.0

Runs your apps' processes on demand behind *.localhost hostnames, one stack per git worktree
Documentation

carte

Run your local web apps à la carte: visit https://myapp.localhost and carte starts the app, then stops it once you're done with it.

  • Many apps at once: carte stops the least recently used ones to keep memory in check.
  • The whole Procfile: asset watchers, job workers and schedulers start and stop with the web server.
  • A hostname per worktree: a worktree in a feature-x folder runs at https://feature-x.myapp.localhost.
  • Projects and stacks: apps that work together start together, and worktrees with the same name form a stack.
  • HTTPS everywhere, with a local certificate authority.
  • A terminal UI for state, logs and controls.
  • Sharing apps on the public internet through Cloudflare Tunnel or ngrok.
  • Kubernetes Services at hostnames like https://grafana.monitoring.prod.localhost, forwarded when you visit.

carte runs on macOS and Linux.

Install

With Homebrew:

brew install elektronaut/tap/carte

Or with Cargo:

cargo install carte

Setup

carte setup --dry-run   # show what it will do
carte setup

Setup runs once per machine and asks for your password where needed. It:

  • creates a certificate authority for carte's hostnames and trusts it
  • runs the daemon on ports 80 and 443. On Linux, this lets every program use ports from 80 up.

Apps are served under .localhost. To also serve them under .test, run carte setup --tld test.

carte setup --check shows what's in place, and carte setup --uninstall removes it.

Coming from puma-dev

carte setup offers to replace puma-dev, and to keep its .test hostnames. To turn the apps linked in ~/.puma-dev into carte projects:

carte import puma-dev

docs/puma-dev.md compares the two and covers the switch in detail.

Projects

A project is a group of apps that belong together. Each project is a file in ~/.config/carte/projects/. For a single app, this is enough:

cd ~/code/myapp
carte project add .

That writes ~/.config/carte/projects/myapp.toml with one line:

root = "~/code/myapp"

and the app is at https://myapp.localhost.

carte runs the processes in the app's Procfile.dev or Procfile. Without one, it runs a Rack app with Puma and a Node app with its dev script.

A project can also hold several apps that work together. Say the acme product is three repos in ~/work, next to some unrelated ones:

~/work/
├── acme-accounts/    Rails API
├── acme-billing/     Rails API
├── acme-frontend/    Vite app calling the other two
└── side-project/

One file makes them a project:

# ~/.config/carte/projects/acme.toml
root = "~/work"
include = "acme-*"
strip_prefix = "acme-"

[env]
"{{app.name | upper}}_URL" = "{{url:app}}"

[apps.acme-frontend]
depends_on = ["billing", "accounts"]
  • include picks the three acme-* repos as apps, and leaves side-project out.
  • strip_prefix shortens their hostnames to accounts.acme.localhost, billing.acme.localhost and frontend.acme.localhost.
  • [env] gives every app the others' URLs, like ACME_BILLING_URL=https://billing.acme.localhost.
  • depends_on starts billing and accounts along with the frontend.

A repo can also carry its own defaults in a carte.toml.

docs/configuration.md is the reference for every setting.

Worktrees and stacks

Worktrees with the same folder name form a stack: their apps run together and call each other. Say you add a worktree to billing:

cd ~/work/acme-billing
git worktree add ~/worktrees/acme-billing/feature-x -b feature-x

Now https://billing.feature-x.acme.localhost runs the worktree. The frontend has no feature-x worktree, so https://frontend.feature-x.acme.localhost runs its main checkout, calling the feature-x billing. Remove the worktree, and carte stops it.

carte leaves databases alone. For separate data per worktree, use CARTE_CHECKOUT in database.yml or similar.

Day to day

Once a project is added, there's little left to do. Visiting an app starts it, and it stops when you stop using it. New worktrees and changes to project files are picked up by themselves.

carte restart   # the app you're in, to apply changes now
carte attach    # answer a debugger prompt; ctrl-q d detaches
carte           # open the terminal UI

touch tmp/restart.txt restarts an app too.

docs/cli.md covers the rest of the CLI. Coding agents can use carte through its MCP server; see docs/mcp.md.

Sharing

carte setup --share dev.example.com   # once, with Cloudflare Tunnel or ngrok
carte share billing@feature-x --auth --ttl 2h

Sharing is always explicit, and only shared apps are reachable. See docs/sharing.md.

Kubernetes

carte can forward to a Kubernetes cluster's Services, like kubectl port-forward without the command. Give the cluster a project file that names its kubeconfig context:

# ~/.config/carte/projects/prod.toml
kube = { context = "prod" }

The Service grafana in the monitoring namespace is then at https://grafana.monitoring.prod.localhost, or https://grafana.prod.localhost if no other namespace has a grafana.

carte import kube writes a project file for each context you pick. See Kubernetes.

Configuration

Machine settings live in ~/.config/carte/config.toml, and every key is optional:

tld = "test"
idle_timeout = "15m"

carte reloads it when it changes. If a file is broken, carte keeps the last working version and shows the error.

Alternatives

carte is heavily inspired by puma-dev, which is a good choice if you just want a web server per app.

Overmind and process-compose run a project's processes in your terminal. They suit working on one app at a time.

portless gives dev servers .localhost names, but you start and stop them yourself.

Contributing

See CONTRIBUTING.md.

License

MIT. See LICENSE.