{
  "markdown": "<div align=\"center\">\n\n<img src=\"site/binky.svg\" alt=\"\" width=\"88\" />\n\n# Binky\n\n**One isolated local world per git worktree — ports, env, database, URLs.**\n\nSo a swarm of coding agents runs in parallel on one machine without anything colliding.\n\n[![CI](https://github.com/andreisilva1/binky/actions/workflows/ci.yml/badge.svg)](https://github.com/andreisilva1/binky/actions/workflows/ci.yml)\n[![PyPI](https://img.shields.io/pypi/v/binky)](https://pypi.org/project/binky/)\n[![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](pyproject.toml)\n[![License](https://img.shields.io/badge/license-Apache%202.0-green.svg)](LICENSE)\n\n[Docs](https://binky-dev.vercel.app/) · [Quickstart](#quickstart) · [Adapters](#adapters) · [Commands](#commands) · [For agents](#for-agents) · [How it works](#how-it-works) · [Troubleshooting](TROUBLESHOOTING.md)\n\n</div>\n\n---\n\n`docker-compose` was built for one process at a time. Binky is built for fifteen at once.\n\n> **Status: alpha.** The core works end to end — worktree isolation, ports, adapters, supervision,\n> reconciler, admission, proxy, HTTPS. The config format is stable; the CLI may still move.\n\n## The problem\n\nYou point three agents at the same repo. The second one runs `pnpm dev` and gets `EADDRINUSE`.\nThe third runs your migrations and drops the table the first was reading. You start hand-editing\n`.env` files, and now you're the scheduler.\n\nBinky is the scheduler. One `binky up <branch>` per agent, and each gets its own ports, its own\ndatabase, its own URLs — from the same committed config.\n\n## Install\n\nPython 3.11+ and git, on **Linux or Windows** — the two platforms Binky is tested on for real.\nmacOS isn't a supported target yet; a well-tested port would be a welcome [contribution](CONTRIBUTING.md).\n\n```bash\nuv tool install binky          # or: pipx install binky\nbinky --version\n```\n\nOr from a clone, to run the unreleased `main` or to hack on it:\n\n```bash\ngit clone https://github.com/andreisilva1/binky && cd binky\nuv tool install .               # or: pipx install .\n```\n\nAdapters that need a driver ship as extras — installing Binky for Redis shouldn't pull `boto3`:\n\n```bash\nuv tool install \"binky[postgres]\"        # or [redis], [mysql], [mongodb], [s3], [kafka]\nuv tool install \"binky[all-adapters]\"    # the whole matrix\n```\n\n## Quickstart\n\nAlready have a `docker-compose.yml`? Start from it:\n\n```bash\nbinky init                 # writes a binky.toml you can read and edit\nbinky check                # validate it\n```\n\nOr write it by hand — this is the whole config:\n\n```toml\n[project]\nname = \"acme\"\n\n[services.web]\ncmd = \"pnpm dev --port ${self.port}\"\nurl = \"web\"                              # → web.<worktree>.acme.localhost\ndepends_on = [\"api\"]\nenv = { API_URL = \"${api.url}\" }\n\n[services.api]\ncmd = \"go run ./cmd/server\"\nurl = \"api\"                              # asking for a URL is what asks for a port\ndepends_on = [\"db\"]\nenv = { DATABASE_URL = \"${db.url}\" }\n\n[services.db]\nadapter = \"postgres\"                     # a private database per worktree\nadmin_url = \"${env.POSTGRES_ADMIN_URL}\"\nmigrate = \"make migrate\"\nseed = \"make seed\"\nclone_from = \"golden\"                    # migrate+seed once, then copy per worktree\n```\n\nThen bring worktrees up in parallel:\n\n```console\n$ binky up login-fix\n  api  pid 16560  :4846\n  web  pid 29732  :4504\n✓ up: login-fix (2 service(s))\n\n$ binky up checkout-v2\n  api  pid 21768  :4137\n  web  pid 46336  :4605\n✓ up: checkout-v2 (2 service(s))\n\n$ binky status\nacme\n  checkout-v2  [running]\n      api  :4137\n      web  :4605\n  login-fix  [running]\n      api  :4846\n      web  :4504\n```\n\nTwo branches, four processes, four ports nobody chose by hand. Hand a worktree's coordinates to\nwhoever needs them — a shell, an agent, a test run:\n\n```console\n$ binky env login-fix --dotenv\nWEB_URL=http://web.login-fix.acme.localhost\nAPI_URL=http://api.login-fix.acme.localhost\n```\n\nAnd the rest of the lifecycle:\n\n```bash\nbinky down login-fix       # pause (keeps files + ports); `up` again is instant\nbinky remove login-fix     # destroy it (refuses if there are uncommitted changes)\n```\n\nNothing is hardcoded and nothing is discovered at runtime: every process boots already knowing the\nwhole port map, its own and its dependencies'.\n\n> **One rule to internalise.** A service gets a port when it declares `url` or `ports` — asking is\n> explicit. A service with neither gets none, which is correct for a worker or a one-shot job, and a\n> trap if you then write `${self.port}` in its `cmd`. Unknown tokens are left alone rather than\n> blanked, so the literal `${self.port}` reaches the shell and the process dies on its own argument\n> parsing. `binky check` warns when a service does this.\n\n## What it costs to run N worlds\n\nThe claim is that N isolated worlds shouldn't cost N times one world. Measured, not asserted —\n`benchmarks/worlds.py` is in this repo and reproduces the table below (`postgres:16`, 200,000 rows\nper world, Docker Desktop on Windows 11):\n\n| worlds | RAM: a container each | RAM: Binky | time: a container each | time: Binky |\n| ---: | ---: | ---: | ---: | ---: |\n| 1 | 150 MiB | 174 MiB | 6s | 4s |\n| 2 | 298 MiB | 182 MiB | 11s | 6s |\n| 4 | 596 MiB | 228 MiB | 20s | 10s |\n| 8 | 1197 MiB | 295 MiB | 40s | 16s |\n\n**The 8th world costs +150 MiB and +4.8s as its own container, or +17 MiB and +1.7s under Binky.**\n\nRead the first row too. At **one** world Binky is behind — it pays for a server plus a golden\ntemplate nobody is using yet, and only earns that back on the second. And **disk is not a win**:\n`CREATE DATABASE ... TEMPLATE` is a file copy, not copy-on-write, so every world is still a full\ncopy of the rows. What Binky removes is the *server* per world, not the *bytes* per world. It also\ndoesn't make your own app processes cheaper — one dev server per worktree costs the same either way.\n\n```bash\npython benchmarks/worlds.py --sweep 1,2,4,8 --rows 200000\n```\n\n## When you don't need Binky\n\nWorth saying plainly, because the first row of that table already says it:\n\n- **One branch at a time.** If you never have two worlds up at once, Binky is a daemon and a config\n  file you didn't need. Use it when the second agent shows up.\n- **Everything already runs in containers, and that's fine.** Binky's win is removing the *server*\n  per world. If your compose stack is small enough that N copies fit comfortably, there's nothing\n  to reclaim.\n- **You need real isolation, not local isolation.** Binky runs your commands as you, on your\n  machine. It is not a sandbox — see [Security](#security).\n\n## Adapters\n\nAn adapter carves an isolated **slice** of one shared server — a database, a key prefix, a bucket —\ninstead of running one server per worktree. **16 names, 10 implementations, every one exercised\nagainst a real server in CI.**\n\n| slice | adapters |\n| --- | --- |\n| a database | `postgres` · `mysql` · `mariadb` · `percona` · `mongodb` · `clickhouse` |\n| a key prefix | `redis` · `valkey` |\n| a bucket / prefix | `s3` · `minio` |\n| a vhost / topic prefix | `rabbitmq` · `kafka` · `redpanda` |\n| a collection | `qdrant` |\n| an index prefix | `elasticsearch` · `opensearch` |\n\nProtocol-compatible names share one implementation rather than a copy of it — `valkey` is the Redis\nadapter, `percona` is the MySQL one, `opensearch` is the Elasticsearch one.\n\n### `clone_from`: pay for migrate+seed once\n\nWith `clone_from`, the first `binky up` builds a **golden template** — provision, migrate, seed —\nand every worktree after that is a copy of it. The template is keyed by a hash of your `migrate` and\n`seed` commands, so changing either rebuilds it automatically.\n\nSupported where the server can copy a slice server-side (`postgres`, `mysql`, `mariadb`, `percona`,\n`mongodb`). Where it isn't, or where a clone fails on something environmental — a client binary too\nold to authenticate, a missing grant — Binky **falls back** to provision+migrate+seed for that\nworktree and logs `clone_fallback`. Correctness never depends on cloning; only speed does.\n\nOne sharp edge worth knowing: the hash covers the migrate and seed *commands*, not the files they\ncall. Editing a script those commands run does not rebuild the template — delete its marker under\n`~/.binky/golden/` to force one.\n\n### Writing your own\n\nTwo tiers, one contract. Both implement the same four verbs:\n\n| verb | does |\n| --- | --- |\n| `provision(slice)` | create the slice (`CREATE DATABASE ...`) |\n| `resolve(slice)` | return its address → `${db.url}` |\n| `teardown(slice)` | destroy it |\n| `capabilities()` | what it supports, e.g. `{\"clone\": true}` |\n\n**In-process** adapters are Python classes in this repo, discovered by name. **External** adapters\nare executables in any language, discovered as `binky-adapter-<name>` on `PATH` and driven over a\none-shot subprocess + JSON protocol:\n\n```console\n$ binky-adapter-filestore provision   <<< '{\"slice\": \"acme_login-fix\", \"config\": {}}'\n{\"ok\": true}\n$ binky-adapter-filestore resolve     <<< '{\"slice\": \"acme_login-fix\", \"config\": {}}'\n{\"ok\": true, \"address\": \"file:///tmp/binky-filestore/acme_login-fix\"}\n```\n\nPython authors get the protocol for free — `binky.adapter_sdk.run()` bridges a normal adapter class\nto it. See [examples/adapters/filestore.py](examples/adapters/filestore.py) for a complete,\ndependency-free one in 30 lines.\n\n## Commands\n\n| Command | What it does |\n|---|---|\n| `binky init [dir] [--force]` | Write a starting `binky.toml` from `docker-compose.yml` + `.env` |\n| `binky check [path]` | Validate a `binky.toml` and flag footguns |\n| `binky up <name> [--group g]` | Create/use the branch's worktree, allocate ports, provision resources, start services |\n| `binky reload <name> [--group g]` | Restart in place — stop, then bring back up on the same ports and data |\n| `binky down <name>` | Stop the worktree's processes (keeps its files and ports) |\n| `binky remove <name> [--force]` | Destroy the worktree — stop, drop its slices, remove its files |\n| `binky status [.]` | List worktrees (grouped by project); `.` = current project only |\n| `binky env <name> [--dotenv]` | Print a worktree's exposed coordinates, for you or an agent |\n| `binky curl <name> <service> [path]` | Call a service through the proxy with the `Host` header filled in (`-X`/`-d`/`-H`/`-i`/`-f`) |\n| `binky verify <name>` | Run the project's `agents.verify` checks; exits non-zero on failure |\n| `binky logs <name>` | Print a worktree's captured service logs |\n| `binky gc` | Sweep orphaned adapter slices a crash left half-provisioned |\n| `binky config` | Show the machine-global settings (RAM/disk reserves, proxy ports) |\n| `binky reserve [--ram %] [--disk gb]` | Set how much RAM/disk Binky permanently keeps free |\n| `binky port [--proxy p] [--https p]` | Set the proxy/HTTPS ports |\n| `binky dashboard` | Live TUI of every worktree |\n| `binky doctor` | Diagnose the install and daemon; exits non-zero if something is wrong |\n| `binky metrics` | Point-in-time daemon metrics as JSON |\n| `binky mcp` | Run the MCP server so agents can call Binky's verbs as tools |\n| `binky daemon start\\|stop\\|status` | Manage the background daemon |\n\n## For agents\n\n`binky mcp` speaks MCP over stdio, exposing `up`, `down`, `status`, `env` and `verify` — the same\nverbs the CLI calls, against the same daemon.\n\nIn Claude Code, one line wires it up:\n\n```bash\nclaude mcp add binky -- binky mcp\n```\n\nAny other client that speaks the protocol takes the same stdio server as a config block — the same\none everywhere, only the file differs:\n\n```json\n{ \"mcpServers\": { \"binky\": { \"command\": \"binky\", \"args\": [\"mcp\"] } } }\n```\n\nTo run it with nothing installed, hand it to `uvx` instead — `claude mcp add binky -- uvx --from\n\"binky[mcp]\" binky mcp`, or as a block, `\"command\": \"uvx\"`, `\"args\": [\"--from\", \"binky[mcp]\",\n\"binky\", \"mcp\"]`. For a project whose worktrees provision adapter slices, add those extras too, e.g.\n`binky[mcp,postgres]` (or `binky[mcp,all-adapters]` for the whole matrix).\n\nBinky is published in the [MCP Registry](https://registry.modelcontextprotocol.io) as\n`io.github.andreisilva1/binky`, so registry-aware clients can discover and install it from there.\n\nFor the tool list and an agent-oriented walkthrough, see [AGENTS.md](AGENTS.md).\n\n<!-- mcp-name: io.github.andreisilva1/binky -->\n\n\n## How it works\n\nA single machine-global daemon sits between your worktrees and the machine:\n\n```mermaid\nflowchart TB\n    CLI[\"agents · CLI · MCP\"] -->|\"up · down · status\"| D((\"binky daemon<br/>machine-global\"))\n\n    D --> ADM{\"admission<br/>RAM · disk · max_parallel\"}\n    ADM -.->|\"no room → queue / suspend\"| Q[\"waiting\"]\n    ADM -->|\"admit\"| W[\"worktree<br/>git worktree per name\"]\n    W --> P[\"ports<br/>whole map before start\"]\n    P --> R[\"adapters<br/>isolated slice per worktree\"]\n    R --> S[\"supervisor<br/>depends_on · health · logs\"]\n    S --> X[\"proxy<br/>svc.worktree.domain → port\"]\n\n    D -.->|\"reads · writes\"| ST[(\"~/.binky<br/>SQLite + settings\")]\n```\n\n1. **Worktree** — creates/uses a git worktree per name.\n2. **Ports** — a global allocator assigns every process a port *before anything starts* and injects\n   the whole map, so nothing collides (`${self.port}`, `${api.url}`, …).\n3. **Resources** — adapters carve an isolated slice per worktree and tear it down on remove.\n4. **Supervision** — starts services in `depends_on` order, waits for health, captures logs.\n5. **Proxy** — routes `<service>.<worktree>.<domain>` to the right port (WebSockets/HMR included).\n   Set `https = true` and Binky fronts it with Caddy for TLS via a local CA, when Caddy is on PATH.\n6. **Admission** — a FIFO queue that only starts a worktree when the machine has room: fewer than\n   `max_parallel` running **and** enough free RAM (a percentage kept in reserve) **and** enough free\n   disk (a fixed GB headroom). If a running swarm later crosses the RAM reserve, the daemon suspends\n   the newest worktree to relieve pressure and resumes it — in fairness order — once room returns.\n   Tune the reserves with `binky reserve`; see them with `binky config`.\n\nState lives in `~/.binky/` (a SQLite registry plus a settings store, migrated in place across\nupgrades). Nothing runs in the cloud, and Binky never phones home.\n\n## Examples\n\n- [examples/hello](examples/hello) — the smallest possible project.\n- [examples/rag](examples/rag) — vector search where each worktree gets its own embedded corpus.\n  The case where sharing a database actually hurts: two agents re-indexing, one `TRUNCATE`.\n- [examples/adapters/filestore.py](examples/adapters/filestore.py) — an external adapter, complete.\n\n## Security\n\nBinky runs **your** commands on **your** machine as **you**. It is a developer tool for a\nsingle-user workstation, not a multi-tenant sandbox — a `binky.toml` is as trusted as a `Makefile`,\nand `binky up` on a repo you don't trust is `make` on a repo you don't trust. The threat model and\nwhat's explicitly out of scope are written down in [SECURITY.md](SECURITY.md).\n\nThe one rule worth repeating here: **never put a credential inline in a committed `binky.toml`**.\nUse `${env.NAME}` or an `env_file`. `binky check` warns when you do, and `binky init` never writes\none.\n\n## Something not working?\n\n[TROUBLESHOOTING.md](TROUBLESHOOTING.md) covers the cases that actually come up — a port held from\noutside, a dev server ignoring `$PORT`, a stale golden template, `*.localhost` not resolving. Start\nwith `binky doctor`.\n\n## Development\n\n```bash\npython -m venv .venv && . .venv/bin/activate   # or .venv\\Scripts\\activate on Windows\npip install -e \".[dev,all-adapters]\"\npytest\nruff check src tests examples benchmarks\n```\n\nAdapter integration tests skip unless you point them at a real server —\n`BINKY_TEST_PG`, `BINKY_TEST_REDIS`, `BINKY_TEST_MYSQL`, `BINKY_TEST_MONGO`, `BINKY_TEST_S3`,\n`BINKY_TEST_RABBITMQ`, `BINKY_TEST_KAFKA`, `BINKY_TEST_QDRANT`, `BINKY_TEST_CLICKHOUSE`,\n`BINKY_TEST_ELASTICSEARCH`. CI provides all of them.\n\n## Contributing\n\nBug reports, new adapters, and PRs are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) to\nget set up, and [ARCHITECTURE.md](ARCHITECTURE.md) for a map of the internals.\n\n## License\n\nApache-2.0 — see [LICENSE](LICENSE) and [NOTICE](NOTICE).\n",
  "bytes": 16144,
  "sha": "c23aeb18d265a0df8b7346cb6e895fd89f91e5ac5cbc0e652e2acb63e16d547e",
  "repo_slug": "andreisilva1/binky",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_andreisilva1_binky_4e7f97c3/readme"
}