{"slug": "show-hn-aidcrew-a-team-of-coding-agents-each-on-its-own-model-in-one-terminal", "title": "Show HN: Aidcrew a team of coding agents, each on its own model, in one terminal", "summary": "Aidcrew, a new open-source terminal tool from developer Antonio Ciccia, orchestrates a team of coding agents that each run on different AI models and providers, with every job isolated in its own git worktree. The tool, which supports mixed models like Claude Opus 5 and DeepSeek V4 Flash through OpenRouter, is designed to keep costs under a cent per run and is available for macOS, Linux, and Windows. Aidcrew's architecture enforces a plugin system where the core has no dependencies on specific providers, and it reads agent definitions from existing project files like .claude/agents.", "body_md": "A team of coding agents, each on its own provider and model, every job in a git worktree of its own, in one terminal.\n\n```\n  architect  claude-opus-5      coder  deepseek-v4-flash ◆   reviewer  free-tier\n  ▸ Plan in PLAN.md: rotate…  ⠹ thinking                   ▸ The multiplier is fine…\n```\n\n*One take, cut for length. An empty repository, the setup wizard, a key, a team\nof two. The architect plans on glm-5.3-flash; the coder builds, tests and\ncommits on deepseek-v4-flash; the architect verifies the branch and merges it\n— both through OpenRouter, the whole run under a cent. What the shell runs at\nthe end is main.*\n\nTwo claims, and the code is the argument for both.\n\n**Everything is a plugin.** The core knows no provider, no tool, no file format.\nWhat ships in `plugins/`\n\n— the OpenAI, Anthropic and Gemini dialects, the\nfilesystem and shell tools, the guards, compaction, prices — loads through the\nsame registry a stranger's plugin does.\nIf the contract were not enough to write them, the contract would be wrong.\n\nThat is a test rather than a paragraph. `packages/core/src/architecture.test.ts`\n\nfails the build if the core imports a tool or a provider, if it reaches out of\nits own package by path, or if it so much as names a real service in a string:\n\n``` js\nconst forbidden = /\\b(openai|anthropic|deepseek|openrouter|gemini|ollama)\\b/i\n```\n\n`packages/core/package.json`\n\nhas no `dependencies`\n\nkey at all.\n\n**Mixed models are the default, not an extension.** Planning on a strong model,\nexploring on a free tier, reviewing on a third is how a bill stays affordable,\nand it only works if two agents can hold two credentials on two services in one\nsession. That is the base case here.\n\nOne file, no runtime to install alongside it. From the\n[latest release](https://github.com/antoniociccia/aidcrew/releases/latest):\n\n```\n# macOS, Apple silicon. Swap the name for your platform.\ncurl -Lo aidcrew https://github.com/antoniociccia/aidcrew/releases/latest/download/aidcrew-macos-arm64\nchmod +x aidcrew && sudo mv aidcrew /usr/local/bin/\naidcrew --version\n```\n\nBuilds are published for macOS (arm64, x64), Linux (x64, arm64) and Windows\n(x64), with a `checksums.txt`\n\nbeside them. Before a release is published, the\nbinary it built is started on each of the three. On Windows the shell tool\nruns `bash`\n\n, so have Git for Windows on the PATH — or take the Linux build\nunder WSL, which is the better-worn road.\n\nFrom source, which is what you want if you are going to change it:\n\n```\ngit clone git@github.com:antoniociccia/aidcrew.git\ncd aidcrew && bun install     # Bun 1.3 or later\nbun run build                 # a binary for this machine, in dist/\naidcrew demo\n```\n\nSixty seconds, no key and no account: a throwaway project with a real bug, and a model that does not exist. Real files, the real tools, the real loop — nothing leaves your machine. It ends with the check passing, or it tells you that is a bug in aidcrew.\n\nWith a key of your own:\n\n```\naidcrew config set-key provider:zen   # read from stdin, never an argument\naidcrew -p \"make the failing test pass\"\naidcrew                               # the interface: the whole team, one screen\n```\n\nAgents come from the files a project already has — `.claude/agents/*.md`\n\nby\ndefault — read where they are rather than imported, so a definition edited for\nanother tool is current here too. Which of them are on *this* team, and what\neach one runs on, is `.aidcrew/config.toml`\n\n:\n\n```\n[agents.architect]\nprovider = \"anthropic\"\nmodel = \"claude-opus-5\"\ntools = [\"read\", \"bash\"]          # designs, does not write\n\n[agents.coder]\nprovider = \"zen\"\nmodel = \"deepseek-v4\"\n\n[agents.reviewer]\nprovider = \"zen\"\nmodel = \"deepseek-v4-flash-free\"  # review at no cost\ntools = [\"read\", \"bash\"]\n```\n\nCommitted with the repository, so whoever clones it gets the team.\n\nAn agent file says what one agent is *for*. How the team works together — hand\nthe work on rather than stopping to ask, what a handoff has to carry, what\ncounts as finished — is one thing said once, in `ORCHESTRATE.md`\n\n:\n\n```\n# Notes for whoever edits this\nEverything above the rule is for you. The agents never see it.\n\n---\n\nNobody is watching this run. When the next step is clear, take it. When it\nbelongs to somebody else, send it with `agent_send` and say what you expect\nback. Finished means checked, not written.\n```\n\nIt reaches every agent on every request, after its own file and after the\nroster — which aidcrew supplies, because who is running changes while the\nsession does and no file on disk can know it. You need not write one: without\nit a team works on the same wording built in. Call it something else, or keep\none for every project, with `[sources] orchestration`\n\nbeside `agents`\n\nand\n`skills`\n\n.\n\nOne agent leads, and every job comes back to it. When the architect hands a fix\nto the coder and the coder hands it to the tester, the tester's verdict returns\nto the architect — not to the coder it heard from — so the one who was given\nthe job is the one who decides it is done. Name the leader with `[defaults] leader`\n\n; it defaults to the first agent the project declares, and it is the one\nagent that cannot be dropped from the team, because a team whose leader was\nremoved has nowhere for work to come back to.\n\nEvery job gets a `git worktree`\n\nof its own, shared by the agents working it.\n`/task rotate-keys coder reviewer`\n\nopens one; the checkout you are sitting in is\nnever touched, and two jobs running at once are two separate diffs rather than\none corrupted file. `aidcrew undo`\n\ntakes back the last change any of them made.\n\nA checkout with work in it outlives the session. Close the terminal with files\nchanged and not committed, or with commits on no branch, and the worktree\nstays under `.aidcrew/wt/`\n\n; the next session picks it up where it was left and\nsays so. Only a clean checkout, or one whose work a branch already holds, is\ntaken away.\n\nAn agent can carry a `role`\n\n, which several agents may share. Work addressed to a\nrole goes to whichever agent on it is free:\n\n```\n[agents.coder]        # role defaults to the agent's own name\n[agents.coder-night]\nrole = \"coder\"\n```\n\nNaming a file with `@`\n\nsends it: `what does @src/auth.ts do?`\n\narrives with the\nfile attached, rather than costing the agent a turn to go and find it. `^t`\n\nfinds one by part of its name, for the keyboards where `@`\n\nis awkward.\n\nTyping `/spawn coder`\n\nstarts another one mid-session, onto the job you are on\nand into the same checkout, without leaving what you were doing. `/help`\n\nlists\nthe rest, and `/tour`\n\nis eight pages on what the whole thing is — the same\nones a first run ends on.\n\nWhen they are all busy there is a decision to make, and it is not the sender's. The question appears in the pane of the agent it is about, with the three answers that exist: wait, start a second agent of that role, or drop it and tell the sender so. A headless run queues, as it always did.\n\nA turn is bounded — fifty tool calls, so a model going round in circles is\nstopped — and an agent you have turned loose with `/yolo`\n\nis sent back to carry\non when it reaches that bound with the work unfinished, a few times, before the\nstop is real. Nobody watching means nobody to say \"go on\", so the harness says\nit. An agent that is asking first stops and waits for you.\n\n`^l`\n\nasks which agents to put next to each other and draws them in their own\npanes, so a handoff can be watched from both ends at once — the plan going out\nof one pane and the files arriving in the other. Each pane keeps its own\nscroll, its own spinner and its own cost; a question an agent asks is answered\nonly from its own pane, and `tab`\n\nstill moves between them.\n\nThe divider between two panes moves. Drag it with the mouse, or press `^←`\n\nand\n`^→`\n\nto move it four columns a press; either way a pane is never pushed\nnarrower than it can be read, and the split you settle on is remembered for\nthe project. `^l`\n\nagain returns to one agent at a time.\n\nDrop a TypeScript module in `~/.aidcrew/plugins`\n\nor `.aidcrew/plugins`\n\n. No\nbuild step, no publishing, no restart. A plugin declares any of six things —\n`providers`\n\n, `tools`\n\n, `loaders`\n\n, `hooks`\n\n, `prices`\n\n, `ui`\n\n— and a whole provider\nis about twenty lines:\n\n``` js\nimport { definePlugin, defineProvider } from '@aidcrew/plugin-sdk'\nimport { z } from 'zod'\n\nexport default definePlugin({\n  name: 'my-service',\n  providers: [\n    defineProvider({\n      id: 'my-service',\n      endpoint: 'https://api.example.com/v1',\n      configSchema: z.object({ apiKey: z.string().min(1) }),\n      create: ({ apiKey }) => ({\n        id: 'my-service',\n        async *send(request, signal) {\n          // Translate the canonical request, stream back canonical deltas.\n        },\n      }),\n    }),\n  ],\n})\n```\n\n`request`\n\nis the canonical model — `Message`\n\n, `ContentBlock`\n\n, `Usage`\n\n,\n`StopReason`\n\n— which no provider sees from outside. Adding a service never\nchanges those types, and never changes the core.\n\nA provider that lacks tool calling, or has it and gets it wrong, declares so; the harness then puts the tools in the prompt and reads the calls back out of the text. That is the normal case on several open models, and it is the reason this seam exists rather than a list of blessed services.\n\nA plugin that needs to know something first exports `setup(host)`\n\n, called once\nbefore it registers; what it returns is merged over what it declared. The host\nit is handed is small on purpose — where the work is, where your files are, its\nown settings from `[plugins.<name>]`\n\nin the project config, a way to ask you a\nyes-or-no question, a way to say something, a directory of its own — and every\nitem is something a plugin cannot work out for itself. That is what lets a\nstranger ship a plugin for their issue tracker: it can ask for the name of the\nvariable holding a token instead of telling people to paste one into the\nsource. [ examples/plugin-with-setup](/antoniociccia/aidcrew/blob/main/examples/plugin-with-setup/index.ts) uses\nall of it and imports nothing private.\n\n```\naidcrew plugin check ./my-plugin   # what the host will say about it, before you ship\naidcrew plugin trust my-plugin     # a plugin that arrived with a clone runs only once you say so\n```\n\nProviders |\nAnthropic; Gemini; anything OpenAI-compatible (Zen, OpenRouter, DeepSeek, GLM, Ollama, vLLM), in both dialects, choosing between them by trying |\nTools |\n`read` , `write` , `edit` , `grep` , `glob` , `wc` , `awk` , `lsof` , `bash` , `skill` , and `agent_send` between agents. Everything that only reads is a tool of its own rather than a shell command, so looking something up does not need approving |\nMCP |\nAny MCP server, over stdio or HTTP, declared in the `.mcp.json` a project already has. Its tools arrive as ordinary tools and the agent loop never learns the difference. A server is a program, so one a project declares does not start until `aidcrew mcp trust <server>` says it may |\nGuards |\nA never-write list, an always-ask list, and a snapshot of every file before it changes. On every path, because they are registered with the host rather than by each caller — and headless has nobody to ask, so what would have been a question there is a refusal |\nContext |\nConversations shortened when they no longer fit, summarised by a cheaper model when the project names one |\nCost |\nPer agent and per session, from the provider's own price list, from the project's stated prices, or from the remaining balance on the key |\nImages |\nPasted into the prompt and sent to models that accept them |\nSessions |\nEvery turn written to disk; a session resumes where it was left, transcript, history and checkouts included |\nThe screen |\nThe alternate screen buffer, so nothing scrolls and the shell comes back as it was; every frame exactly the window's height, so it never blinks; drag over a pane to copy what it says |\n\n```\npackages/core          canonical types, agent loop, plugin registry, agent bus,\n                       governor, worktrees, event log — no provider, no tool\npackages/plugin-sdk    definePlugin() and the types for writing one\npackages/cli           commands, credentials, history\npackages/tui           the interface\npackages/fast-width    terminal width measurement, because the usual one\n                       dominated every frame\nplugins/               the official plugins, loaded like any other\nbun test\nbun run typecheck\nbun run lint\nbun run build:all # every platform, cross-compiled from any one of them\n```\n\nWhat changed between releases is in [CHANGELOG.md](/antoniociccia/aidcrew/blob/main/CHANGELOG.md).\n\nReleases are cut from a tag:\n\n```\nbun run version:set minor     # writes the version, commits it, tags it\ngit push --follow-tags        # CI starts a binary on each platform, then publishes all five\n```\n\nTest first, then the smallest code that passes, then tidy up. A bug gets a test that reproduces it before it gets a fix.\n\nThis is a young project and it is better with more hands on it. The places where help matters most right now:\n\n**Providers and plugins.** A service you use that is not on the list above is a twenty-line plugin away;shows the shape.`examples/`\n\n**Windows.** The binary is built and started there on every release; the tools have been run there far less. Reports from real use are worth more than anything else.**Models and prices.** The bundled price list and the ranking that puts models in front of a newcomer are both inand`plugins/prices`\n\n, and both go stale; a correction with a link is a welcome pull request.`packages/tui/src/models.ts`\n\n**Agent files and briefings.** Teams that work well for a language or a kind of project, as`.aidcrew/agents`\n\nfiles and an`ORCHESTRATE.md`\n\n.**Themes.** A palette is a few lines in.`packages/tui/src/theme.ts`\n\n[CONTRIBUTING.md](/antoniociccia/aidcrew/blob/main/CONTRIBUTING.md) has the ground rules — the failing test\nfirst, comments that say why, three checks before a pull request. Questions\nand ideas go to [Discussions](https://github.com/antoniociccia/aidcrew/discussions);\nsomething broken goes to an [issue](https://github.com/antoniociccia/aidcrew/issues/new/choose).\n\nMIT.", "url": "https://wpnews.pro/news/show-hn-aidcrew-a-team-of-coding-agents-each-on-its-own-model-in-one-terminal", "canonical_source": "https://github.com/antoniociccia/aidcrew", "published_at": "2026-09-03 19:57:42+00:00", "updated_at": "2026-09-03 20:23:40.981697+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools", "artificial-intelligence"], "entities": ["Aidcrew", "Antonio Ciccia", "OpenRouter", "Claude Opus 5", "DeepSeek V4 Flash", "OpenAI", "Anthropic", "Gemini"], "alternates": {"html": "https://wpnews.pro/news/show-hn-aidcrew-a-team-of-coding-agents-each-on-its-own-model-in-one-terminal", "markdown": "https://wpnews.pro/news/show-hn-aidcrew-a-team-of-coding-agents-each-on-its-own-model-in-one-terminal.md", "text": "https://wpnews.pro/news/show-hn-aidcrew-a-team-of-coding-agents-each-on-its-own-model-in-one-terminal.txt", "jsonld": "https://wpnews.pro/news/show-hn-aidcrew-a-team-of-coding-agents-each-on-its-own-model-in-one-terminal.jsonld"}}