Coasts (Containerized Hosts) is a CLI tool with a local observability UI for running multiple isolated instances of a full development environment on a single machine. It works out of the box with your current setup: no changes to your existing application code, just a small Coastfile at your repo root. If you already use Docker Compose, Coasts can boot from your existing docker-compose.yml; if you do not use Docker or Compose, Coasts works just as well.
Build once and run N instances with whatever volume and networking topology your project needs. Check out one coast at a time to bind canonical ports to your host, and use dynamic ports to peek at any other worktree.
Coasts is agnostic to AI providers and agent harnesses. The only host requirement is Git worktrees, so you can switch tools without changing how you work and without any harness-specific environment setup.
Coasts is also offline-first with no hosted service dependency, so there is no vendor lock-in risk: even if we disappeared, your local workflow would keep running.
For the full user-facing documentation, see the Coasts docs.
To contribute, read the contributing guide.
Note: Coasts is currently macOS-specific. General Linux support is coming shortly.
curl -fsSL https://coasts.dev/install | sh- Rust (stable toolchain)
- Docker
- Node.js
- socat (
brew install socaton macOS) - Git
cargo build --releaseBinaries are placed in target/release/:
coast-- the CLI clientcoastd-- the background daemon
# Start the daemon
coastd --foreground &
# In a project with a Coastfile and docker-compose.yml:
coast build
coast run main
coast run feature-x --worktree feature/x
# Swap which instance owns the canonical ports
coast checkout main
coast checkout feature-x
# Inspect
coast ls
coast ps main
coast logs main
coast ports main
# Clean up
coast rm main
coast rm feature-xIf you have coast globally installed, the production daemon occupies ~/.coast/ and port 31415. The workspace builds separate coast-dev and coastd-dev binaries that use ~/.coast-dev/ and port 31416, so the two never conflict.
Run the setup script once to build everything and symlink the dev binaries into ~/.local/bin:
./dev_setup.shThis builds the web UI, compiles the workspace, and creates coast-dev / coastd-dev symlinks. On first run it adds ~/.local/bin to your PATH — restart your shell or source ~/.zshrc to pick it up.
You'll want three terminals:
Terminal 1 — dev daemon:
coast-dev daemon start # start in background
# or: coastd-dev --foreground # start in foreground for log outputAfter Rust changes are rebuilt by make watch, restart the daemon to pick them up:
coast-dev daemon restartTerminal 2 — Rust rebuild on save:
make watchThis runs cargo watch and recompiles the workspace whenever Rust source files change. After a rebuild completes, restart the daemon in Terminal 1.
Terminal 3 — web UI with hot reload:
cd coast-guard
npm install
npm run dev:coast-devThis starts the Vite dev server on http://localhost:5173 with hot module replacement, proxying /api requests to the dev daemon at localhost:31416.
Use
npm run dev(without:coast-dev) if you're developing the UI against a production daemon on port 31415.
The Makefile is the primary entry point for development tasks:
| Command | What it does |
|---|---|
make lint |
Check formatting (cargo fmt --check) and run cargo clippy |
make fix |
Auto-format and auto-fix clippy warnings |
make test |
Run the full unit test suite across all workspace crates |
make check |
make lint + make test in sequence |
make coverage |
Generate an HTML coverage report and open it |
make watch |
Rebuild on source changes (requires cargo-watch) |
The web UI depends on TypeScript types generated from Rust structs via ts-rs. After changing any Rust types that are used by the UI, regenerate the bindings:
cd coast-guard
npm run generate:typesThis runs cargo test -p coast-core export_bindings and rebuilds the barrel file in src/types/generated/.
The docs viewer in the UI reads from a generated manifest. After changing any markdown files in docs/, regenerate it:
cd coast-guard
npm run generate:docsTranslation and search index generation are centralized Python scripts invoked via the Makefile:
make docs-status # show which docs need translation
make translate LOCALE=es # translate docs for one locale
make translate-all # translate all supported locales
make doc-search LOCALE=en # generate search index for one locale
make doc-search-all # generate search indexes for all localesBoth scripts read OPENAI_API_KEY from the environment or from .env in the project root. See .env.example.
make testRuns cargo test --workspace across all crates.
Integration tests live in integrated-examples/ and exercise full end-to-end coast workflows. They are useful for validating real behavior but come with practical costs: they require Docker running, socat installed, and a release build. Each test spins up real DinD containers, so a full run can consume significant disk space and you may need to docker system prune periodically to reclaim it.
For the full list of tests, prerequisites, and cleanup guidance, see the integrated-examples README.
Quick usage:
integrated-examples/test.sh # run all tests
integrated-examples/test.sh test_checkout test_secrets # run specific tests
integrated-examples/test.sh --include-keychain # include macOS Keychain testcoast/
coast-cli/ # Thin CLI client, talks to daemon over unix socket
coast-daemon/ # coastd background process (handlers, state DB, port manager)
coast-core/ # Shared types, Coastfile parsing, protocol definitions
coast-secrets/ # Secret extraction, encryption, keystore
coast-docker/ # Docker API wrapper, DinD runtime, compose interaction
coast-git/ # Git worktree management
coast-guard/ # Web UI (React + Vite), served by the daemon
coast-i18n/ # i18n locale files for the CLI
scripts/ # Python build scripts (translation, search index generation)
docs/ # User-facing documentation (English + translations)
integrated-examples/ # Example projects and shell-based integration tests
