{"_id":"@armoryworks/md-agent","_rev":"13-f264b84d9253132b849050b9a0037349","name":"@armoryworks/md-agent","dist-tags":{"latest":"1.11.0"},"versions":{"1.0.0":{"name":"@armoryworks/md-agent","version":"1.0.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.0.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"25b313acecf86ee463ac705af268749dd11f4826","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.0.0.tgz","fileCount":17,"integrity":"sha512-o8IkLXBiG/aq7zVLrLXm/64t/j+kdICk8cUKdQuDS4WEzqn8xkkU6QqYrUat/exkcabKIZvdd1L16Zst+iqqgQ==","signatures":[{"sig":"MEQCIBIoSgY7p5yEuZ3R8yqgbdebWeL69JPIRcs3Xe/FlkRaAiB3yw5LXCxAekJzMiyK5CYgtnIHNrqHFw9n+Ib+OjSNkA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":193650},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"5995126b0423f63e91cdb1993ea0951f1562dcb2","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:gemini":"tsx smoke-gemini.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"9.2.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"22.22.1","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.0.0_1784278706879_0.6641623648403068","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@armoryworks/md-agent","version":"1.1.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.1.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"a525573147c7bf3f9e72f84664ef6151ed9642e5","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.1.0.tgz","fileCount":21,"integrity":"sha512-hicNQP9Iec8yBnvkle+eR+hE41gTWK3PesAeDy0KlWzg+JtGy+MFrRwz1YFF6Bhfcb1beaIm3T6BRGdUJOZ//Q==","signatures":[{"sig":"MEUCIG01MkHDL6p68vnog5as/ufnhrMwPClOfGWaYul6OPa5AiEA6hFW0WDrDJL+wrDU1dFRo+H1PLB+WdNS7zRm5Mg+5mM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDFPtFKBXx+8QdvYYj/ceWEFR8vkBp1co5dIV+MIH4EMAIhALzcXMnKs5+Im2rh/1TvnS/c0VN0SUnyhGkYoxonQrfF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":261764},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"de9c3f13505629753142043c301fa0900f066924","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.1.0_1788547805309_0.13302825079770075","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@armoryworks/md-agent","version":"1.2.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.2.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"30c6dfa769e236b65ee3c7bd7fdc2cdb5cf31b63","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.2.0.tgz","fileCount":21,"integrity":"sha512-43X4y8i5BtW1VXUgTTiq40/rD8/hxOoIO0ACDFI66A6DjS74xJE1HBcyA0XFgEpvQ5mwO59zUkte15jxCecEog==","signatures":[{"sig":"MEUCIQCeA0hTNQiNNJ8VFHZ9BMA6Do9wHrKOPo6i7zRO+W4FsAIgbyHLXVMoNrl1viOB+5hAEBLRRVDlO2WXDSLfNFj4Jo8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC4CQErIuR7FOylcHkfwhFiizJDN4goXI3FaoxLixfihQIgCmttseqn1RvKlVRbtePw8aLYfooqoWuQ08kGpbI/snk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":289255},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"484e742520cfa398fd65e9709ea7459a4f1b1973","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.2.0_1788550839438_0.5430634923279147","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@armoryworks/md-agent","version":"1.3.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.3.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"f3a2cb726dfafb52d86781a7f5b7b2474be5923e","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.3.0.tgz","fileCount":22,"integrity":"sha512-gma8YVXPpYZ+Wmj1eN0OPvx2VigX8w7DFdrTwBGZlY87ypWDnEapSdN4S2m4X1mRFT5T7RMsRVYeEpFA/9vjWg==","signatures":[{"sig":"MEUCICmbLevxmvgQl5nx4gDRCu4nmzTXqspq9bglVr+rx9fBAiEAuBQGdR6F3IrEyDfOSzcppza+QzvxgT1TsGQaqcQZXZ0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQD7zk/ctxnMOAxqKxOyN/jaNgQzWspr34pbBkcQUgnX5gIhALw5jmrCd5lrEgmPYp6S1zAFiw6rpNBOG8fuI/JSGvQd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":317539},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"b4ae11fb2671f6a444a07bac98240b047b3958e3","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.3.0_1788551630664_0.7761481402448294","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@armoryworks/md-agent","version":"1.4.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.4.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"08fa8aa7763b6b1aee65929a852972626e910c88","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.4.0.tgz","fileCount":25,"integrity":"sha512-DgDcI4rhoib6AT5i/BYNPMiU/hVnsT3AxSiSFCWMxpRF/xvydcIOZ5DKoAOXzEVKLZYhp/0ZBaS7QKWnj6KflQ==","signatures":[{"sig":"MEYCIQD9y18DJphKg6WQNSBFDRamwLUs1GSUQsysiJu9QyMEyQIhAPAt/jsO6POt1PBUHiGwIsh584+gT7a4W0AWQVfTMwJ0","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIF8ToOP/p79/+AGkRS4prRI/SYU28DoFkK4P0cEhkaveAiEAlsaJL8R9KzFHU5qmZZc3FqlcFswkoaylCAQ+1AOGsL0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":353769},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"320867ccd7c868c2c07e8df8b42ee8642091ac00","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","postinstall":"node scripts/postinstall.mjs","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.4.0_1788553049015_0.9588916624861841","host":"s3://npm-registry-packages-npm-production"}},"1.4.1":{"name":"@armoryworks/md-agent","version":"1.4.1","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.4.1","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"0f0ad54f5d85b3b18cfeece93ec09e5d32b755df","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.4.1.tgz","fileCount":26,"integrity":"sha512-uozTeDD7wVZ3x6gT0vpzkmMxNkanjXoEQozSDo+G0jfCOXYamV6TQIuVyslQ9gnsjvnO9Mj+CHHZOiDXe7+DPg==","signatures":[{"sig":"MEUCIQCFK22Ty1tmxwgnc4gex9B51Xl7Ln2Xfv0tnm5xPPgs5AIgKJBw/0SbIL8nRBXbinsfxnZRK0Rbt/l6tbCHuZu+zuk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCICM4Ozg0ToC014VfrypFF8ymXuOawGTIGbim3WY2Ye+RAiEAsZC+wP7KWc6xTVMy3/nlZLtaS2JLd5OV6joLQ6e12LE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":354737},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"e106d9d5841618c5aaaa4aa4fce4b1a1d18cf3d6","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","postinstall":"node scripts/postinstall.mjs","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.4.1_1788553356192_0.796195623225598","host":"s3://npm-registry-packages-npm-production"}},"1.4.2":{"name":"@armoryworks/md-agent","version":"1.4.2","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.4.2","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"01af92b48c61009369829ecf40f7fefb146a089a","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.4.2.tgz","fileCount":25,"integrity":"sha512-zN5D4FEVBL3qgDkdasuUw445GgOQxzq9dI6/tf0ZSCjYUN+TT1Uc4Fc4OAfNePV/IYVNiIEoIDszV3YvvCDD0Q==","signatures":[{"sig":"MEUCIF8VRbnmUDRX7OHkPN0E0HLFDWh42/WNBRV5bxdTuHgrAiEAwlBrzMCD01ooToeamqvuISAJRmu0ny22Zxi2IsCG79E=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIF003ZMgsEqDPunCKIM1eVd0y8Tbvzw7WGikZ2uvgXn7AiBz4tchMR4RUzogExNCahSCeN40zZxhTPtiodRLf424uA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":357909},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"7b6d4f458ae0c2673541c4b57e7f1e08a5db1b74","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.4.2_1788555120450_0.023531025637029135","host":"s3://npm-registry-packages-npm-production"}},"1.4.3":{"name":"@armoryworks/md-agent","version":"1.4.3","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.4.3","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"17158a377359d25103037af8fd450e42f10fff52","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.4.3.tgz","fileCount":25,"integrity":"sha512-xMwiNK7g5AR+I4fT8RV3u7ivqn3Je9kzms7gxJrrMeTBO62a8Ye4xW9da3ZZmz+oyoT2t40PpytfFKjgMJ/brQ==","signatures":[{"sig":"MEYCIQD5Dy0ZKujE9hHB4L223cl8bgq916MsCOM87tXF7wNYOQIhALT5QTmROeHKNhfj/YeqemWW0XGtC1Zhu7Has2QcQfqA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDuI/DXz63277ID+2yL00kuylzw0YOV2NfZ84Aq4D2GGQIhALcc0KrLRJvLtGPso8v3amSUmW1iiprYKSGF20nF9wQ2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":359919},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"9a7847acd93c8d51f35401e61d4003c397b44be2","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.4.3_1788556009364_0.14543786984093554","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@armoryworks/md-agent","version":"1.5.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.5.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"7eadb5898835e90404f86466b812409eac57522d","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.5.0.tgz","fileCount":26,"integrity":"sha512-v1BjPT9hdyMYKzO3Adwj09VXzW9dWcNW1uwo7Tj4Lx/CZFFs1HIgaHX7u6Rm1CAU3pSnqUMu9ACZz1MC7fCb5Q==","signatures":[{"sig":"MEQCIGH0FJ403fcjRANnVe0LoGbQe4YtikHXqznMkaSe6hQsAiBdqIrgB2NwVO4qUstXev3BKZ+BUeYWRw3i567E0f0pyA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCrRqN2PBTIwD6Circfc5Q1jv2kTeSzTtO/MDhg9NK/pgIhAOd40/hFBrR7hHErIX61Qhumql/TGKDja23s1e9X3oFI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":367615},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"ab9831a2136d406df235eb6cb1ff18e7ae25de51","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.5.0_1788557068725_0.03132573778111336","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"@armoryworks/md-agent","version":"1.7.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.7.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"407de120e9a37aca6332efc897d5dbce1d78a8d7","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.7.0.tgz","fileCount":26,"integrity":"sha512-XoSPxFzsWSLxBk0VZe+ZK0LXJrR/XZ9CYSg6p2NGsIJQrLg8k/t2lYlTHdHIJtEr0qpgszCbr1qh3z8QpafX4g==","signatures":[{"sig":"MEQCICLwEUDxt4iRfMYhy0f60w0jiKMtXbI5B+u/rEgKKy8bAiBbHpS56nETI3+E7QgJjCz6zXtuCnHNSgaiXlaGjcwTRg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIAWfz85XQ396eq2y1qSJHSr4E5igx6vnsYW6mfDhvjeDAiBXk4HCGGMmauq97Tm64ofkLwJ8TeEDULkgtFDUNXkihw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":390083},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"173a806ff5f3150859de5267bba41c57d9cb7c20","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts && tsx smoke-providers.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.7.0_1788557872254_0.7089067591041238","host":"s3://npm-registry-packages-npm-production"}},"1.8.0":{"name":"@armoryworks/md-agent","version":"1.8.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.8.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"69b65a4e6ef5265b70384f9f06ebc60f336954d2","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.8.0.tgz","fileCount":27,"integrity":"sha512-iurlI6bm38laKVfuBfXoNmwGZH+oueC23vHUvvs0PJRypvSnJdKol78+JycRGCOf8iNxRBeIUjQo/TdGSONx3Q==","signatures":[{"sig":"MEQCIBu6ZMxgrbRvLyT7XBuZSzAxGzEvO6+xccXbfyuTnL0TAiBDPdMPl7TLy5nBqrpMY3Sihe3PGoGysB8kW1ZlnWMX6w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDluq6rn1CpKtL6iyrkIVwefKkdYQuzAqsAX6Y4AaZCewIhAPJz1iZ/s3OONdEBIkNOWjDc21Zvt6metsi7W6SJOV3u","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":408905},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"1f7453398826ea476c0124b895d85cdcc96e46ca","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts && tsx smoke-providers.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.8.0_1788561808503_0.6900374872330812","host":"s3://npm-registry-packages-npm-production"}},"1.9.0":{"name":"@armoryworks/md-agent","version":"1.9.0","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","_id":"@armoryworks/md-agent@1.9.0","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"homepage":"https://github.com/armoryworks/md-agent#readme","bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"bin":{"md-agent":"dist/index.js"},"dist":{"shasum":"bbff67234ec3628b88d950171fb555897cd9fa43","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.9.0.tgz","fileCount":28,"integrity":"sha512-ubPGNU3TcNsRcbset93ESsE7XGJydO9qSroJEcj8PxmkLSYLqjlr3aFu5ZfvakpgbsD7jSrzlywPEJxcyZr2Kg==","signatures":[{"sig":"MEQCIANrPyX5YwT8qFEPx/CA2KWsQDjxwYv1wClKMIdSgjUOAiAHWVZwlXwAmZkR9AAoumu/2d2LeXaweGdufBer0UCsLA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCekqWB8qQdSvKJ/2/sFwOL4o+8giWEMqLQPp0yqKZ+uQIhAJLGDvsiQ4cZrL9tEELXylPHLxHXCj58Ykq6vEhmb5dG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":440972},"main":"dist/index.js","type":"module","engines":{"node":">=20"},"gitHead":"77c641d90748f6b800b8c5488af5c39206510602","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts && tsx smoke-providers.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/md-agent_1.9.0_1788628133017_0.9287194381160973","host":"s3://npm-registry-packages-npm-production"}},"1.11.0":{"_id":"@armoryworks/md-agent@1.11.0","bin":{"md-agent":"dist/index.js"},"bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"dist":{"shasum":"17145ee913d50b9c7b4055b5b1473ea69094085a","tarball":"https://registry.npmjs.org/@armoryworks/md-agent/-/md-agent-1.11.0.tgz","fileCount":30,"integrity":"sha512-5Ib5uEGfk4WNFDfA/yQv5h6FUnE7NWwNl0ZoZXAdnKeHrjXrBbbnIclOhuLb7/AewytEnXZLkV6ZVtLba/FfOg==","signatures":[{"sig":"MEQCIFCZ+v10m+sc68ogVO4TTPJBBZPLLgAGkJGlj9HvJqsLAiBVjh+SvWvZVROjpkhamGnVlKkxr1dEjGN03P1VEao5og==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIA2qrOGB5opIkqctOaUTSkKYwJySZTSOFOu51ZlWYz3XAiANl8eN4MR59jY1yS7i4QQc7SqeYQ7H8pf4KtXNwRsmTA=="}],"unpackedSize":503366},"main":"dist/index.js","name":"@armoryworks/md-agent","type":"module","author":{"name":"ArmoryWorks"},"engines":{"node":">=20"},"gitHead":"64943e56a8ba62f36eb132cbf0440fccdd3162af","license":"Apache-2.0","scripts":{"dev":"tsx src/index.ts","test":"tsx smoke-team.ts && tsx smoke-providers.ts && tsx smoke-heal.ts && tsx smoke-workspace.ts && tsx smoke-script.ts","build":"tsc","start":"node dist/index.js","smoke:agy":"tsx smoke-agy.ts","prepublishOnly":"npm run build && npm test"},"version":"1.11.0","_npmUser":{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"},"homepage":"https://github.com/armoryworks/md-agent#readme","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"_npmVersion":"11.19.0","description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","directories":{},"maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"_nodeVersion":"24.20.0","dependencies":{"chokidar":"^5.0.0","cross-spawn":"^7.0.6","gray-matter":"^4.0.3","@inquirer/prompts":"^8.4.3"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.22.3","typescript":"^6.0.3","@types/node":"^25.9.1","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/md-agent_1.11.0_1788647026035_0.4605734346027799"}}},"time":{"created":"2026-07-17T08:58:26.745Z","modified":"2026-09-05T22:23:46.359Z","1.0.0":"2026-07-17T08:58:27.011Z","1.1.0":"2026-09-04T18:50:05.414Z","1.2.0":"2026-09-04T19:40:39.534Z","1.3.0":"2026-09-04T19:53:50.816Z","1.4.0":"2026-09-04T20:17:29.110Z","1.4.1":"2026-09-04T20:22:36.278Z","1.4.2":"2026-09-04T20:52:00.525Z","1.4.3":"2026-09-04T21:06:49.453Z","1.5.0":"2026-09-04T21:24:28.830Z","1.7.0":"2026-09-04T21:37:52.365Z","1.8.0":"2026-09-04T22:43:28.637Z","1.9.0":"2026-09-05T17:08:53.108Z","1.11.0":"2026-09-05T22:23:46.155Z"},"bugs":{"url":"https://github.com/armoryworks/md-agent/issues"},"author":{"name":"ArmoryWorks"},"license":"Apache-2.0","homepage":"https://github.com/armoryworks/md-agent#readme","keywords":["claude","claude-code","agents","orchestration","multi-agent","cli"],"repository":{"url":"git+https://github.com/armoryworks/md-agent.git","type":"git"},"description":"Orchestrate a team of Claude Code agents against a single goal via file-based IPC.","maintainers":[{"name":"danielhokanson","email":"daniel.hokanson+npm@gmail.com"}],"readme":"# md-agent\n\nA small CLI that runs a **team of agent CLIs** — [Claude Code](https://claude.com/claude-code)\nand, per seat, [Antigravity](https://antigravity.google) — against a single goal.\nOne *orchestrator* agent coordinates several named *role* agents (e.g.\n`backend-engineer`, `qa-lead`, `discovery-analyst`), routing work to them and\nsynthesizing what comes back. Coordination happens over plain files on disk, so\na run is fully inspectable and resumable.\n\nThe shape it is built for: **delegate** mechanical work to a cheap seat,\n**isolate** every seat in its own git worktree, **verify** each worktree with a\ncommand that proves the result, **admit** the branches that pass. Judgement\nstays on a claude seat; nothing lands in your tree until you merge it.\n\n> Each agent is a real `claude` or `agy` process. md-agent is the conductor, not\n> the model — it spawns the CLI, routes messages, persists sessions, tees every\n> seat's stream to a trace, and keeps a running transcript and cost tally.\n\n## How it works\n\n```\n                 ┌──────────────────┐\n   you  ──────▶  │   orchestrator   │   (a claude session; routes TO: blocks)\n                 └────────┬─────────┘\n              inbox/*.txt │ ▲ outbox/*.txt\n                          ▼ │\n        ┌───────────┬───────────┬───────────┐\n        │  role A   │  role B   │  role C    │   (one agent CLI process each — claude or agy)\n        └───────────┴───────────┴───────────┘\n```\n\n- The **orchestrator** is **stateless**: it has no growing conversation. Each turn\n  it is handed its **ledger** (`ledger.md` — its externalized memory) plus the new\n  event(s), and it replies with an updated ledger + zero or more `TO: <role>` blocks.\n  Each block is written to that role's `inbox/<role>.txt`. Events that arrive while\n  a turn is in flight (e.g. several roles finishing at once) are **coalesced into a\n  single next turn** — one ledger in, one ledger out — instead of paying a full\n  turn per event; the orchestrator also plans against the joint state rather than\n  arrival order. Multiple `TO:` blocks for the same role merge into one message,\n  and an unconsumed inbox is appended to, never overwritten, so dispatches can't\n  be silently lost.\n- Each **role** is a child process watching its inbox. It runs its own (stateful)\n  `claude` or `agy` session and writes the reply to `outbox/<role>.txt`.\n- The orchestrator watches every outbox; each reply becomes the next event it\n  folds into the ledger and acts on.\n- Every message is appended to a single `transcript.md` (the orchestrator is the\n  sole writer, so the transcript is the one source of truth).\n- On a timer, the run **checkpoints**: it writes the current ledger to the\n  transcript (a durable footprint) and hands control back for feedback, interval\n  changes, or exit. If no one responds within a grace window it auto-continues\n  and arms the next checkpoint, so the cadence stays a reliable heartbeat instead\n  of stalling.\n\n**Why the ledger?** Feeding every role reply into a growing orchestrator\nconversation makes per-turn cost climb with the run — and worse, when a child\nagent takes minutes to reply, the orchestrator's prompt cache expires, so the\n*entire* growing context is re-read at full price on the next turn. Keeping the\norchestrator's resident context to `system + ledger + this event` makes it\n**bounded by design**: a cold cache is cheap because there's little to re-read.\nThe ledger holds status and pointers; details live in shared files and are\nretrieved only when needed.\n\nEach participant's session id is persisted under `sessions/`, so a run can be\npaused and resumed without losing context.\n\n## Requirements\n\n- **Node.js** ≥ 20 (ESM, `NodeNext`).\n- The **`claude` CLI** installed and on your `PATH`, already authenticated.\n  md-agent shells out to it (`claude -p --output-format stream-json`). The\n  orchestrator is always claude.\n- Optionally the **`agy` CLI** (Antigravity), for seats configured with\n  `provider: \"agy\"` (`agy -p --output-format stream-json`). Only the providers a\n  run is configured to use are probed at launch.\n- **git**, when a run uses `isolation: \"worktree\"`.\n\n## Install & build\n\n```bash\nnpm install\nnpm run build     # tsc → dist/\n```\n\n## Usage\n\nJust run it:\n\n```bash\nmd-agent                         # after: npm install -g @armoryworks/md-agent\nnpx @armoryworks/md-agent        # or without installing\nnpm run dev                      # from a checkout, via tsx\n```\n\nA bare `md-agent` opens the **home screen**: it scans `./runs` for prior work\nand presents it — standalone runs and journeys (grouped with their phases),\neach with its goal, spend, recency and status (`running`, `unfinished`,\n`HALTED`, `complete`). Nothing on it asks you to touch the filesystem:\n\n- **Continue** — the first choice, always the most recent unfinished thing. A\n  run resumes where it stopped (seats reattach to their sessions). A journey is\n  driven from its first phase that did not end cleanly: a halted phase is\n  retried in place (its `HALT.txt` is cleared and the reason kept in the\n  transcript), an unfinished one resumed, the next one started. The manifest\n  path is recorded in each phase run, so nothing has to be re-typed.\n- **Launch `md-agent.launch.json`** — offered when the current directory has\n  one (see `md-agent init` below).\n- **Resume a specific run or phase** — choose exactly which one.\n- **Look inside a seat** — a seat's trace: what it was asked, the tools it ran,\n  what it said, what each turn cost. See *Looking inside a seat*.\n- **Start something new** — the setup wizard (roles, goal, checkpoint interval,\n  sub-teams, soft time budget).\n- **Combine past runs into a new run** — select one or more prior runs; a new\n  run is seeded with their goals + final ledgers + pointers to their artifacts,\n  and the wizard takes it from there.\n- **Mark runs complete** / **Restore a shelved run** — shelve finished work\n  (hidden from the menus, untouched on disk) and bring it back later.\n\n### The wizard: goal first, then a fork\n\n*Start something new* asks, in this order:\n\n1. **What should the orchestrator be reaching for?** — the goal. It is the\n   first question because it is what everything else is sized to.\n2. **Journals** — keep this project's run records in a private repo? Use the\n   configured one, pick or create another, skip for this run only, or *No, and\n   don't ask again — ever*. Once opted out the panel's footer shows\n   `journals off (type \"journals\")`; that keyword, typed during any run, turns\n   them back on.\n3. **How should the team be set up?** — *Have Claude plan it* or *Set it up by\n   hand*. The planner (`MD_AGENT_PLANNER_MODEL`, default `claude-fable-5-1`)\n   is given the goal, a read-only look at the repo, and a brief on how md-agent\n   works, and returns a recommended team: how many seats, each one's mandate,\n   provider and tier, the verify command it found, isolation, escalation, a\n   budget, and the questions it could not settle. Then: **launch it**,\n   **review each seat** — the recommendation first with the planner's one-line\n   reason for that provider and tier, then every alternative with what it is\n   good for and what it costs; your pick replaces the plan's — **save it** as\n   `md-agent.launch.json`, or **adjust it by hand** (the wizard, prefilled). A\n   plan costs roughly a dollar's worth of tokens and takes under a minute.\n\n### Which tier for which seat (measured)\n\nFive runs of one three-angle code review on 2026-09-05, same seats otherwise,\nscored against the opus run's 20 challenger-verified findings:\n\n| Reviewer shape | Cost | Baseline hits | False positives the challenger passed |\n|---|---|---|---|\n| opus, all angles | $9.78 | 19–20 | 0 |\n| opus correctness + sonnet drift | $5.00 | 8 | 1 |\n| sonnet correctness + sonnet drift | $3.71 | 3 | 1 |\n| sonnet, all angles | $4.57 | ~2.5 | 3 |\n\nSo: **every seat that judges runs on opus** — review, challenge, audit,\ndrift or gap analysis, anything whose output is a conclusion. Split judging\nwork across parallel opus seats for wall-clock, never down-tier it for cost.\nSonnet and haiku take the work a command checks: enumeration, extraction,\napplying a known change, citation checking. A sonnet challenger verifies\ncitations, not conclusions; put the challenger on opus when the conclusions\nmatter. `md-agent init`, the planner and the skill all encode this.\n\n### `md-agent init`\n\nWrites a starter `md-agent.launch.json` into the current repo — a cheap seat\nbehind a verify command, a claude reviewer, worktree isolation, escalation, an\ninline `$help` block explaining each choice. Edit the goal and `verify.cmd`,\nthen `md-agent` offers it as a one-key launch (or `md-agent --launch\nmd-agent.launch.json`). The second run never needs the wizard.\n\n### The umbrella\n\nWhile a run is live the top of the console is frozen — the ArmoryWorks mark,\nthe run's **goal**, and a tree of the orchestrator with every seat beneath it:\nprovider and model, what it is doing and for how long (`working 38s`,\n`replied 2m ago`, `in huddle`, `recovering`), turns taken, last-turn cost and\ncache read, cumulative spend. Log output scrolls underneath. It is a status\nsurface only: seats still report to the orchestrator through their outboxes\nexactly as before.\n\n### Stopping a seat\n\n**ctrl-x** at any time (or type `stop`) opens the stop menu: pick one or more\nseats, then for each choose **hand off to <seat>** or **leave abandoned**. A\nhandoff gives the receiving seat the stopped seat's mandate, its outstanding\ndispatch (or the last one it was working on), its last report, and — under\nworktree isolation — where its edits live, so nothing has to be re-explained.\nEither way the stopped seat's outbox carries a `[SEAT STOPPED]` note naming\nwho picked the work up (or that nobody did), which reaches the orchestrator\nthrough the normal path, so it re-plans instead of waiting on a seat that is\ngone. A stopped seat stays stopped across resumes; dispatches to it are\ndropped and reported back.\n\n### Seats can reach each other's work\n\nUnder `isolation: \"worktree\"` a seat's files live only in its own worktree, and\na claude seat cannot read outside its cwd — so, before 1.10, a reviewer asked to\n\"check the sweeper's table\" answered that the file did not exist. Now:\n\n- **Verified replies are committed.** When a seat's reply passes its check, the\n  harness commits its workspace on the seat's branch (`md-agent(<seat>): <first\n  line of the reply>`) and the orchestrator's event says so: `[verify PASS in\n  sweeper's workspace: … — committed 3f2a9c1 on md-agent/<run>/sweeper]`. The\n  completion gate commits every changed workspace before judging it, so a\n  branch head is exactly the tree that passed.\n- **Sibling worktrees are readable.** Every claude seat gets\n  `--add-dir runs/<run>/workspaces`, and its mandate names the path and the\n  branch form (`git show md-agent/<run>/<seat>:<path>`), read-only.\n- **The orchestrator is told** that seats' work is not in each other's trees and\n  to hand a consumer the producer's branch or path — and to dispatch the\n  consumer only after the producer's reply has landed.\n\n### Readiness is explicit\n\nA seat that works in slices reports after each one; only a reply that presents\nthe *deliverable* should be judged by the verify command. The seat's mandate\nasks it to end such a reply with the line `VERIFY-READY`; that line is what\nbounces on failure. A reply without it that still reads as finished (\"done\",\n\"complete\") is judged too, unless it also reads as interim (\"slice 2 done\",\n\"notes at …\", \"continuing\"), in which case the verify result is attached to the\nevent rather than bounced.\n\n### Verify where the work is\n\n**The merged tree is judged too.** When more than one seat changed its\nworkspace, the gate merges every changed branch into a scratch worktree cut\nfrom the base HEAD and runs the run's check there once. A conflict fails the\ngate naming the branch and the paths; a merged FAIL fails it with the output.\nTeardown prints `merged together: PASS | FAIL | CONFLICT (…)` under the\nper-seat lines, so \"safe to merge\" means safe to merge *all of them*.\n\n**The verify command is dry-run at launch.** It is expected to fail (the\ndeliverable does not exist yet); what refuses the launch is a shell error or a\nmalformed comparison (`test -ge 10` with no left operand — what an unquoted\nheredoc leaves behind when it eats `$(…)`), because every seat reply would then\nbounce on a check that can never pass. Three runs spent $3.56 that way before\nthis check existed.\n\nWith a `verify` command set, **every seat reply that changed its workspace is\nchecked there** before the orchestrator sees it (an isolated workspace with no\nchanges is not judged — the same rule the completion gate uses — and a seat can\ncarry its own `verify`, or `verify: false` for a review-only seat). A reply that claims to be done\nwhile the check fails is sent straight back to the seat with the output — no\norchestrator turn is spent relaying it — up to `maxFailures` times; after that\n(or for replies that are not completion claims) the result is attached to the\nreply the orchestrator receives. The completion gate runs the same way: under\nisolation, every seat whose workspace changed must pass. The orchestrator\nitself runs without edit tools (`Write`, `Edit`, `Bash`…) so it coordinates\nrather than doing the work — `MD_AGENT_ORCH_TOOLS=all` restores them.\n\n### Keeping a seat's turns small\n\nA seat's turn is one agentic loop inside its CLI — dozens of model calls, each\nre-reading the whole conversation so far. A turn that reads a repository and\nruns a full test suite can reach millions of tokens on its own, and a stateful\nsession carries all of it into the next turn. Three things hold that down:\n\n- **Turn discipline** in every seat's mandate: one slice per turn, one check,\n  then report; never re-read the repo or re-run the suite to \"confirm\" what an\n  earlier turn established.\n- **A turn cap** — `roles[].turnTimeoutSec`, default 300 for agy and 600 for\n  claude. A turn that runs past it is stopped and reported to the orchestrator\n  as an ask that was too big for one turn, so it re-scopes rather than repeats.\n- **Recycling by size** — a session whose *resident context* (what its last\n  model call read, and so what every call of the next turn would re-read) is\n  over `MD_AGENT_ROLE_RECYCLE_TOKENS` (default 200k) is reseeded from a handoff\n  note before its next dispatch, in addition to the every-8-turns rule.\n- **Per-turn caps** — `roles[].turnBudgetUsd` (claude, `--max-budget-usd`) and\n  `roles[].turnMaxSteps` (agy, default 80 tool steps) bound a turn\n  deterministically where the wall-clock cap only approximates it.\n- **Read discipline** — tool output is three quarters of what a seat re-reads\n  on every call of a turn (measured across two review runs: 76% of the chars\n  entering seat context were grep/cat/Read output; the seats' own reports were\n  3%). Every seat's mandate now says: never print a whole file, read with\n  offsets and line budgets, batch many checks into one grep or one script.\n  `roles[].readOnly: true` gives a judging seat Read/Grep/Glob only, so it\n  cannot dump files or run suites at all. The recycle-by-size default is 120k\n  resident tokens (was 200k), and a claude seat's turn has a per-tier USD cap\n  by default (opus 5, sonnet 2.5, haiku 1; `roles[].turnBudgetUsd`, 0 = none,\n  `MD_AGENT_TURN_BUDGET_USD` for all) — a capped turn keeps its work on disk\n  and comes back as `[TURN CAPPED]`.\n- **agy under `budget.usd`** — Antigravity reports tokens, not a price, so an\n  agy seat counts $0 toward `usd` unless `budget.agyUsdPerMTokens: { input,\n  output, cacheRead }` gives it one; its turns are then estimated and bound.\n  Without it, `budget.tokens` is what bounds an agy seat, and launch says so.\n- **A lean prefix** — every model call re-reads the CLI's fixed prefix (tool\n  schemas, MCP servers, skills: ~23k tokens on a typical machine). Seats get the\n  built-in tools they need (`roles[].tools`, default Bash/Read/Edit/Write/Glob/\n  Grep/WebFetch/WebSearch) and none of the user's MCP servers (`roles[].mcp:\n  \"inherit\"` restores them); the orchestrator gets Read/Glob/Grep and no skills.\n  `roles[].effort` and `roles[].fallbackModel` pass through to the CLI.\n- **A fallback ladder** — `roles[].fallback` (or a run-level `fallback`) is\n  where a seat moves when its provider runs dry; see *When a provider runs dry*.\n- **No skills, optionally no project instructions.** Seats load no skills by\n  default (`roles[].skills: true` restores them — 53 descriptions rode in every\n  call before). `roles[].projectInstructions: false` runs the seat with\n  `--setting-sources user`, dropping the project's CLAUDE.md and settings from\n  its prefix: on a repo with a 70 KB CLAUDE.md that is ~20k tokens per call,\n  three times the rest of the prefix. Leave it on for seats that edit the repo;\n  turn it off for seats that only read or enumerate. The orchestrator never\n  loads it (`MD_AGENT_ORCH_PROJECT_INSTRUCTIONS=1` to restore).\n\nLarge shared briefs reach seats the way they reach the orchestrator: a pointer\nto `context.md` plus an excerpt, read on demand rather than resident every turn.\n\n### When a provider runs dry\n\nA seat whose provider is out of quota — agy's *\"Individual quota reached …\nResets in 164h48m\"*, or a claude `rate_limit_event` that isn't `allowed` —\n**stops itself**: it records the stop and the reset time in `state.json`, tells\nthe orchestrator through its outbox (`[SEAT STOPPED] … OUT OF QUOTA … resets in\n~165h`), and exits. It is not respawned; the orchestrator reassigns its work to\na seat that still has quota or drops it. Any other turn error is reported to\nthe orchestrator the same way (`[ROLE ERROR] …`) instead of leaving it waiting\non a seat that will never answer.\n\n**Auto-heal.** A seat with a `fallback` ladder does not stop when its provider\nruns dry — it moves. Each rung is `{ \"provider\", \"model\" }` (provider defaults\nto claude, model to the seat's own tier, resolved on that provider); a run-level\n`fallback` is the default for every seat without its own. Two moments heal:\n\n- **At preflight.** If a role provider fails its probe (agy's weekly quota is\n  the usual case), every seat on it is moved to its first usable rung before\n  the run dir exists, the rung's provider is probed too, and the launch goes\n  ahead: `[preflight] seat \"sweeper\" falls back: agy·gemini-3.8-flash-medium →\n  claude·claude-haiku-4-5`. A seat on the dry provider with no rung still fails\n  the launch, naming the seat. The orchestrator's claude has no stand-in.\n- **Mid-run.** A seat whose turn raises the provider's out-of-quota error\n  records the move in `state.json` (`healed[]`, with the reset time), reseeds a\n  fresh session on the new provider from its mandate plus its transcript\n  history — the dead provider cannot be asked for a handoff — and re-runs the\n  same dispatch. Its reply opens with `[SEAT HEALED] \"sweeper\" moved from\n  agy·… to claude·… — agy ran out of quota (resets …)`, the umbrella and\n  `--watch` show `← healed from agy·…`, and the orchestrator keeps dispatching to\n  it as normal. Rungs on the provider that just failed are skipped (a quota is\n  per account, not per model), and each rung is used once, so a ladder cannot\n  loop. With no rung left the seat stops itself as above.\n\n```json\n{ \"name\": \"sweeper\", \"provider\": \"agy\", \"model\": \"sonnet\", \"escalate\": false,\n  \"fallback\": [{ \"provider\": \"claude\", \"model\": \"haiku\" }, { \"model\": \"sonnet\" }] }\n```\n\n**A capped turn is not a crash.** A seat stopped by its own `turnBudgetUsd`,\n`turnTimeoutSec` or `turnMaxSteps` reports `[TURN CAPPED] … was stopped by its\nper-turn budget … files it wrote before the cap are on disk (possibly partial,\nuncommitted). Re-dispatch it with a SMALLER ask` — and the spend of that turn\nis booked, so the run's Σ stays true. Any other turn error is `[ROLE ERROR] …`.\n\n**Idle turns re-invoke.** Under `autoComplete`, an orchestrator turn that ends\nwith nothing dispatched and no seat working is re-invoked five seconds later\n(three times at most, then the watchdog's ten-minute nudge takes over) instead\nof waiting ten minutes for the watchdog — the shape that cost a 45-minute run\nten idle minutes.\n\n**The gate waits for busy seats.** A completion request while a seat is\nmid-turn waits for its reply (bounded by the longest turn cap in play) before\njudging, so a commit landing seconds after RUN END cannot slip past the gate\nunjudged and unbooked.\n\nA **loop guard** watches for one seat being dispatched to over and over with\nnothing verified in between — the shape that spends a week of quota on cache\nreads. At four consecutive dispatches the orchestrator is told, in its next\nevent, to change approach; at six the run HALTs with the reason. A dispatch to\nany other seat, or a verify PASS, resets the count.\n\n### Budgets\n\n`budget` in a launch config (or journey phase) sets spend ceilings, each with a\n**soft** line (the orchestrator is told to wind down) and a **hard** line (the\nrun HALTs cleanly and can be continued from the home screen once it clears):\n\n```json\n\"budget\": {\n  \"usd\":         { \"soft\": 5,  \"hard\": 10 },\n  \"tokens\":      { \"soft\": 2000000 },\n  \"fiveHourPct\": { \"soft\": 70, \"hard\": 90 },\n  \"sevenDayPct\": { \"hard\": 95 }\n}\n```\n\n`usd` and `tokens` sum every seat and the orchestrator (tokens = everything\nprocessed: input, cache reads and writes, output). `fiveHourPct` and\n`sevenDayPct` are your **plan windows** — the claude CLI reports them on every\nturn, so they are exact and need no translation from your usage page; agy seats\ndon't report them, so for agy-heavy runs use `tokens`. The umbrella shows all\nof it live: per-turn and net spend for each seat and the orchestrator, the run\ntotal, and `5h 21% · 7d 7%`.\n\n### Journals — a run's record in source control\n\nA run's **journal** is its durable record: `state.json` (goal, seats, context,\nbudget, journey reference, end stamp), `ledger.md`, `transcript.md`,\n`context.md`, `log/` (the seat traces), spend files, the mailboxes, and a\ngenerated `JOURNAL.md` cover page. Not the seats' worktrees — those are\nbranches in the project repo already. The repo root carries a **master index**,\nregenerated on every push: `index.json` for md-agent and `JOURNALS.md` for\npeople — every run across every project with status, spend and goal, linked\nto its cover page — so one pull tells the home screen what the repo holds.\n\n`./runs/` stays the working store and the journal is a filtered copy of it,\nrather than the run directory being a checkout: the seats' git worktrees live\nunder the run directory, and a live run writes every turn.\n\nJournals never go into the project repo (`runs/` is gitignored there on\npurpose: transcripts and traces carry credentials and internal findings).\nThey go to a **private journal repository per project** — `forge-md-agent`,\n`nom-md-agent` — or one shared fallback, configured in\n`~/.config/md-agent/config.json`:\n\n```json\n{ \"journal\": { \"repos\": { \"forge\": \"git@github.com:armoryworks/forge-md-agent.git\" },\n               \"remote\": \"git@github.com:armoryworks/md-agent-journals.git\",\n               \"ask\": true, \"autoPush\": false } }\n```\n\n- **At the end of every run** — clean, **interrupted** (ctrl-c), or halted —\n  md-agent asks whether to push the journal. A project with no repo yet is\n  offered `<owner>/<project>-md-agent`, created private with `gh`; or a URL\n  of your own; or the shared repo. Every one of these prompts has **\"No, and\n  don't ask again — ever\"**, remembered globally; pushing stays available from\n  the home screen. \"Yes, and always push\" turns on `autoPush`.\n- **Before every push** the remote's visibility is checked (`gh repo view`):\n  a **public** repo is refused outright, an internal or unverifiable one needs\n  an explicit yes. The journal is also scanned for credential shapes (API\n  keys, tokens, private-key blocks) and a hit blocks the push until confirmed.\n- **Home screen → ⇅ Journals**: push runs not yet pushed, pull journals from\n  the repo into `./runs` (they then appear on the home screen — *Continue*,\n  *Look inside a seat*, *Combine* all work on them), change the project's repo,\n  or set the run-end prompt to ask / auto-push / never.\n\nA pulled run's seats can't reattach to sessions from another machine; on\n*Continue* they are re-seeded from the transcript, which is the same fallback\na local run uses when its session is gone.\n\n### Finding a seat's session again\n\nEvery seat's first prompt opens with a marker line `[md-agent <run>/<seat>#<gen>]`\n(`gen` is 0 for the first session and +1 per recycle), and a claude seat starts\non an id md-agent mints from the same string (`--session-id`), recorded in\n`sessions/` before the first turn runs. On resume a seat reattaches to its stored\nid; with no stored id it searches the CLI's own store for its marker\n(`~/.claude/projects/*/<id>.jsonl`, `~/.gemini/antigravity-cli/brain/<conversation>/`)\nand reattaches to the latest generation it finds; only then does it fall back to\nreplaying its transcript history. A journal carries the claude session files under\n`sessions/claude/`, and a pull puts them where that machine's CLI will look, so a\nrun continued elsewhere reattaches too (paths inside the old conversation are\nstale there; the resume kickoff says so).\n\n### Looking inside a seat\n\nEvery participant's turns are teed verbatim to `runs/<dir>/log/<seat>.jsonl`\n— the orchestrator included — bracketed by md-agent turn markers carrying the\nprompt excerpt, model, duration and usage. The outbox is a seat's status\nreport; the log is its working. Read it three ways:\n\n- **During a run:** type `show <seat>` (a name, its number, or `orch`) at the\n  console — the panel steps aside for a pager and comes back when it closes.\n  `show` alone lists the seats.\n- **From the home screen:** *Look inside a seat*.\n- **From the shell:** `md-agent --inspect runs/<dir> --seat <name>`.\n\nThe rendering collapses tool calls to one line each (`⚙ Bash npm test`),\nshows the head of each result, surfaces permission denials (`⛔ denied Write …`)\nand drops the CLI's bookkeeping events.\n\nEverything below remains available as flags for scripting and automation.\n\nSeed the run with a context document (you'll be prompted to select sections or\ncode blocks from it):\n\n```bash\nnpm run dev -- --context ./brief.md\n```\n\nResume a previous run:\n\n```bash\nnpm run dev -- --resume runs/2026-05-21_00-28-34-my-run         # prompts for the checkpoint interval (defaults to the run's stored value)\nnpm run dev -- --resume runs/<dir> --minutes 15                 # skip the prompt; set it directly (also --minutes=15)\nnpm run dev -- --resume runs/<dir> --quiet                      # no prompts at all: stored interval + budget (what the journey driver uses)\n```\n\nVersion:\n\n```bash\nmd-agent --version        # also -v, or `md-agent version`\n```\n\nWatch a run from anywhere — a second terminal, or a Claude Code session that\nlaunched it detached — built from the run's files alone:\n\n```bash\nnpm run dev -- --watch runs/<dir>            # terminal: the live umbrella, repainted every 2s until the run ends\nnpm run dev -- --watch runs/<dir> --once     # one frame (plain text when piped) — the thing to paste into a message\nnpm run dev -- --status runs/<dir>           # one digest: what each seat is on, its tool calls by kind, last line, cost, artifacts\nnpm run dev -- --watch runs/<dir> | cat      # piped: the digest printed whenever it changes (--every N seconds) until the run ends\nnpm run dev -- --watch runs/<dir> --json     # the frame as data\n```\n\nStop a run that has no console (started detached, or from another terminal):\n\n```bash\nnpm run dev -- --stop runs/<dir>     # places STOP in the run dir; the run tears down cleanly within seconds\ntouch runs/<dir>/STOP                # the same, by hand\n```\n\nThe run's watchdog picks the file up, tells the seats to exit, audits the\nworkspaces, stamps `endedAt`, and — if a journal repo is configured with\n`autoPush` — pushes the journal. `--stop` waits for that and only sends\n`SIGTERM` if the process lingers past 30s. (A `HALT.txt` placed in the dir by\nhand is honored the same way.)\n\nLook inside a seat of any run:\n\n```bash\nnpm run dev -- --inspect runs/<dir>                  # list the seats\nnpm run dev -- --inspect runs/<dir> --seat engineer  # open one's trace in a pager\n```\n\nOn resume you're asked for the checkpoint interval (pre-filled with the run's\nstored value); passing `--minutes` skips the prompt. Either way the choice is\npersisted to `state.json`.\n\nLaunch a run from a config file instead of the wizard (the console UI still\nruns — this only replaces the setup questions):\n\n```bash\nnpm run dev -- --launch ./my-run.json\n```\n\nThe config is a `LaunchConfig` (see `src/persist.ts`): `goal`, `roles`\n(`{name?, description, model?, provider?, permissionMode?}`), and optional `name`, `context` (path\nto a doc included whole), `inbox` (path to a handshake doc prepended as context),\n`maxMinutes`, `teams`, `budgetMinutes`, `autoComplete`, `kickoff`, `runDir`,\n`verify`, `escalation`, `isolation`, `budget`, `journal` (per-run override of\nthe journal settings: `{ remote?, autoPush?, ask? }`). Anything omitted (run name, per-role name/model) is filled\nby the one-time bootstrap turn; supply them all and that LLM call is **skipped**,\nso the run starts instantly.\n\nThe interactive wizard asks this per role. It prints what each backend is suited\nto — claude for judgement, review and anything that can be quietly wrong; agy for\nbreadth, volume and mechanical work behind a verifier — then picks one seat at a\ntime, so the choice is made against the task's shape rather than by habit. The\nconfig/journey path supplies `provider` directly and skips the prompt.\n\n- **`roles[].provider`** — `\"claude\"` (default) or `\"agy\"` (Antigravity, which\n  replaced the deprecated Gemini CLI). Configuration-based, no autodetection. The\n  orchestrator is always `claude`. **Both providers are stateful** — claude resumes\n  with `--resume`, agy with `--conversation` — so an agy seat keeps its context\n  across turns and is recycled on the same schedule. Use agy seats for cheap,\n  mechanical or high-volume role work. agy resolves paths against its\n  *project*, not the process cwd (started bare it works in\n  `~/.gemini/antigravity-cli/scratch`), so every agy turn is bound to the seat's\n  directory with `--add-dir` — under worktree isolation that is the seat's\n  worktree, otherwise the shared tree. The tier (`model`) maps per provider\n  (claude `claude-opus-5` / `claude-sonnet-5` / `claude-haiku-4-5`, agy\n  `gemini-3.1-pro-low` / `gemini-3.8-flash-medium` / `gemini-3.8-flash-low` —\n  low/medium reasoning on purpose: a `-high` turn spends ~60k thinking tokens,\n  and Antigravity's individual plan is a **weekly** cap), or\n  name a concrete id and it is passed through as-is (`gemini-3.1-pro-low`,\n  `gpt-oss-120b-medium`); `agy models` lists what is available. Claude models\n  through agy are a generation behind the `claude` CLI and burn Antigravity\n  quota at 8× — there is no seat where they win. `permissionMode` is honored by\n  both: claude passes it to `--permission-mode`, agy maps it onto\n  `--mode accept-edits` / `--mode plan` / `--dangerously-skip-permissions`.\n- **`isolation`** — `\"none\"` (default) or `\"worktree\"`, asked by the wizard.\n\n  With `\"none\"` every seat edits md-agent's cwd directly. Simple, and fine when\n  the seats are advisory or you trust the run end to end.\n\n  With `\"worktree\"` each role gets its own `git worktree` at\n  `<runDir>/workspaces/<role>` on branch `md-agent/<run>/<role>`, cut from the\n  repo's current HEAD. Seats cannot overwrite each other, and the run's output\n  becomes reviewable artifacts instead of edits already in your tree — audit with\n  `git diff`, keep with a merge, discard with `git worktree remove`. That is what\n  makes a cheaper provider safe to delegate to: a wrong answer is dropped, not\n  reverted back out.\n\n  On teardown the orchestrator prints each seat's directory, branch and diffstat,\n  because an audit surface nobody is told about does not get audited. **When a\n  `verify` command is configured it is run inside each workspace** — the same\n  runner, timeout and output tail as the completion gate, only the working\n  directory differs — and each seat is marked PASS or FAIL with the failing\n  output. That is the difference between \"here are some branches\" and \"here is\n  which branch is safe to merge\": admission becomes informed rather than hopeful. If the\n  target is not a git repo this fails loudly rather than falling back to the\n  shared tree — a silent fallback would leave you believing edits were contained\n  when they were not. `roles[].cwd` overrides it per seat.\n\n- **`roles[].escalate`** — default `true`. Set `false` to pin a seat at its tier\n  so the escalation ladder cannot promote it. A deliberately cheap seat doing\n  bulk enumeration should stay cheap when a verify failure escalates the rest of\n  the team; otherwise escalation quietly erases the cost split the seat was\n  chosen for. If every seat is pinned, escalation logs that and does nothing.\n\n- **`verify`** (`{cmd, cwd?, maxFailures?, timeoutSec?}`) — deterministic completion\n  gate + circuit breaker. The orchestrator's `[[PHASE-COMPLETE]]` is honored only when\n  `cmd` exits 0; a non-zero exit feeds the output back to fix, and after `maxFailures`\n  (default 2) consecutive fails the run HALTs rather than looping. The LLM fixes; the\n  gate decides \"done\".\n- **`escalation`** (`ModelTier[]`, requires `verify`) — on repeated verify failure,\n  climb this tier ladder (re-spawning roles on the stronger tier — resuming their\n  sessions by default, with the failing verify output attached verbatim to the next\n  dispatch) before the circuit breaker HALTs.\n- **`roles[].permissionMode`** — claude CLI `--permission-mode` for that role's\n  session (e.g. `acceptEdits`). See `MD_AGENT_ROLE_PERMISSION_MODE` below.\n- **`roles[].verify`** — this seat's own check over the run's: a `{cmd, …}`\n  spec, or `false` for a seat that produces nothing the command can check (a\n  reviewer). The seat's mandate names the command it is judged by, and its\n  workspace and branch.\n- **`roles[].tools`, `roles[].mcp`, `roles[].turnBudgetUsd`,\n  `roles[].turnMaxSteps`, `roles[].effort`, `roles[].fallbackModel`** — see\n  *Keeping a seat's turns small* above.\n- **`roles[].fallback`** / **`fallback`** — the auto-heal ladder, per seat or as\n  the run's default; see *When a provider runs dry*. `roles[].healed` is written\n  by md-agent when a seat moves.\n- **`roles[].skills`**, **`roles[].projectInstructions`** — see *Keeping a\n  seat's turns small*.\n- **`roles[].readOnly`** — a judging seat: Read, Grep and Glob only (no shell,\n  no writes). Pair with `verify: false`. See *Keeping a seat's turns small*.\n\n`autoComplete` lets the orchestrator **end the run itself** — once the goal is\nmet, every role is idle, and all work is committed it emits `[[PHASE-COMPLETE]]`\nand the run tears down cleanly instead of idling until the budget/a checkpoint.\nOff by default for the interactive wizard (the run stays alive for more work);\njourney phases default it **on** so a finished phase advances the journey\nwithout a human typing `exit`.\n\n### Script mode (a deterministic driver in the orchestrator's chair)\n\nEvery sequencing failure seen in the field runs was a model deciding order: a\nconsumer dispatched before its producer replied, a completion requested in\nthe same turn as a verdict was sent out to be applied. Script mode removes\nthe class. `\"script\": \"./drive.mjs\"` in the launch config replaces the model\norchestrator with a JS function; the run loop, verify, auto-commit, heal,\nbudgets and teardown are unchanged, and the orchestrator's cost is zero.\n\n```js\n// drive.mjs\nexport default async function run(h) {\n  const tables = await h.dispatch(\"sweeper\", \"Produce the three tables … VERIFY-READY when done.\");\n  const [correct, drift] = await Promise.all([\n    h.dispatch(\"reviewer-correctness\", \"Angle 1 …\"),\n    h.dispatch(\"reviewer-drift\", \"Angles 2 and 3, from the sweeper's committed tables …\"),\n  ]);\n  const verdicts = await h.dispatch(\"challenger\", \"Check every finding in both reports …\");\n  await h.dispatch(\"reviewer-correctness\", \"Apply these verdicts, then VERIFY-READY:\\n\" + verdicts);\n  h.note(\"docs/review.md — challenged and corrected\");\n  return \"review complete\";           // the completion reason; the gate runs next\n}\n```\n\n`h.dispatch(seat, ask)` resolves with the seat's full reply — any `[verify …]`\nline first, then its text (which may open with `[SEAT HEALED]`, `[TURN\nCAPPED]` or `[ROLE ERROR]`; the script decides what to do). Asks made in the\nsame tick go out as one turn. `h.read(seat, path)` reads a sibling's file\nfrom its worktree or branch; `h.note(line)` adds to the ledger's artifacts;\n`h.roles` lists the seats. The script's resolved string is the completion\nreason. A thrown error fails the turn loudly and the watchdog halts the run.\n`autoComplete` is implied. Resume restarts the script from the top.\n\n### Per-worktree setup\n\n`\"setup\": \"npm ci\"` runs once inside each seat's fresh worktree before the\nseat starts, and in the gate's merged tree before its check — for repos whose\nverify command needs installed dependencies the checkout does not carry. A\nfailure is reported to the orchestrator as a `[ROLE ERROR]` and the seat still\nstarts; `sessions/<seat>.setup` records the outcome so a resume skips it.\n\n### Journeys (templated multi-phase runs)\n\nDefine an entire campaign up front and let each phase hand off to the next:\n\n```bash\nnpm run dev -- --journey ./journey.json\n```\n\nA `journey.json` is `{ \"name\": \"...\", \"phases\": [ ... ] }` where each phase is a\nlaunch config plus an `id` and optional `pauseBefore`. Phases run **in sequence,\neach as its own child orchestrator** (full console UI, independently resumable).\nWhen a phase finishes, md-agent reads that phase's ledger and authors a **parting\nhandshake** — what it produced, surprises, and suggested role adjustments — into\nthe next phase's folder (`phases/<id>/INBOX.md`), which that phase reads as\ncontext on launch. A handshake may target **multiple downstream phases** when the\noutcome materially changes a later one. Before each non-first phase (unless\n`pauseBefore: false`) the driver pauses so you can read the handshake and edit the\nmanifest live, then `Enter` to launch, `skip`, or `exit`.\n\n**Resuming a journey:** the home screen's *Continue* does this for you. By hand,\n`--from <phase-id>` starts at that phase and skips the ones before it (e.g. after\na crash, a HALT, or a partial prior run). If that phase already has a ledger and\ndid not end cleanly (killed, or halted by the watchdog), it is **resumed** — its\nseats reattach to their sessions and the HALT marker is cleared — rather than\nstarted over:\n\n```bash\nnpm run dev -- --journey ./journey.json --from 05-some-phase\n```\n\nCaveat: `--from` only inherits upstream **context** if those earlier phases\n**actually ran before** — their handshakes live in `phases/<id>/INBOX.md` and\npersist. Using `--from` to skip into a phase on a journey whose earlier phases never\nran means the resumed phase starts with **no upstream handshake**. (`--from` has no\neffect without `--journey`.)\n\n### Time budget (scoping)\n\nSetup and resume also ask for an optional **soft time budget** (minutes). When\nset, every orchestrator turn is prefixed with a live `⏱` line — elapsed and\nremaining — and the orchestrator is instructed (system prompt) to scope work to\nfit: prefer landing small, committable units over starting work it can't finish,\nand **wind down** as the budget nears. The budget is **soft** — once exceeded the\nsignal flips to \"wind down, start nothing new,\" but the run does **not** hard-stop;\nover-runs are tolerated to land in-flight work. The budget is per-session (resets\non resume — \"give it a 15-minute run\"). Blank = no budget (the `⏱` line then shows\nelapsed only).\n\nDuring a run you can type a line at any time to interject (it goes to the\norchestrator, which decides how to propagate it). At a checkpoint you can:\n\n| Input        | Effect                                                |\n|--------------|-------------------------------------------------------|\n| *(text)*     | feedback to the orchestrator, then continue           |\n| *(empty)*    | continue with no feedback                             |\n| *(no input)* | after the grace window, auto-continues (heartbeat stays alive) |\n| `extend N`   | run N more minutes before the **next** checkpoint only|\n| `interval N` | change the recurring checkpoint interval to N minutes |\n| `show <seat>`| open a seat's trace (any time, not only at a checkpoint) |\n| `stop`       | stop one or more seats — hand off or abandon (also **ctrl-x** any time) |\n| `exit`       | stop the run cleanly                                  |\n\n## As a Claude Code skill\n\n```bash\nmd-agent skill install            # every project on this machine → ~/.claude/skills/md-agent/\nmd-agent skill install --project  # this project only → ./.claude/skills/md-agent/ (commit it to share)\n```\n\nTeaches Claude Code when a task is a team job (a cheap complete check, parallel\nparts, branches to review, work that outlives the session), how to write a\nlaunch config, the console commands, and how to read a run. It is picked up at\nthe start of the next session, in the CLI, desktop app and IDE extensions;\n`/md-agent <goal>` invokes it by name, or Claude reaches for it on its own when\na task looks team-sized. `md-agent skill uninstall` removes it, `skill show`\nprints it. The skill ships in the npm package under `skills/`.\n\nYou're offered it the **first time the home screen opens** on a machine that\nhas Claude Code but not the skill — install user-wide, for this project, not\nnow, or don't ask again. (There is deliberately no install-time script: current\nnpm hides install-script output and flags packages that have one.)\n\n## Configuration (environment variables)\n\n| Variable                  | Default      | Purpose |\n|---------------------------|--------------|---------|\n| `MD_AGENT_ORCH_MODEL`     | `sonnet`     | The orchestrator's model — a tier (`opus`/`sonnet`/`haiku`) or a concrete model id. It re-reads a ledger and routes, so it does not inherit the CLI's default model; set `opus` when there is no `verify` and judgement is the whole job. |\n| `MD_AGENT_PLANNER_MODEL`  | `claude-fable-5-1` | The model that plans a team in the wizard's *Have Claude plan it* fork — a tier or a concrete id. |\n| `MD_AGENT_ORCH_TOOLS`     | unset        | `all` gives the orchestrator its edit tools back (`Write`, `Edit`, `MultiEdit`, `NotebookEdit`, `Bash`). Off by default: a coordinator that can edit will do the seats' work itself. |\n| `MD_AGENT_HANDSHAKE_MODEL`| *(orch model)* | Model for the short between-phase handshake turn in a `--journey` run. Falls back to `MD_AGENT_ORCH_MODEL` (never the CLI default, which may be a premium model). |\n| `MD_AGENT_CHECKPOINT_GRACE`| `120`        | Seconds a checkpoint waits for your input before auto-continuing and arming the next one. `0` = wait indefinitely (block until you respond — the old behavior). |\n| `MD_AGENT_HEARTBEAT_STALL` | `360`        | Seconds a role's claude turn may produce **no stream output** before the watchdog treats it as hung and re-spawns it (resuming its session) + re-issues the work. The session beats a heartbeat on every output chunk, so a busy turn stays fresh; only a genuinely stuck turn (e.g. a tool call that never returns) goes silent this long. A dead (crashed) role is recovered immediately via its exit event regardless. |\n| `MD_AGENT_TEAMS`          | off          | Pre-sets the **\"allow sub-teams?\"** setup-wizard prompt to \"yes\". Sub-teams are opt-in **per run** — the wizard asks at setup and the choice is stored in `state.json`. When allowed, the orchestrator may send two roles into a 1:1 **huddle** (`TEAM: <name> members=a,b`): they iterate directly and only one consolidated result returns to the orchestrator — the back-and-forth never enters its context. |\n| `MD_AGENT_TEAM_MAX_ROUNDS`| `12`         | Hard cap on huddle exchanges before the reporter is forced to summarize (runaway-loop backstop). Per-team override via `maxRounds=` in the `TEAM:` block. |\n| `MD_AGENT_ORCH_STALL`     | `600`        | Seconds the orchestrator may sit idle with **no role work pending and no turn** before the progress watchdog nudges it (and, after `MD_AGENT_ORCH_MAX_NUDGES`, HALTs). Catches the orchestrator-side deadlock the role watchdog can't see. |\n| `MD_AGENT_ORCH_HANG`      | `360`        | Seconds the orchestrator's own claude turn may produce no output before it's treated as hung mid-turn → HALT (no self-recovery, which would re-enter the stuck path). |\n| `MD_AGENT_ORCH_MAX_NUDGES`| `2`          | Consecutive progress-watchdog nudges with no advance before the run HALTs. |\n| `MD_AGENT_SKIP_PREFLIGHT` | unset        | Skip the launch-time agent readiness probe (P4). Set for offline / fast-iteration runs. The claude probe runs on haiku with no tools, MCP or session file, and its cost (like the bootstrap's and the planner's) is booked into the run as `sessions/preflight.cost.json` etc. |\n| `MD_AGENT_MAX_EVENT_CHARS`| `16000`      | Choke-point (P2): a role reply longer than this is spilled to `runs/<dir>/spill/<role>-<ts>.md` and the orchestrator gets a head excerpt + pointer. `0` disables. |\n| `MD_AGENT_MAX_LEDGER_CHARS`| `8000`      | Ledger size target. The ledger is re-read AND re-emitted every turn, so bloat taxes every later turn twice; past this size the next turn carries a deterministic compact-now nudge. `0` disables. |\n| `MD_AGENT_ROLE_RECYCLE_TOKENS` | `200000` | Recycle a role session when its resident context — what its last model call read (input + cache read + cache write), i.e. what every call of the next turn re-reads — reaches this many tokens. Measured per call, not summed over the turn. `0` disables. |\n| `MD_AGENT_ROLE_RECYCLE_TURNS` | `8`      | Role-session recycling: after N turns, a role writes a ≤300-word handoff note and is reseeded as a fresh session (mandate + handoff), bounding its ever-growing resident context (and cache-read cost per turn) on long runs. `0` disables. The per-turn `ctx ~Nk tok · cache X% hit` role log, and the live per-seat cost shown in the dashboard, are the data for tuning N. |\n| `MD_AGENT_ROLE_PERMISSION_MODE` | unset  | Default `--permission-mode` for claude-backed roles (e.g. `acceptEdits`, `bypassPermissions`). Headless `-p` sessions auto-deny tools the host settings don't allow, so roles that edit files need this (or a per-role `permissionMode` in the launch config, which takes precedence) on hosts without a global allowlist. |\n| `MD_AGENT_ESCALATION_FRESH` | off        | Escalation (P1c) re-spawns roles on the stronger tier **resuming their sessions** by default (they keep everything learned attempting the fix). Set to discard that context and start the upgraded team fresh instead. |\n| `MD_AGENT_NO_DASHBOARD`   | unset        | Disable the sticky top-of-console status panel (also auto-disabled when stdout isn't a TTY). |\n| `NO_COLOR`                | unset        | Disable ANSI color in the dashboard. |\n\nPer-role models are chosen automatically by the orchestrator at setup when a\nseat leaves `model` unset (each role is assigned `opus`/`sonnet`/`haiku` by\ncognitive load); a launch config can pin a tier or a concrete id. The concrete\nids per tier live in `src/persist.ts` (`MODEL_IDS` for claude, `AGY_MODEL_IDS`\nfor agy).\n\n## Cost tracking\n\nToken usage and USD cost are captured from each `claude` turn and accumulated per\nparticipant in `sessions/<who>.cost.json`. The run-wide total is shown live in the\ndashboard header, and each role logs its per-turn and cumulative cost to the\nconsole.\n\n## Run layout\n\n```\nruns/<timestamp>-<name>/\n├── state.json          # goal, roles, models, checkpoint interval; \"endedAt\"/\"endReason\"\n│                       #   once torn down cleanly; \"journey\" for a phase run;\n│                       #   \"completedAt\" when shelved (Restore clears it)\n├── ledger.md           # orchestrator's memory (stateless across turns; resume reads this)\n├── context.md          # large shared-context brief (only when > ~2 KB) — the orchestrator\n│                       #   gets a pointer + excerpt in its prefix and reads this on demand;\n│                       #   roles always carry the full brief in their instructions\n├── transcript.md       # full conversation (orchestrator is sole writer)\n├── log/<seat>.jsonl     # every turn's CLI stream, verbatim — the seat's working (orchestrator too)\n├── inbox/<role>.txt     # orchestrator → role\n├── outbox/<role>.txt    # role → orchestrator\n├── teams/<name>/channel.md  # huddle transcript (only when sub-teams are used)\n└── sessions/\n    ├── <who>.txt        # the seat's current session id (claude ids are minted up front — uuid v5 of run/seat#generation)\n    ├── <who>.sessions.jsonl # the seat's session lineage: one line per generation (+1 per recycle)\n    ├── <who>.cost.json  # accumulated token usage + cost (also preflight/bootstrap/planner)\n    ├── <who>.window.json # latest plan-window utilization a claude seat saw\n    └── claude/<id>.jsonl # (journals only) the claude CLI's own session transcripts, restored on pull\n```\n\n> **`runs/` is gitignored.** Transcripts capture full agent conversations and can\n> contain credentials, secrets, and project-internal findings — never publish\n> them.\n\n## Project layout\n\n| File                   | Responsibility |\n|------------------------|----------------|\n| `src/index.ts`         | CLI entry / arg parsing (`init`, `--inspect`, …) |\n| `src/home.ts`          | home screen: run discovery, continue/resume/inspect/combine/shelve menus |\n| `src/init.ts`          | `md-agent init` — starter launch config |\n| `src/watch.ts`         | `--watch` / `--status`: the umbrella and the digest from a run's files |\n| `src/stop.ts`          | `--stop`: end a detached run cleanly |\n| `src/journal.ts`       | journals: private repo per project, push/pull, visibility + secret checks, the run-end offer |\n| `src/inspect.ts`       | seat traces: render `log/<seat>.jsonl`, pager |\n| `src/plan.ts`          | the planner: goal + repo + design brief → recommended team |\n| `src/theme.ts`         | ArmoryWorks palette, the mark, ANSI helpers |\n| `src/orchestrator.ts`  | setup wizard, run loop, ledger turns, dispatch, checkpoints |\n| `src/team.ts`          | sub-team engine (1:1 huddle) — opt-in via `MD_AGENT_TEAMS` |\n| `src/role.ts`          | role child-process loop |\n| `src/claude.ts`        | `claude` session wrapper (spawn, session-id, usage capture) |\n| `src/ipc.ts`           | file-based inbox/outbox + transcript helpers |\n| `src/persist.ts`       | run state, session ids, cost accounting, transcript replay |\n| `src/dashboard.ts`     | the umbrella: sticky goal + orchestrator/seat tree |\n| `src/parse.ts` / `src/select.ts` | context-file parsing + section selection |\n\n## License\n\n[Apache License 2.0](LICENSE) — © 2026 ArmoryWorks. See `NOTICE`.\n","readmeFilename":"README.md"}