{"_id":"@ghostmind-dev/ensemble","_rev":"41-a58e8adc93cb311bd1ae5623832839a5","name":"@ghostmind-dev/ensemble","dist-tags":{"latest":"0.31.0"},"versions":{"0.1.0":{"name":"@ghostmind-dev/ensemble","version":"0.1.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","opencode","openrouter","llm","cli"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.1.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"3adf7eed97921e90fd60cea3ad37561c9ed892fe","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.1.0.tgz","fileCount":22,"integrity":"sha512-eTz6nP5KGK8MRhss6wtQV5BHT0KMaEZGEvCuvyq6WouOVC5FuN3RMx6o1MCnkjrrx2WDNPO3LTYdlGvkV7cmfA==","signatures":[{"sig":"MEYCIQDj/Vjqndl3oAj6i+Tx2xVsqiCvAMH8qVTTnbRgaVwKUAIhAN55U1YO4MRvWNXinvj/KLH2DAIMCdYXGuayIYM6j8K7","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":141116},"type":"module","engines":{"node":">=22.6.0"},"exports":{".":"./src/index.ts","./package.json":"./package.json"},"gitHead":"677b762515167a05c66e19b72b659da0184c5687","scripts":{"graph":"node src/cli.ts","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"deprecated":"Broken: shipped raw TypeScript, which Node cannot load from node_modules. Use 0.1.1+.","repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@opencode-ai/sdk":"1.18.15"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"peerDependencies":{"opencode-ai":">=1.18.0"},"peerDependenciesMeta":{"opencode-ai":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.1.0_1786310925818_0.8367519960508438","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@ghostmind-dev/ensemble","version":"0.1.1","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","opencode","openrouter","llm","cli"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.1.1","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"799a38f5d21a4a55bc9a35a33f6f270c4a0b8f46","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.1.1.tgz","fileCount":65,"integrity":"sha512-vefBTwxlll4H6SSi8AerLt8c+96PzDyJX8qSGxKTkTa6SMltw2NA8p2bs5gwjZKdsFEw/2KZqKqI0Hx8SqjAMg==","signatures":[{"sig":"MEUCIAdAx+wHKP3OOf4NqXDu9BcvRknKNzb90BkRUdNMcHReAiEA7Nm/sOwQac9sUZjSmZ5VFU9xvsegluer3+z+YHUbHCk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":258367},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"41d71449708dc9f7fdf2afad790e7048e0cd1a59","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@opencode-ai/sdk":"1.18.15"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"peerDependencies":{"opencode-ai":">=1.18.0"},"peerDependenciesMeta":{"opencode-ai":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.1.1_1786311245980_0.18712217384639152","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@ghostmind-dev/ensemble","version":"0.2.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.2.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"6c92dfc49ac96948dd71ad8bdbf981b3fb12975b","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.2.0.tgz","fileCount":69,"integrity":"sha512-9wrIHcEYSZO0wNsTYyIIuCzrOs5Pbbx4DoNm/61WQP9jxq/PUBrhiEQ6mt2kK3c6k8xBdM7A39d6kH/7mB+obA==","signatures":[{"sig":"MEUCIQCXzE0Crd+66H4bgFuXeYuxXW6iFHhTUPWdS+wepMOS9AIgPgKWZQ38bkLkHN8Be+eOPUgR0nUbqpfdyZKYcNohUrE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":285779},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"fadd5c5373fbae4d46256be9bb6893841457dc86","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.2.0_1786313428746_0.8729299620430309","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@ghostmind-dev/ensemble","version":"0.2.1","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.2.1","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"9da0d56e9492e94169a39e1a0d8649fe16f43191","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.2.1.tgz","fileCount":69,"integrity":"sha512-ZZi4jbyZmYXllAt5jO2iZaxJzYSqlYGUOXVO+X/TwVV1+vXdmxQVZtvx3HvEbaddXDLCw6L8yanRobfmNIonJg==","signatures":[{"sig":"MEYCIQCQ6vkzvsJ7Gd8FNhiaBjQyrj03Dp7YmTzn995dS6j+bQIhANGJg6SAZQETBnAAtKrHyfmQ8kQkySSZVRZzXW50Y84b","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":291801},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"dd01811bb598d64852024587d45e2d61d2537f1a","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.2.1_1786313996285_0.8809896390646303","host":"s3://npm-registry-packages-npm-production"}},"0.2.2":{"name":"@ghostmind-dev/ensemble","version":"0.2.2","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.2.2","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"b591cabc88fad9b31908c0100c23ba7339ca73cf","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.2.2.tgz","fileCount":73,"integrity":"sha512-smWyi5remtQYVUM/RfO9dW88+Tag7tlwPlvqPuP8PLRUVei87p4SetSmFSh2FFyYDXYQHETiNznYDm1FF10c+w==","signatures":[{"sig":"MEYCIQDG7hLjYw/ySfi0TrV7T3VkOVzIba11al80W18MGEEa5wIhAL87ReEwIWZ+yVsUD/wsOWMI/bUU2O94gVy71L/s6qN9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":326224},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"df36f047b05dc81bea639667ed1bf4fcb7634131","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.2.2_1786314603977_0.8438117759390802","host":"s3://npm-registry-packages-npm-production"}},"0.2.3":{"name":"@ghostmind-dev/ensemble","version":"0.2.3","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.2.3","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"87ae8ad0934aff07f71e143f37d63aa87a99c212","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.2.3.tgz","fileCount":73,"integrity":"sha512-AP5cVqrA+Zs/kbi51k33y84HYkPpzurU1SoIIm0jU/UWA9ukv9FcUZ2YdkyRPaaEt/EiKpSAuDnikpj39VwIKQ==","signatures":[{"sig":"MEQCIEu4o1xiX2SkP4kfBbk5QXCfPHc4WCMNjo+9mXlwgGvuAiB0Z6aK63ZhWDHPbHJg71Kel623T5kiWhdyzoJ/6iuEHg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":328084},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"90fbc3c2787d388c168a46a450e385b1cb8ace6e","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.2.3_1786314755749_0.5552376701082968","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@ghostmind-dev/ensemble","version":"0.2.4","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.2.4","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"be01829de0381a1773b4b31448bf5feb90d21c14","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.2.4.tgz","fileCount":73,"integrity":"sha512-jCGWWpbnQqgda0ra3A+IrtNj43S2Cypn8lELEEK7+lDVmS+aCysvUllSMa0qOu+xV9GMELQLJGW63xqzldcK3A==","signatures":[{"sig":"MEQCIFiJIi7sHrFKjS52yowUiy51GzmQy3SD/dXRMUBn6yVnAiA/8yNU8AAm/DXdCXGFPF2ng1qdblk0z4zjOZFYwVbgPw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":334363},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"58cb64c64d55708c0cef4432079d834744cfc120","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.2.4_1786315767491_0.9488724230699053","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@ghostmind-dev/ensemble","version":"0.3.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.3.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"e2d311e7546445eaf7edffd5e969d447c1a7c96c","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.3.0.tgz","fileCount":77,"integrity":"sha512-9TagWuKdurh2eMF6nZCJwxBrohSChSNnD40xwcpTftd2kFzZxFKRhj+RG5IUa29jw/l0iomyGynpbWmvVYu5FA==","signatures":[{"sig":"MEYCIQD2at3Zvb/E67svyqxHOzohfJ69WD8LR7FZm+el/dUtbQIhAOiLWjWZYfO7kYuR9fL5vcYQuj9QVIdjHN00PdYCBSsH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":339476},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"417419672e93c77fbbc4c02fd5f8e7e4bb5cc461","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.3.0_1786316112433_0.8909512657034406","host":"s3://npm-registry-packages-npm-production"}},"0.3.1":{"name":"@ghostmind-dev/ensemble","version":"0.3.1","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.3.1","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"4b577d2452765813f7a3111138bb4d612055f04b","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.3.1.tgz","fileCount":77,"integrity":"sha512-E9BhbO+VNODq9pwCtD0bazZyitfmnpX00i03/UKKmG5iG92Ry2yV96T8EKkcvy1tmumiiPyf/H3yzF+ClWMSuA==","signatures":[{"sig":"MEUCIGYVjY9niD0YreLoeGVBKhXB5dEHMaPzANv+DwXI5me0AiEAoY6QwsTos9t8CxDiiziC73f4CGdg8VV086wm/KN+NGs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":342071},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"d678e68abf47dfdc45f0086597ce76c17f640775","scripts":{"build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.3.1_1786318437757_0.005311172087229643","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"@ghostmind-dev/ensemble","version":"0.3.2","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.3.2","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"74f93686e9502b5f086bb7f73737747fd747788f","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.3.2.tgz","fileCount":77,"integrity":"sha512-WK0cQSPa1n8/WT8809dE1i4TBj6Sf1++ky3mvCdnThYbo/ZHvJ90nnIT3DKG84L7a9GtYKXEizTt+OhIUiSQLQ==","signatures":[{"sig":"MEUCIFnGjmLewRDMvAVPBQt+TKw2lpviVB4PjyUQIimypVEdAiEAwBERkL5PzzCFtG5G9I3Y0fbBKSR7NJcidDj2OXwPvic=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":344821},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"dc30a498f7df5a4a24699c8c874d15c8af4ff281","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.12.1","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.3.2_1786319377044_0.8259392636847587","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@ghostmind-dev/ensemble","version":"0.4.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.4.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"47993ca12bc22385f2d5ba0f01d52056f65bc613","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.4.0.tgz","fileCount":77,"integrity":"sha512-8X4NnkH6eMdL5A6B3EwfF9zOMLkOuiG1YjKPbDX62D7OKUSOIL9qwfRdKEzRsoMmRAy37g9C3VCZvCtASGtMnw==","signatures":[{"sig":"MEQCIFshTFv9q6lVHURJ5rkfWs+U2TaDl3mFWJj4iozohn8nAiBreIxsycNd/dYKdIUJUA9AoZt5xBjtYYYfA41CEBfgiA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":363565},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"fff7af20cd7a01174cc0049ac687be70c8add356","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.4.0_1786983178130_0.3617216948778448","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@ghostmind-dev/ensemble","version":"0.5.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.5.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"b58bdad5d3e5099e6d9f6ddd30b0028357c8faf7","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.5.0.tgz","fileCount":77,"integrity":"sha512-SOrSqt0PMyymcOAJmdxVpZVAWOB+tK1ENvphzn7XZD75dcmDi/fVqEfhYZkGtQlERFCdbi2VQERNI8FiQ0dxkg==","signatures":[{"sig":"MEQCIB/ZKw967PTVZa/cMYwCna+B5TLOJkJMuL51yeMv5LOoAiAwxuYviWlf1kB68yC7zWmT4N2HG0a2R0V4pD5A/PBLlQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":382188},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"c966b9d76e49229dabefd9bd1209d2cf23ab7a35","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.5.0_1786993570573_0.059511935829962725","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@ghostmind-dev/ensemble","version":"0.6.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.6.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"118b2734b2c2b39c44efcf46f38c114853ef4ccb","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.6.0.tgz","fileCount":81,"integrity":"sha512-x73YGqb1nV06dW1DABjyCOrw8/Eb5bat/7mTMs9jzXQJoxW+U3/Mk3EkbLYR97ckJocAv6NBo8gBZIcNzH4Zsg==","signatures":[{"sig":"MEQCIGCGWh4JznhE/aeGmx5S7JmptNRvjhmXVPt0zBt15jzuAiAtcIxl7bABb+PYuqAlcK9T8wgsHV9kk3TECEMBNWlkaw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":410445},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"75578b5d98ecbf4c24faa98bbda35f8d99dbd1c4","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.6.0_1786994204743_0.58477217855385","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@ghostmind-dev/ensemble","version":"0.7.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.7.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"226ae9b6aa3f54eb0e9c9f8ace93b8b0cc166fb3","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.7.0.tgz","fileCount":85,"integrity":"sha512-83dd54UJOVBa/Ri0EMhuaVHupwNXJoPAC0x2fo+I7EbrpmqtFbLqZFTjLM+hQEqZNtQh1+q4vTX2Uakxg3yTcw==","signatures":[{"sig":"MEYCIQCW57gcMW7kvzT9lt3f/2YtxmYtnpT6pHA7nKZiGAh37gIhAIJwx3PGj/DKPuvFWIytIOcLcOAAyfVZ1VysPntlseWu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":417868},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"6715aa23824e9e5979fc740da3eb94ef88736e20","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.7.0_1786994586937_0.06548917028837353","host":"s3://npm-registry-packages-npm-production"}},"0.7.1":{"name":"@ghostmind-dev/ensemble","version":"0.7.1","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.7.1","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"0eae96dde0ded6d87b6b96652b2324af39ab08ec","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.7.1.tgz","fileCount":85,"integrity":"sha512-DKP+WKbwd1iqb7MFLDyVZgRUsGKTDVecGpYdrgCsr1fdLfPHG1ZAG4/UeI95H2fvEB9hT9fAGq58Sw25HtpieQ==","signatures":[{"sig":"MEYCIQDA9DMKNzGsPljOSUYtyODDATiefpqqsUATMG5B4rRUxwIhAIhOXC3Z5ojs380lSJuo/+fedMJAP/0DGGXlwXj5+iRS","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":421084},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"0730a8339faf4282f13a684c0dc5055c694495ee","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.7.1_1786999264738_0.6549219774295509","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@ghostmind-dev/ensemble","version":"0.8.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.8.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"cf276426b0b867849be1810b061c260103e2d1ad","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.8.0.tgz","fileCount":85,"integrity":"sha512-SCDlMwZrKqa7JH9hTB5N2xDN8hjlyc52o2iI46x0BuU8SpT+Hup467MXDL+2bEN9u0RgZPvE/wLopyCXCljypQ==","signatures":[{"sig":"MEUCIQDwv0IL2UAhCrf33srrtkjqel6BHndHnk9AMA4SJ9C8jgIgSArTHYFKdH4BW7km+8yJNXHPNA7BbKM3AzgXECrOXPQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":440206},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"d28b5dff0eefab7e0cdce6aa89aba89297521b15","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.8.0_1787000546300_0.5155768792943265","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@ghostmind-dev/ensemble","version":"0.9.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.9.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"cb3f56b7ca80666c3c2c39780b20ca8654843c56","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.9.0.tgz","fileCount":85,"integrity":"sha512-wn2Zl21SPd5IEP4psOoswwM9aDTzpqihiMLunuIazDCTfHoNqVLVa+ru8YITL5IW0aSY+KEIKk+9CDSwlHGm1g==","signatures":[{"sig":"MEQCIEdgMPkPjoEvwzgRONtIKbsTjwWIjqUP4L//fd2KoIKWAiA2SXRzFtUy4+C7IMlpI0wuN4pLF3zw47HJ6Pkkve3DnA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":445431},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"8e8baf0b08904dea37666188baa0c306a3db668b","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.9.0_1787002766311_0.39574776287062563","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@ghostmind-dev/ensemble","version":"0.10.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.10.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"de744099f9de2e29bcd171b88c4ea73f23cc517e","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.10.0.tgz","fileCount":85,"integrity":"sha512-KOgKIMMRKXZ6CzH3yUfB3jAt2Uafbgg9mQE25RIJ2iL2Jzb+tmww5Ndq/X6NYTRSHKaTvSdh9vA1XRzwE3+jEw==","signatures":[{"sig":"MEUCIE8ZKdgaFSohB6Q0HpNPd0rW6ZdV5OKkjZdYgML9NDxDAiEAw30z/AsdDmKxCqLahNV05QunzqTI9jfLuOTl6vKzbKw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":458977},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"4c7671a5124db3fc1e66d7603fb93f1d84bd033c","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.10.0_1787003351300_0.2143334704633968","host":"s3://npm-registry-packages-npm-production"}},"0.10.1":{"name":"@ghostmind-dev/ensemble","version":"0.10.1","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.10.1","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"dccc2fc66eee6614774ba1b5be477db185b2b553","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.10.1.tgz","fileCount":89,"integrity":"sha512-TVbhqITmMefWRTKbO9Ngv9yOUHilND6oKVir292wHCQahpMsWAr/D3puJrOMxTGbta1ciMbOGaiUdGpoYry3uQ==","signatures":[{"sig":"MEUCIGq26KUHaBn/PzebrLsT21nwesNvKpGDrFBIMW8MHXURAiEAk1rEseATG0B27HcrhRiXRp0YzhrwfhwFpjoEkPDVUYk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":473899},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"054a06112ed6e30d46ea4aafe85dc8ce4d0cf66f","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.10.1_1787005496720_0.9996539795495207","host":"s3://npm-registry-packages-npm-production"}},"0.10.2":{"name":"@ghostmind-dev/ensemble","version":"0.10.2","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.10.2","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"b5450bb7a5d0d75ad87e3671e3852d7ea6997ae1","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.10.2.tgz","fileCount":89,"integrity":"sha512-rDC38pWV3t1kSnzejoM4+9kz1EVXCAPRhSpn8RnQOkfuLT5Kb0AG8/xRh7rM2W82Yl/8s4SetKgCwSOf8BNdUQ==","signatures":[{"sig":"MEUCIQD8AhNRgSZh4zBLM8cJr9Nfbu75ljHa46k5nArqkI4lQQIgP0rHyP5Zyf2uC/JGXPInWAimGkSGPX1L8vd0MzwbxdU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":478353},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"a05ef35d3550ecfd638a7226ccc8472c79ea1500","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.10.2_1787006524281_0.24675902836449537","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@ghostmind-dev/ensemble","version":"0.11.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.11.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"801c1cb4ec441288a10657e622704a797684368a","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.11.0.tgz","fileCount":93,"integrity":"sha512-XHbnOg5qaJSkUmbD+BVhU+GiPIO4pXnbq6oiLY2lKMWv5ajo87FAH00sda6Ika8rHrxx08F7Yl9hplDvHgpa0w==","signatures":[{"sig":"MEQCIHT2Gm52Dp2jz189tBQ6Rkj/zSAOR1KW1WGWCoGYtF+BAiBS+xN/oCZ1t5MytWvyXisNv5Apl8YbAs/9g9r+WzEKhg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":499203},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"cd889a6197e23121aedd3eb3718a5c5a71c9720f","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.11.0_1787010394158_0.84628519848773","host":"s3://npm-registry-packages-npm-production"}},"0.12.0":{"name":"@ghostmind-dev/ensemble","version":"0.12.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.12.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"77a6b6a150175a2fc95581b7abea083695377b60","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.12.0.tgz","fileCount":97,"integrity":"sha512-Jt2kzkU85iEPRMDgJPD5fyG0AGRvRPwMXuKgb2Fe73PKIcF3EZ8cqH82ED3LKHpAu5H8rmXNQVFN8pELc2aowQ==","signatures":[{"sig":"MEUCIB7Vljn6mulCig+QgvJb/m4ceobf1DLWTKUJTRJCjQPsAiEAvMMd2M0/IGgFUho5euV1Zb9VKNsXeWjgXF/9yml/5w4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":512403},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"f73a5cedd64d363b07d6f5a75b67db00880f9344","scripts":{"bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.12.0_1787101983970_0.8840187989914818","host":"s3://npm-registry-packages-npm-production"}},"0.13.0":{"name":"@ghostmind-dev/ensemble","version":"0.13.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.13.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"3dc4bfa43e745fb339e3b6640fb093e499624b04","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.13.0.tgz","fileCount":97,"integrity":"sha512-qocvoFe5eL5/6xg+KbHJmes4BulurMhR9hkdOCNEuARqaOrizqzgw3tIFdNaIJadbly84qRGZN2wLnJpcoIzuw==","signatures":[{"sig":"MEYCIQCH+kxcpz6b1WXo6H1oXn45wBJU7J2Z8RIiIbnLHI4W/QIhAJveSB+gAw9SjpvXbuM+AT2icBqWwoRYlJuHfSZTZwdW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":512996},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.6.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"af721aba23f5bac7072bf02fd1990cfa58a0c427","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test && npm run build"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.13.0_1787148468589_0.47905708902925226","host":"s3://npm-registry-packages-npm-production"}},"0.13.2":{"name":"@ghostmind-dev/ensemble","version":"0.13.2","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.13.2","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"b1cd58ba44e7621d9a2e55c86ac7603957d354c5","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.13.2.tgz","fileCount":97,"integrity":"sha512-U3cCVhm416bNC3NvvqOemjgOqeW8rtHgyPaLtuLlft6dI2bu0jpQFHJSSBlwxkW4wflozICqRAXyS7QqustIMw==","signatures":[{"sig":"MEUCIEdnLF3P7WTj6FUwSPslOKimsFS7MlyzbehCPrTbvGsbAiEA6pv9KkuqFrBhleJdDMoCeD0Kv3T0VJBlC5TdBcoMzt4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":513013},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"56fea7cc8a742deed3a494267b825adf512fb113","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.13.2_1787148749508_0.6181785676884293","host":"s3://npm-registry-packages-npm-production"}},"0.14.0":{"name":"@ghostmind-dev/ensemble","version":"0.14.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.14.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"45ab111eece2476bdbd9d3ba5498d16e69b6a4c6","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.14.0.tgz","fileCount":97,"integrity":"sha512-briH+ukHY/L8YQziLx8XNxUb/dM52q0+RkB9j8NkkisKWqZ1lhgRWCPqJUikU+b09cwuNuLkyRIDQhfUFXVoag==","signatures":[{"sig":"MEYCIQDS+5Hv5dO3oV/CsJzA6PjMcdoqtc4+qh+pNpBml7AefQIhAKg/MaEahvaj87OBfWSqU3TYB/5kX4ugBmgLPEpjPVku","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":517884},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"5dfeb8aa04e8c686a7fcbe51d365c0629049577f","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.14.0_1787169074641_0.3985199044490666","host":"s3://npm-registry-packages-npm-production"}},"0.15.0":{"name":"@ghostmind-dev/ensemble","version":"0.15.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.15.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"f67544f8bb6aa54d13b1c3c2a215b33d02b277eb","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.15.0.tgz","fileCount":97,"integrity":"sha512-Ktnaw8Efv8Tuut0UgCCm6dSiZ7gDFqZSV8NmA2FKYoWfKkBC+W5UIcPO++YF+1PqIvxmbAUyp+7/0VutMLhp8A==","signatures":[{"sig":"MEQCIC4mKfroiQBwj7DHcxL3fiDQ255VEZ1uIOumUQUt02cKAiAIvS2sj4rgmVAqqpRnnFac6yQSoEFCJ3F21+xJ/CH+0g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":532771},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"61d7cbce832d8e120ea5085f9d405e80de2cea62","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.15.0_1787174952522_0.8213786000315952","host":"s3://npm-registry-packages-npm-production"}},"0.16.0":{"name":"@ghostmind-dev/ensemble","version":"0.16.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.16.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"77a2d3669dfd45aba82a2f32fb0fb578aed76aa0","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.16.0.tgz","fileCount":101,"integrity":"sha512-7tdtnAmUj6nOKHbsEXo4VKC+DWx2MhFUm2WOJubnF5TZUHPYoXHmq6DMywvIDhKuzBmhoHLhnALle7cTxIWpxA==","signatures":[{"sig":"MEUCIDJIn43pj/JCuRvZj5IwNc+u3XTsEUxzPRykXV5NJh4SAiEAgxRak7aym2C4TdLVYZmH+Cxh8vFMEogqw0KEHC4H5H8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":552075},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"b5485ba55e9f2023426db2f7ed4ccdb361433442","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.16.0_1787183857404_0.09141826627271832","host":"s3://npm-registry-packages-npm-production"}},"0.17.0":{"name":"@ghostmind-dev/ensemble","version":"0.17.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.17.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"1c6bbe717319cd904ac71efd14a5919655c74836","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.17.0.tgz","fileCount":101,"integrity":"sha512-p1p0FS4d7RoIkJMWnt5WXJUP2SNQXogn+dvvYdYyh4bNAQ61VTZ8zaiHUdbqlG9gLRHCUZLT5xYiKqiKJi+CzA==","signatures":[{"sig":"MEQCIArHcUw9zZc0MuyKtWP/E3lIGJRlnAuQRkNGdjjDm5BhAiBJR/szbZQYDDWz6mvgkoKydvMljZXtUf8bteyAAX143Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":558138},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"3db8df36a94fa146b77c2f83dc8e8df95711e7af","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.17.0_1787184174903_0.8088172613301892","host":"s3://npm-registry-packages-npm-production"}},"0.18.0":{"name":"@ghostmind-dev/ensemble","version":"0.18.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.18.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"6c69af868887ed6aeab93ea3bb7200c9ea889818","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.18.0.tgz","fileCount":105,"integrity":"sha512-rtDykXgTJgIj/23TFMkcHhlo5UtQKmOWBhs+bZaNG1eNBXCY8De196apqmqix35+EgPht2XiWDvfuwC18QO2BQ==","signatures":[{"sig":"MEUCIQCNGU5ecbxuYYhauOh2oaVloCZ3KmwGaC0xh939NlWBngIgNbzgrfB5HLvRXokxHJ2dC/EYv/hLCfYGHTYXI7dl/UQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":566051},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"1b6fe03322970a876856706acb5f3839b22f1f4c","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.18.0_1787184812016_0.4776068111388494","host":"s3://npm-registry-packages-npm-production"}},"0.19.0":{"name":"@ghostmind-dev/ensemble","version":"0.19.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.19.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"be967b6022ed995effc735528aa248ee3c78a6d1","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.19.0.tgz","fileCount":105,"integrity":"sha512-EUg+7PUIAnBmTeh+dtHg7ajPjDkUFKSvIl+J3CsAXSlJQ3Wp1+qalPJhp4yxLTj++KKGLn2Wf3hnHO0tYlDBhQ==","signatures":[{"sig":"MEYCIQD1tJtybL2u7cR2fzmlwEzv6auRAmH/ODGDL8+x2QUkFwIhALix3SIBhDDI5IefJRsRFZd+EmIoObwmGrdUvug12sZg","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":574532},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"2a13663a38c31506623dbad05f3ec8ae28aad9b5","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.19.0_1787185254602_0.08871100507219132","host":"s3://npm-registry-packages-npm-production"}},"0.22.0":{"name":"@ghostmind-dev/ensemble","version":"0.22.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.22.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"4bb5198756274c66e72a4deae51983aed02f793b","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.22.0.tgz","fileCount":133,"integrity":"sha512-PaoIoibdoBXkyn9dbEJJWpUHmHYDtWyUoLxz8kuLsqw23nsU+iqUyKah1iSOyjRKkuaIt/RQ2WT1VxGKQE2IAg==","signatures":[{"sig":"MEUCIQCI6KZQNBYSSyifDJH+jCUt5GzUAJsdFVVTuxJ4/wsgbgIgGWp2992MpZXqbMogNc5nRNweIvLHm5BPt1Na7q+1gnI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":739176},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"e4cce46a5f2412817c64693e4f05c2585f9eff6b","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.22.0_1788016074673_0.1026079844502894","host":"s3://npm-registry-packages-npm-production"}},"0.23.0":{"name":"@ghostmind-dev/ensemble","version":"0.23.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.23.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"78611f5a2e167fa9e831a19f4c8bbd2297962674","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.23.0.tgz","fileCount":145,"integrity":"sha512-84rYgMSzMxfVZtiHfP2geRSyPOBSvIVii4OwiCmWGk4eOO4Qdu+IIycLP8iiKJfXr4mvQD0WDs+8vbLIgSTJhg==","signatures":[{"sig":"MEYCIQDe8Qru2ewuNVIIsQaKjv76pTTt/PeVAItne/4dt1ZjzAIhAMUfEOE16XYyzFO13z+Lsnk6kwnXzTaXxktlJ0rZtxSE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":835750},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"e84629402651819bdc2c4c6f2bfee42dabf1f971","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.23.0_1788576715307_0.10700939242819207","host":"s3://npm-registry-packages-npm-production"}},"0.24.0":{"name":"@ghostmind-dev/ensemble","version":"0.24.0","keywords":["ensemble","agents","multi-agent","multi-model","orchestration","graph","openrouter","llm","cli","mcp","tool-calling"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.24.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"2bfc3a20381151892c7c29fd6f9680098505e8f2","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.24.0.tgz","fileCount":169,"integrity":"sha512-QHxlQ0g/b1GE2K/CqTg7ksjhVXsqtSCqSCwI2ELkjfXyy+HzQkhMqv89k90uKJrXlxm7T6Hor6VZtPVR8bsecA==","signatures":[{"sig":"MEYCIQD75cXuPnEp1Z4YBN6Yp0d0prS+y/T5D0lsndewo4/50AIhALqHNKk13lqGEuIFn9KRpb3OU+5f92SkkkmVFrSL6P4l","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":933131},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"29bd4251e9014c8e05a0ad777a340c4bb25655bc","scripts":{"test":"node test/run.mts","bench":"node bench/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","bench:test":"node bench/checker.test.mts","bench:optimize":"node bench/optimize.mts","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Multi-model agent ensembles. Describe a scene — nodes wired by edges, each node any model with scoped state — in one TypeScript file, and run it: conditions, loops, parallel groups, live visualization.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"zod":"^3.24.1","yaml":"^2.7.0","@modelcontextprotocol/sdk":"^1.30.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.24.0_1788651441692_0.3379952828024959","host":"s3://npm-registry-packages-npm-production"}},"0.26.0":{"name":"@ghostmind-dev/ensemble","version":"0.26.0","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.26.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"fe5b708397e8300e8dd456f5e4a81a208f0f825a","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.26.0.tgz","fileCount":60,"integrity":"sha512-UtjxqLQizzbbVtInDeWtdrevf8Ob4j+t6+D7MZ9RzrM/Nr1Qn8t1am3cLwVBz4RuiPA1Kufzh7M2u9j9j1qnVQ==","signatures":[{"sig":"MEQCIDlf8M70kIS4bRfeD/hosc/tSkFc2wL3M0Yjh40UaGpPAiAMQ8WgIOoy7ANUxf57VHZjUXSfglH3JyOqdHzAEo9IHw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDQ64XWJE4d1yP3Nt3Ei3PPWkr1vWIfSc16wlHubL14xAIgTRlw3Ox0Yq7Nvbecpe0/f2PUc4nflsM3XegkDzoJwZ8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":310376},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"9899541a3ef34acc5315fb26c31e495646de5143","scripts":{"test":"node test/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","directories":{},"_nodeVersion":"24.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.26.0_1789770905343_0.141388159918453","host":"s3://npm-registry-packages-npm-production"}},"0.27.0":{"name":"@ghostmind-dev/ensemble","version":"0.27.0","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.27.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"28cbc933b18e46dc4278a6cf09fd7669276cb2cf","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.27.0.tgz","fileCount":68,"integrity":"sha512-bUcTACPeYplDCjV6E8h3NmSUZZQp3v6HHsK5JjEjAHmYnu+GXvzUeyfkCrtrckDurYlV3LpVkL2YXzD3MSYTyA==","signatures":[{"sig":"MEQCIBOzU/3d0ygSQwqwtR+aSjDMA5UGspqPAXnRphhSgINDAiAtn6Lm21CoP9iEv699G8PzXWhgtewWYg953D4Z2oVYmA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDMkG2jvoTZDuzDzGNligKblegS9T2rx2NTqy71vlveZQIgUZVqO5xbwJbiS6TnxrCaTF5DlffiJgpued2ALnP9hyo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":414233},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"20ae83d46a2018e22cfbde32cb792fa1381d79f4","scripts":{"test":"node test/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","directories":{},"_nodeVersion":"24.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.27.0_1789783044341_0.718553583309353","host":"s3://npm-registry-packages-npm-production"}},"0.28.0":{"name":"@ghostmind-dev/ensemble","version":"0.28.0","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.28.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"dc873f445b65a033c27e0e97b336214d16f0862d","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.28.0.tgz","fileCount":68,"integrity":"sha512-apxkyJ8fkj3okvlmcn4gTfw8GX7t3If84k0zhAB0Qg4JYuNmVWQ3cMS8qeSaq8bBFle8QsnubFtXqyKblba45Q==","signatures":[{"sig":"MEQCIGEGpthKicM2d3s0fmHCwt+WzzMXn76u/Cjqut4yi8wZAiA+rhSBf1y+yn9rGsaH8fkSsFPQG10NVzxBC2Qw78jvhw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDITziUXKvFisdj5MKt2H2dRWayIZlYD2Ei5HJU0TNUjgIhAKRyDRGAr2qUaBmvNXKEoN9K8Q05QJn0L67HBQFXCQtI","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":419964},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"119ed6eb2e24cae6268e1441d6fb17567014edaf","scripts":{"test":"node test/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","directories":{},"_nodeVersion":"24.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.28.0_1789868589791_0.004892575321122861","host":"s3://npm-registry-packages-npm-production"}},"0.28.1":{"name":"@ghostmind-dev/ensemble","version":"0.28.1","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.28.1","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"7382c509a788c08efa980ea87ba877958894db93","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.28.1.tgz","fileCount":68,"integrity":"sha512-QkqOIK7t9Lw5B8dOAy64l/TdVacmkcUlko2uwPBE1fQpDh7z1XHQHaqYCcAaAAqJYGzL7Shz448y5GzzjY+7Cg==","signatures":[{"sig":"MEQCIC6hlVkvdo6lXhSldy+xzk4pGyhUtXplF8y/SFSQA43qAiAe/k7mClwT+Rd9lsbVHEe3AaABJa/KksYzwLqD5EC/Vg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIAhcAofXD9iKc78rwh1DrbnLnFc7zJaB6lGV0x4+yNYeAiEAlZJREol9zzrWzYi3Vc7mjq7pD8e5m3/VFrutCAF3iWc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":425459},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"a4ec0297b90c62bfc0a56a5ca749d14be6009ac0","scripts":{"test":"node test/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","directories":{},"_nodeVersion":"24.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.28.1_1789919776678_0.37914669853527494","host":"s3://npm-registry-packages-npm-production"}},"0.29.0":{"name":"@ghostmind-dev/ensemble","version":"0.29.0","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.29.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"1341d8fd3a722223f7d3d822ff76fdf6bd0c1527","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.29.0.tgz","fileCount":68,"integrity":"sha512-SJlezlxsLsDrSICD/QrHaXGtCzNWAcAaEaQr5OWFrMKiZnBC1laxFwDcQ+7Lrgl3sUx5yKcwU3T0a3kWjkBtgg==","signatures":[{"sig":"MEQCIETp0onlnP/OiTP1TPzF2CeuIq6KbCOJGEQJ9+hujBMtAiACiklwkU+pE7xF1Ff2o72686AXrNWDSIea1EO5xMC6cQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCqBvbDoFgA7toK5qTVq7LLwZ47z2j23QYn45SmmqfqUQIgQ36V1io9pBK5GIBr2UXLZR2cNucYLx7ECVM4BBQAbXo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":427571},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"f7ba35e31807b18f16855eb5b2513ee2e8846712","scripts":{"test":"node test/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","directories":{},"_nodeVersion":"24.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.29.0_1789920741795_0.378007469845546","host":"s3://npm-registry-packages-npm-production"}},"0.30.0":{"name":"@ghostmind-dev/ensemble","version":"0.30.0","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"license":"MIT","_id":"@ghostmind-dev/ensemble@0.30.0","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"homepage":"https://github.com/ghostmind-labo/ensemble#readme","bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"bin":{"ensemble":"bin/ensemble.js"},"dist":{"shasum":"0d337842d354ed8a53eb7b779a417efa1c8bb14a","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.30.0.tgz","fileCount":68,"integrity":"sha512-0XoDoPWKrqJVPENZbviAVwSnZYAodCHSMnkpDwdlrQKtLGckpzuhxhtY3vxePrWncwmTlF6VzDaaLAfPJZLjeA==","signatures":[{"sig":"MEQCIGnJDgxDnLnlTXLVYZ/oJJ2jf5Gq4g6/QFPk1tbqCe25AiB8WA/c8jzno984VewXMZKpCxG02rvN93KVGCuXoNNUUQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIDnUGeqJ9acQXyo80OSPuks+bzDOOqQQ9ZF3bCUA/NVHAiABt9gfSufIBY3bgIFDRwLYbIw7tvVnN4z1EWNfe9QPoA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":522329},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"f7ba35e31807b18f16855eb5b2513ee2e8846712","scripts":{"test":"node test/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","directories":{},"_nodeVersion":"24.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/ensemble_0.30.0_1790276347471_0.2015165796963192","host":"s3://npm-registry-packages-npm-production"}},"0.31.0":{"_id":"@ghostmind-dev/ensemble@0.31.0","bin":{"ensemble":"bin/ensemble.js"},"bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"dist":{"shasum":"9ec73477042efa64a1072533f34396da9a62e109","tarball":"https://registry.npmjs.org/@ghostmind-dev/ensemble/-/ensemble-0.31.0.tgz","fileCount":76,"integrity":"sha512-FhxVrqpgVVO1w/EmUHEb7RKm7uqDXWldKrpukjQnxjlLca5UVNUi/lNRCngcNLfHfCJ1pQpsAUaRmWrktL3gDw==","signatures":[{"sig":"MEUCIGPBWiR5PDDgyp7opJJryK8abROW7Rz7mclCAvPsS2ifAiEA9tZOrf6kvnvOhMlwtO2mRU89d+v1ij0AXdgKzHuo01o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIFcWEEdhx/B25gD8Jq2eyufxN9x5OhCpARrWzPylTcwhAiEAi11LWUXg5ssEgTDDzV6yUXqeHj4EkQUx0ChN1YmD+Ok="}],"unpackedSize":735692},"main":"./dist/index.js","name":"@ghostmind-dev/ensemble","type":"module","types":"./dist/index.d.ts","engines":{"node":">=22.18.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"gitHead":"a1ca8de0177527ab58f9aae6bbdf6337ae9a4a67","license":"MIT","scripts":{"test":"node test/run.mts","build":"rm -rf dist && tsc -p tsconfig.build.json","pretest":"npm run build","typecheck":"tsc --noEmit","prepublishOnly":"npm run typecheck && npm test"},"version":"0.31.0","_npmUser":{"name":"ghostmind_dev","email":"admin@ghostmind.dev"},"homepage":"https://github.com/ghostmind-labo/ensemble#readme","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"_npmVersion":"11.17.0","description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","directories":{},"maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"_nodeVersion":"24.19.0","dependencies":{},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0","@types/node":"^22.10.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ensemble_0.31.0_1790464062463_0.14632191391007843"}}},"time":{"created":"2026-08-09T21:28:45.635Z","modified":"2026-09-26T23:07:42.718Z","0.1.0":"2026-08-09T21:28:45.994Z","0.1.1":"2026-08-09T21:34:06.108Z","0.2.0":"2026-08-09T22:10:28.906Z","0.2.1":"2026-08-09T22:19:56.441Z","0.2.2":"2026-08-09T22:30:04.203Z","0.2.3":"2026-08-09T22:32:35.902Z","0.2.4":"2026-08-09T22:49:27.612Z","0.3.0":"2026-08-09T22:55:12.583Z","0.3.1":"2026-08-09T23:33:57.923Z","0.3.2":"2026-08-09T23:49:37.201Z","0.4.0":"2026-08-17T16:12:58.284Z","0.5.0":"2026-08-17T19:06:10.723Z","0.6.0":"2026-08-17T19:16:44.886Z","0.7.0":"2026-08-17T19:23:07.092Z","0.7.1":"2026-08-17T20:41:04.899Z","0.8.0":"2026-08-17T21:02:26.448Z","0.9.0":"2026-08-17T21:39:26.461Z","0.10.0":"2026-08-17T21:49:11.455Z","0.10.1":"2026-08-17T22:24:56.859Z","0.10.2":"2026-08-17T22:42:04.437Z","0.11.0":"2026-08-17T23:46:34.310Z","0.12.0":"2026-08-19T01:13:04.165Z","0.13.0":"2026-08-19T14:07:48.747Z","0.13.2":"2026-08-19T14:12:29.663Z","0.14.0":"2026-08-19T19:51:14.799Z","0.15.0":"2026-08-19T21:29:12.672Z","0.16.0":"2026-08-19T23:57:37.535Z","0.17.0":"2026-08-20T00:02:55.050Z","0.18.0":"2026-08-20T00:13:32.167Z","0.19.0":"2026-08-20T00:20:54.772Z","0.22.0":"2026-08-29T15:07:54.846Z","0.23.0":"2026-09-05T02:51:55.441Z","0.24.0":"2026-09-05T23:37:21.835Z","0.26.0":"2026-09-18T22:35:05.464Z","0.27.0":"2026-09-19T01:57:24.425Z","0.28.0":"2026-09-20T01:43:09.881Z","0.28.1":"2026-09-20T15:56:16.754Z","0.29.0":"2026-09-20T16:12:21.889Z","0.30.0":"2026-09-24T18:59:07.560Z","0.31.0":"2026-09-26T23:07:42.554Z"},"bugs":{"url":"https://github.com/ghostmind-labo/ensemble/issues"},"license":"MIT","homepage":"https://github.com/ghostmind-labo/ensemble#readme","keywords":["jev","typesafe","classifier","decision","routing","workflow","graph","confidence","agent-skills","mcp","openrouter","llm"],"repository":{"url":"git+https://github.com/ghostmind-labo/ensemble.git","type":"git"},"description":"Typed decisions wired to your code. Asks Jev one calibrated question, calls models through OpenRouter when a node needs to write, draw or look, and emits the graph and the run as JSON.","maintainers":[{"name":"ghostmind_dev","email":"admin@ghostmind.dev"}],"readme":"<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/ghostmind-labo/ensemble/main/docs/images/hero.png\" alt=\"ensemble — one calibrated decision, wired to your code\" width=\"760\">\n</p>\n\n<p align=\"center\">\n  <a href=\"https://www.npmjs.com/package/@ghostmind-dev/ensemble\"><img alt=\"npm\" src=\"https://img.shields.io/npm/v/@ghostmind-dev/ensemble?color=1f5c47&label=npm\"></a>\n  <img alt=\"node\" src=\"https://img.shields.io/badge/node-%E2%89%A522.18-1f5c47\">\n  <img alt=\"runtime dependencies\" src=\"https://img.shields.io/badge/runtime%20deps-0-1f5c47\">\n  <img alt=\"license\" src=\"https://img.shields.io/badge/license-MIT-1f5c47\">\n</p>\n\n---\n\n## The goal\n\n**To build systems that decide for themselves, run for days, and can tell you afterwards exactly what they knew and how sure they were.**\n\nNot a smarter agent — a structure around one. A graph of steps, a shared state\nevery step reads and writes, a calibrated judgement at each fork, and a record of\nall of it as JSON.\n\nAgents with tools are winning on open-ended work, and nothing is watching them.\n`ensemble` is what watches: it makes the decisions that steer the work, carries\nthe memory between runs, caps the spending, and writes down every answer with its\nown confidence. The work itself stays yours — any library, any SDK, any agent,\ninside a handler you wrote.\n\n```ts\nconst { result, run } = await triage({ goal: \"I was charged twice for A-104\" });\n\nrun.steps[0].answers.team\n// → { type: \"choice\", value: \"billing\", confidence: 0.91,\n//     probabilities: { billing: 0.91, orders: 0.06, account: 0.03 } }\n```\n\nThat second line is the product. Not *the model said billing* — **billing at\np=0.91, here is the whole distribution, and here is what it cost.**\n\n---\n\n## The idea in one picture\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/ghostmind-labo/ensemble/main/docs/images/division-of-labour.png\" alt=\"Meaning, arithmetic, perception, effects\" width=\"100%\">\n</p>\n\nFour kinds of work, and four different things that should do them:\n\n| Kind of work | Who does it | Why |\n|---|---|---|\n| **Meaning** — which category, is this X, how good is it | [Jev](https://docs.typesafe.ai), through a `decide` node | Calibrated, ~100 ms, ~$0.00002. Every option declared before anything runs |\n| **Arithmetic** — counts, thresholds, dates, prices | a `code` node or a `when:` edge | Classifiers are documented to be unreliable at counting and date ordering |\n| **Perception** — looking at an image, writing, drawing | a `model` node, or any SDK in your handler | Jev takes text and cannot see |\n| **Effects** — send, store, charge, page a person | a `work` handler | Your code, any library. That seam is the point |\n\nEverything else follows from the first row. A classifier answers in **three\nclosed shapes** — yes/no, one-of-N, a rubric position — so every branch of every\ndecision is known *before the run*. That single fact buys a complete graph you\ncan draw, a validator that proves nothing falls through, and a record worth\nauditing.\n\n> With a generative router you cannot enumerate the branches. With a classifier\n> you can.\n\n---\n\n## Install\n\n```sh\nnpm install @ghostmind-dev/ensemble\nexport OPENROUTER_API_KEY=...     # https://openrouter.ai/keys — the only key\n```\n\nOne key, one bill: Jev is served on OpenRouter's System One route, so the\ndecider and every model node go through the same account. Pass it as\n`openrouter: { apiKey }` on the runner instead of the environment if you prefer.\n\nNode 22.18+. Runner files are `.mts`, loaded by Node's own type stripping, so\nthere is no build step. Zero runtime dependencies.\n\nIt is a **library**, not a global tool. Put the dev commands in `package.json`\nand they stay pinned to the project:\n\n```json\n\"scripts\": {\n  \"validate\":  \"ensemble validate\",\n  \"graph\":     \"ensemble graph\",\n  \"check\":     \"ensemble check\",\n  \"calibrate\": \"ensemble calibrate\",\n  \"start\":     \"node run.mts\"\n}\n```\n\n---\n\n# Demo 1 · Route a message, and know when not to\n\nThe smallest thing that is still the whole idea: one question, every option\nwired, and an exit for when the classifier is unsure.\n\n```mermaid\nflowchart LR\n  I([goal]) --> C{{\"classify · decide<br/>team = billing / orders / account\"}}\n  C -->|\"team=billing\"| B[\"to_billing · work\"]\n  C -->|\"team=orders\"| O[\"to_orders · work\"]\n  C -->|\"team=account\"| A[\"to_account · work\"]\n  C -. \"confidence below 0.7\" .-> H[\"escalate · work\"]\n  B --> R([reply])\n  O --> R\n  A --> R\n  H --> R\n```\n\n```ts\nimport { runner, choice } from \"@ghostmind-dev/ensemble\";\n\nexport default runner({\n  name: \"triage\",\n\n  work: {                                     // ← your code. Anything at all.\n    billing: ({ goal }) => myQueue.push(\"billing\", goal),\n    orders:  ({ goal }) => myAgent.run(\"order-lookup\", goal),   // an agent, if you like\n    account: ({ goal }) => myCrm.open(goal),\n    human:   ({ goal }) => pageSomeone(goal),\n  },\n\n  nodes: {\n    classify: {\n      decide: {\n        team: choice(\"Which team should handle this?\", {\n          billing: { what: \"Charges, invoices, refunds\", not_for: \"Where a parcel is\" },\n          orders:  { what: \"Delivery, cancellation, returns\", not_for: \"Money questions\" },\n          account: { what: \"Login, address, personal data\", not_for: \"Anything about an order\" },\n        }),\n      },\n      reads: [\"goal\"],                                  // the ONLY state Jev sees\n      gate: { on: \"team\", min: 0.7, to: \"escalate\" },   // unsure? a person reads it\n    },\n    to_billing: { work: \"billing\", writes: [\"reply\"] },\n    to_orders:  { work: \"orders\",  writes: [\"reply\"] },\n    to_account: { work: \"account\", writes: [\"reply\"] },\n    escalate:   { work: \"human\",   writes: [\"reply\"] },\n  },\n\n  edges: [\n    { from: \"classify\", to: \"to_billing\", on: \"team=billing\" },\n    { from: \"classify\", to: \"to_orders\",  on: \"team=orders\" },\n    { from: \"classify\", to: \"to_account\", on: \"team=account\" },\n  ],\n\n  entry: \"classify\",\n  result: \"reply\",\n});\n```\n\n**Delete one edge and the graph refuses to run:**\n\n```\nnode \"classify\" asks \"team\" but nothing handles \"account\" — the run would fall\nthrough to the exit on that answer. Wire it, or add a default edge from\n\"classify\" with no on/when.\n```\n\nThat check is free, offline, and it is the reason the closed answer space was\nworth having.\n\n```sh\nnpm run validate -- triage.mts          # ✓ triage is sound\nnpm run graph    -- triage.mts | jq .edges\n```\n\n---\n\n# Demo 2 · Look, listen and remember — at the same time\n\nA perception tick. Three lanes run concurrently, meet at one decision, and the\nsystem remembers something across ticks.\n\n```mermaid\nflowchart LR\n  S[\"sense · code\"] -. fork .-> L[\"look · model 👁\"]\n  S -. fork .-> E[\"listen · work\"]\n  S -. fork .-> M[\"recall · code\"]\n  L --> A{{\"assess · decide<br/>join: all\"}}\n  E --> A\n  M --> A\n  A -->|\"action=approach\"| G[\"go · work\"]\n  A -->|\"action=avoid\"| G\n  A -->|\"action=wait\"| W[\"stay · work\"]\n  A -. \"unsure\" .-> W\n```\n\n```ts\nrunner({\n  name: \"senses\",\n  inputs: [\"goal\", \"frame\", \"sensors\"],\n  memory: [\"seen\"],                           // ← survives the tick\n\n  nodes: {\n    sense: { code: () => Date.now(), writes: [\"at\"] },\n\n    look: {                                   // lane 1 — the only node touching pixels\n      model: \"google/gemini-2.5-flash\",\n      prompt: (s) => `What is in front of the robot? Its task: ${s.goal}`,\n      sees: [\"frame\"],\n      writes: [\"scene\"],\n    },\n    listen: { work: \"sensors\", reads: [\"sensors\"], writes: [\"heard\"] },    // lane 2\n    recall: { code: (s) => Number(s.seen ?? 0) + 1,                        // lane 3\n              reads: [\"seen\"], writes: [\"seen\"] },\n\n    assess: {\n      join: \"all\",                            // ← runs once, after every lane arrives\n      decide: {\n        action: choice(\"What should the robot do now?\", { approach: …, avoid: …, wait: … }),\n        novel:  noul(\"Is this different from what a robot on this task usually sees?\"),\n      },\n      reads: [\"goal\", \"scene\", \"heard\"],      // the senses' WORDS, never the frame\n      gate: { on: \"action\", min: 0.7, to: \"stay\" },\n    },\n  },\n\n  edges: [\n    { from: \"sense\", to: \"look\",   fork: true },\n    { from: \"sense\", to: \"listen\", fork: true },\n    { from: \"sense\", to: \"recall\", fork: true },\n    { from: \"look\", to: \"assess\" }, { from: \"listen\", to: \"assess\" }, { from: \"recall\", to: \"assess\" },\n  ],\n});\n```\n\nThree things are being demonstrated, and each is checked before the run:\n\n**Lanes cannot race.** `validate` refuses two lanes that share a node or touch\nthe same state key, in either direction. Write to separate keys and combine after\nthe join. One controller covers every lane, so a failure on one cancels the\nothers, and budget, timeout and cancellation apply to all.\n\n**Jev cannot see, and that is enforced.** Send an image key to a decide node and\nit refuses by name:\n\n```\nnode \"assess\" sends \"frame\" to the decider, but that key holds image data and Jev\ntakes text only. Have a model node look at it and write down what it saw, then\ndecide on that.\n```\n\nWhich is also the cheap architecture: **look once with a model, then ask four\nnarrow questions about the sentence** for a fraction of a cent.\n\n**Memory is declared.** `memory: [\"seen\"]` means the key arrives like an input, a\nnode in the graph writes it, and `graph.json` says what this system remembers.\nNothing else is remembered — and that is visible too.\n\n---\n\n# Demo 3 · Everything at once\n\nThe demos above isolate one idea each. This is what a graph looks like by its\nthird week — **every concept in the library, in one file**, and every path\nthrough it proved for $0 before a token is spent.\n\nA support front desk: look at the screenshot, read the log and recall what has\nbeen seen before — **all three at the same time** — then decide once, answer\nwith a skill inlined, have a second model critique it, score that critique, loop\nwhile it is weak, illustrate only if it matters, and deliver.\n\n```mermaid\nflowchart TB\n  ST[\"start · code\"]\n  ST -. fork .-> LK[\"look · model 👁<br/>sees: screenshot\"]\n  ST -. fork .-> PT[\"pick_tool · code\"]\n  ST -. fork .-> RC[\"recall · code<br/>memory: seen\"]\n  PT --> RL[\"read_log · mcp<br/>tool from state\"]\n  LK --> TR{{\"triage · decide · join: all<br/>area / hazard / urgency<br/>gate: area ≥ 0.65\"}}\n  RL --> TR\n  RC --> TR\n  TR -. \"1 · hazard ≥ 0.6\" .-> AL[\"alarm · work\"]\n  TR -. \"decider down (fallback)\" .-> HO\n  TR -. \"2 · urgency ≥ 1.7 (when)\" .-> AL\n  TR -->|\"3 · area=cosmetic\"| PK[\"park · work\"]\n  TR -->|\"4 · area=bug / question\"| PS[\"pick_skill · code\"]\n  PS --> CW[\"choose_writer · code<br/>catalog + shortlist\"]\n  CW --> AN[\"answer · model<br/>id from state · skill inlined\"]\n  AN --> CR[\"critique · model<br/>another vendor, in prose\"]\n  CR --> RV{{\"review · decide<br/>quality / grounded\"}}\n  RV -->|\"weak or ungrounded\"| TL[\"tally · code\"]\n  TL -->|\"maxLoops: 2\"| AN\n  TL -. \"budget spent\" .-> HO[\"hand_off · work\"]\n  RV --> RM[\"remember · code<br/>memory: last_area\"]\n  RM -->|\"urgency ≥ 1 (when)\"| CD[\"card · model 🎨\"]\n  RM --> SN[\"send · work\"]\n  CD --> AP{{\"approve · decide 👤<br/>by: human\"}}\n  AP -->|\"send_it\"| SN\n  AP -. \"no\" .-> HO\n```\n\n**Every concept, and where it is:**\n\n| Concept | In this graph |\n|---|---|\n| all five node kinds | `decide` (triage, review) · `work` (alarm, park, hand_off, send) · `code` (start, pick_tool, recall, pick_skill, choose_writer, tally, remember) · `model` (look, answer, critique, card) · `mcp` (read_log) |\n| all three questions, one call | `area` choice · `hazard` noul · `urgency` score — asked together at `triage` |\n| a confidence gate | `gate: { on: \"area\", min: 0.65, to: \"hand_off\" }` |\n| a fallback when the decider is down | `fallback: \"hand_off\"` on `triage` — an outage becomes a route, not a crash |\n| a person in the loop | `approve`, a `decide` node with `by: \"human\"` — same closed question, same `on:` edges |\n| safety that outranks the gate | the `hazard>=0.6` edge is **declared first**, so it is tried first |\n| fork / join | three lanes from `start`, meeting at `join: \"all\"` on `triage` |\n| a model that looks | `look` with `sees: [\"screenshot\"]` — and `triage` reads `scene`, never the image |\n| a model that draws | `card`, writing `[\"caption\", \"image\"]` positionally |\n| a model chosen at run time | `answer` with `model: { from: \"writer\" }`, resolved by `choose_writer` |\n| a skill, inlined | `pick_skill` returns a name (or `\"none\"`); `answer` takes `skills: { from: \"skill\" }` |\n| one MCP tool call | `read_log`, with `tool: { from: \"tool\" }` — the graph still says what it can reach |\n| memory across ticks | `memory: [\"seen\", \"last_area\"]`, written by `recall` and `remember` |\n| a loop with a budget | `{ from: \"tally\", to: \"answer\", maxLoops: 2 }`, then `tally → hand_off` |\n| both branch forms | `on: \"area=bug\"` (the node that asked) · `when: (s) => Number(s.urgency) >= 1.7` (arithmetic) |\n\nThe edges are the control flow, and **order is part of it** — first match wins:\n\n```ts\nedges: [\n  { from: \"start\", to: \"look\",      fork: true },   // three lanes, all forks or none\n  { from: \"start\", to: \"pick_tool\", fork: true },\n  { from: \"start\", to: \"recall\",    fork: true },\n  { from: \"pick_tool\", to: \"read_log\" },\n  { from: \"look\", to: \"triage\" }, { from: \"read_log\", to: \"triage\" }, { from: \"recall\", to: \"triage\" },\n\n  // Safety outranks the gate and the routing, because it is declared first.\n  { from: \"triage\", to: \"alarm\", on: \"hazard>=0.6\" },\n  { from: \"triage\", to: \"alarm\", when: (s) => Number(s.urgency) >= 1.7 },\n  { from: \"triage\", to: \"park\",       on: \"area=cosmetic\" },\n  { from: \"triage\", to: \"pick_skill\", on: \"area=bug\" },\n  { from: \"triage\", to: \"pick_skill\", on: \"area=question\" },\n  …\n  { from: \"review\", to: \"tally\", when: (s) => {\n      const quality = Number(s.quality), grounded = Number(s.grounded);\n      return quality < 1.5 || grounded < 0.5;       // read both BEFORE combining\n  } },\n  { from: \"review\", to: \"remember\" },\n  { from: \"tally\", to: \"answer\", maxLoops: 2 },     // the loop, and its budget\n  { from: \"tally\", to: \"hand_off\" },                // spent: a person takes it\n  { from: \"remember\", to: \"card\", when: (s) => Number(s.urgency) >= 1 },\n  { from: \"remember\", to: \"send\" },\n  { from: \"card\", to: \"approve\" },\n  { from: \"approve\", to: \"send\", on: \"send_it\" },   // a person's yes, routed like Jev's\n  { from: \"approve\", to: \"hand_off\" },\n]\n```\n\n**Proving fifteen paths for $0.** The dry run stubs Jev, OpenRouter and MCP,\nanswers for the person from the same script, runs *your* handlers for real, and\ngoes once per declared answer — the person's included:\n\n```\n✓ default              start → look → pick_tool → recall → read_log → triage → pick_skill → choose_writer →\n                       answer → critique → review → tally → answer → critique → review → tally →\n                       answer → critique → review → tally → hand_off\n✓ triage.hazard=0.9    start → look → pick_tool → recall → read_log → triage → alarm\n✓ triage.area=cosmetic start → look → pick_tool → recall → read_log → triage → park\n✓ triage gate tripped  start → look → pick_tool → recall → read_log → triage → hand_off\n✓ approve.send_it=0.9  …\n  edges never taken: e17 (review→remember), e20 (remember→card), e21 (remember→send),\n                     e22 (card→approve), e23 (approve→send), e24 (approve→hand_off)\n✓ frontdesk: 15/15 dry runs completed · $0\n```\n\nRead the first line: three lanes ran, the writer ran three times — one pass plus\na budget of two — and then a person got it. And the report is honest about what\nit did **not** reach: the tail needs a *good, grounded* draft, which `--explore`\nnever produces because it varies one answer at a time. Force it and those edges\nare proven live:\n\n```sh\n… --answer review.quality=2 --answer review.grounded=0.9 --answer approve.send_it=0.9   # → remember → card → approve → send\n… --answer review.quality=2 --answer review.grounded=0.9                               # → … → approve → hand_off\n… --answer review.quality=2 --answer review.grounded=0.9 --answer triage.urgency=0     # → remember → send\n```\n\nThat is the whole development loop: **the graph tells you which branches you have\nnever tested, and testing them costs nothing.**\n\nFull source: [`examples/09-frontdesk/frontdesk.mts`](examples/09-frontdesk/frontdesk.mts).\nA smaller version of the same shape, without the parallel lanes and MCP, is\n[`examples/08-studio`](examples/08-studio/studio.mts).\n\n---\n\n## Short runs and long runs\n\nEverything above is **one function call**. The frontdesk graph is three lanes in\nparallel, one ~100 ms decision, and a model or two: seconds to a couple of\nminutes, inside your request handler, your queue worker or your cron job.\n\n```ts\nconst { result, run } = await frontdesk({ goal, screenshot, log_path });\n```\n\nAt that scale the useful parts are the ones that cost nothing: `validate` before\nyou deploy, `budget` and `stepTimeout` so one bad call cannot hang a request,\nand `run.json` so the answer can be explained afterwards.\n\n`supervise` is what you add **when the tick should repeat** — not something the\ntick needs in order to exist. Same graph, same guarantees; it just gains memory\nbetween runs, budgets across runs, a journal and a watcher. A two-minute run and\na two-day loop are the same code, and you only pay for the second when you want\nit.\n\n---\n\n## A person in the loop\n\n**A person is just another decider.** Give a `decide` node `by: \"human\"` and it\nasks a *person* the same closed questions it would ask Jev — so their answer is\ntyped, their options are wired, and `validate` proves every answer has an edge.\nNo new node kind, no hole in the graph; `graph.json` shows where the people are.\n\n```ts\napprove: {\n  decide: { ok: noul(\"Should this refund be issued as drafted?\") },\n  reads: [\"goal\", \"draft\", \"amount\"],     // what the person is shown\n  by: \"human\",\n  comment: \"reason\",                      // their optional note lands here\n},\nedges: [\n  { from: \"approve\", to: \"pay\",    on: \"ok\" },   // a yes lands as 1 — on: works unchanged\n  { from: \"approve\", to: \"refuse\" },\n],\n```\n\nIt works at both scales:\n\n- **A short run waits.** Pass a `human` handler — a terminal prompt, a chat\n  message with buttons, a form — and the run waits for it. `ensemble run` does\n  exactly that when there's a terminal.\n- **A long wait pauses.** With no handler, the run stops cleanly with\n  `status: \"paused\"` and hands back a plain-JSON snapshot. Store it anywhere and\n  continue later, in any process: `await approvals.resume(paused, { answers: { ok: \"no\" }, by: \"dana\" })`.\n  It's one continuous `run.json`, loop budgets survive the pause, and `resume`\n  refuses if the graph changed in between. Under `supervise`, a paused tick is\n  parked and the loop keeps going.\n\nThe shape that earns it: **Jev takes the common case, a person takes the unsure\nor consequential one** — via a `gate` (Jev isn't sure), a `when:` (the amount is\nlarge whatever Jev thinks), or a `fallback` (Jev couldn't answer at all, because\nthe service was down). Every road ends at the same kind of node, asked the same\nquestion.\n\n---\n\n# Demo 4 · Run for days, and notice when it drifts\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/ghostmind-labo/ensemble/main/docs/images/supervise-loop.png\" alt=\"tick, memory, journal, vitals — with a watcher inside the loop\" width=\"100%\">\n</p>\n\nA runner is **one tick**. `supervise()` keeps one alive: memory between ticks,\nbudgets that stop or rest, a journal a restart resumes from, and a watcher that\njudges whether the whole thing is still going anywhere.\n\n```ts\nimport { supervise } from \"@ghostmind-dev/ensemble\";\n\nawait supervise(worker, {\n  next: async () => ({ goal: await inbox.next() }),   // the sense organ; undefined ends it\n  memory: { topics: \"\" },                             // starting values for the declared keys\n  budget: { total: 20, perDay: 5, perRun: 0.05 },     // perDay RESTS, it does not die\n  run: { stepTimeout: 120_000 },                      // a hung handler fails, not the loop\n  watch: { every: 10, runner: watcher },              // the conscience, below\n  journal: \".ensemble/live\",                          // crash-safe; a restart resumes here\n  onAlert: ({ reason }) => pager.send(reason),        // your effect\n});\n```\n\nLong-running systems rarely fail by crashing. They fail by **drifting**: stuck on\none path, unsure more and more often, repeating themselves, quietly spending. So\nthe supervisor computes vitals — failure rate, gate rate, sameness, spend per\ntick — and hands them to a **watcher, which is just another runner**:\n\n```ts\nconst watcher = runner({\n  name: \"watcher\",\n  inputs: [\"goal\", \"vitals\", \"recent\"],\n\n  nodes: {\n    vitals: { code: () => null },             // somewhere for the arithmetic edges to leave\n    judge: {\n      decide: {\n        progress: noul(\"Do the recent ticks show the work moving toward the goal?\"),\n        looping:  noul(\"Do the ticks keep producing the same result while nothing changes?\"),\n      },\n      reads: [\"goal\", \"recent\"],              // the story as text; the numbers stay out\n    },\n    carry_on: { code: () => \"continue\" },\n    flag:     { code: () => \"alert\" },\n    halt:     { code: () => \"stop\" },\n  },\n\n  edges: [\n    // numbers first, in code — and free. Jev is never asked to compare them.\n    { from: \"vitals\", to: \"halt\", when: (s) => Number((s.vitals as Vitals)?.failureRate) >= 0.5 },\n    { from: \"vitals\", to: \"judge\" },\n    { from: \"judge\", to: \"flag\", on: \"looping>=0.7\" },\n    { from: \"judge\", to: \"carry_on\", on: \"progress>=0.5\" },\n    { from: \"judge\", to: \"flag\" },\n  ],\n  entry: \"vitals\",\n});\n```\n\nAt **$0.00002 a question**, a system can afford to ask whether it is still on\ntrack every few ticks, forever. That is the niche: not a smarter agent, a cheap\ncalibrated conscience around whatever does the work.\n\n**The watched work does not author the evidence.** `recent` carries facts the\nsupervisor wrote — tick, status, path, timing. A tick that handles a support\nmessage or a web page would otherwise be writing the text its own supervisor\nreads. Opt in with `watch: { evidence: \"facts+text\" }` only where the output is\ntrusted.\n\n**Restarts don't repeat side effects blindly.** If the process dies mid-tick,\nthe first `next()` after the restart is told which tick was running and which\nsteps already finished — so an email that was sent is not sent again. And the\nvitals include `costPerCompleted`: spend divided by tasks that actually finished,\nwith the failed attempts charged to them. A cheap decision that sends the work\ndown the wrong branch is not cheap, and that is the number that shows it.\n\nWhat the loop leaves behind:\n\n```\n.ensemble/live/\n  journal.jsonl     every step as it finished, every run, every alert, every verdict\n  checkpoint.json   tick, spend, memory, the recent window — replaced atomically\n  pulse.json        rewritten on every node event: if it goes stale, the process is stuck\n  lock              the pid of the one supervisor allowed on this journal\n```\n\n---\n\n## Does it actually work? Calibrate it\n\n`validate` proves the wiring and a dry run proves the plumbing. Neither says\nwhether a decision is *right*. `calibrate` does — it asks each decide node in\nisolation, no handlers, no models, about $0.00002 a case:\n\n```jsonl\n{\"inputs\":{\"goal\":\"I was charged twice\"},\"expect\":{\"team\":\"billing\"}}\n{\"inputs\":{\"goal\":\"where is my parcel\"},\"expect\":{\"team\":\"orders\"}}\n{\"inputs\":{\"goal\":\"refund please\"},\"expect\":{\"team\":\"billing\"},\"set\":\"holdout\"}\n```\n\n```sh\nnpm run calibrate -- triage.mts cases.jsonl --holdout held.jsonl --budget 0.05\n```\n\n```\n  classify.team  choice · n=120 · right 91.7% · confidence 0.88 · gap 0.031\n    gate min 0.7 → keeps 93.3%, 96.4% of those right\n    gate min 0.8 → keeps 85.0%, 98.0% of those right\n\n  classify.team  dev 91.7% → holdout 89.2% (-2.5%)\n```\n\nThree numbers worth knowing:\n\n- **accuracy** — how often it is right.\n- **gap** — the distance between how sure it was and how often it was right. Near\n  zero means a confidence gate can be trusted. Confidently wrong is the one\n  failure no gate can save you from.\n- **dev → holdout** — tune the wording against `dev`, freeze, then read `holdout`\n  once. A drop of 0.1 or more means the questions were fitted to the examples\n  rather than to the job.\n\nThe gate table is how you pick `gate.min`: it prices every threshold in what it\nkeeps and what it gets right.\n\n---\n\n## The three questions\n\nJev answers in exactly three shapes and refuses everything else. That is the\nfeature.\n\n| Builder | Answer space | Lands on state as | Also returns |\n|---|---|---|---|\n| `choice(instructions, options)` | one of N, max 255 | the option name | `probabilities`, `confidence` |\n| `score(instructions, levels)` | a 2–10 level rubric | a **fractional** number | `probabilities`, `confidence`, `legend` |\n| `noul(instructions, criteria?)` | yes / no | P(yes), 0–1 | — the number *is* the certainty |\n\nA score is the expected value across levels, not the winner: `1.3` means mostly\nlevel 1 with some level 2. That is what makes it useful in a threshold.\n\n**Ask several at once.** Questions in one node go out in a single request and are\nanswered independently — one answer never becomes hidden context for another. A\nspeculative extra question is nearly free, so ask it and let your code decide\nwhether it mattered.\n\n**The key is not an instruction.** Jev never sees a question's key — it is a\nstate key and a branch label for your code. `safe_to_publish: noul(\"Is it OK?\")`\nasks \"Is it OK?\". Put the whole requirement in the question.\n\n**Describe the boundary, not just the option.** `not_for` says what belongs in\nthe *neighbouring* option, which is exactly where classifiers fail.\n\n```ts\nchoice(\"What kind of picture?\", {\n  photo:   { what: \"Photoreal image of a scene\", not_for: \"Explanatory figures\" },\n  diagram: { what: \"Boxes, arrows, labels\",      not_for: \"Photoreal scenes\" },\n})\n```\n\n---\n\n## The five node kinds\n\nA node is exactly one of these, told apart by which key it has. There is no\n`runtime:` string.\n\n```ts\n// decide — one Jev call. The only thing this library does itself.\nclassify: { decide: { team: choice(…), urgent: noul(…) },\n            reads: [\"goal\", \"customer_plan\"],          // the ONLY state sent. Required.\n            gate: { on: \"team\", min: 0.7, to: \"escalate\" } }\n\n// work — one of YOUR handlers, by name. Any library, any SDK, any agent.\nsend: { work: \"billing\", reads: [\"goal\"], writes: [\"reply\"] }\n\n// code — deterministic, free, instant. Where arithmetic belongs.\ntally: { code: (s) => Number(s.rounds ?? 0) + 1, writes: [\"rounds\"] }\n\n// model — one generative call, through OpenRouter. Write, draw, or LOOK.\nlook: { model: \"google/gemini-2.5-flash\", prompt: (s) => `…${s.goal}`,\n        sees: [\"frame\"], skills: { from: \"skill\" }, writes: [\"scene\"] }\n\n// mcp — ONE tool call. Not a loop.\nread: { mcp: { server: \"fs\", tool: \"read_text_file\" },\n        args: (s) => ({ path: s.path }), writes: [\"file_text\"] }\n```\n\n`reads` on a decide node is **required and load-bearing**: accuracy is documented\nto fall as irrelevant detail grows, so the filter is the feature.\n\n`writes` decides what lands on the blackboard: **one key takes the return value\nwhole**, several destructure it, none means the node only had an effect. Watch\nthat first rule — returning `{ rounds: 1 }` for `writes: [\"rounds\"]` nests it as\n`rounds.rounds`.\n\n### Your handlers\n\n```ts\nwork: {\n  photo: async ({ goal, state, signal, report }) => {\n    report({ cost: 0.021, meta: { provider: \"gemini\", model: \"nano-banana-pro\" } });\n    return await myImageApi(goal, { signal });\n  },\n}\n```\n\n`report()` keeps the run record honest about money the runner did not spend.\n`signal` aborts on budget, timeout or cancellation — pass it to your fetch.\n\n**Nothing is off limits in here.** A handler is ordinary TypeScript: a vendor\nSDK, an agent framework running its own loop, a database client, a scraper. The\nzero-dependency rule binds *this package*, not what you build with it. The graph\nshows one opaque step, and the decisions around it stay calibrated and provable.\n\n---\n\n## Branching\n\n```ts\nedges: [\n  // MEANING — a declared option. Static, enumerable, drawable, provable.\n  { from: \"classify\", to: \"gen_photo\", on: \"picture_kind=photo\" },\n  { from: \"classify\", to: \"lettering\", on: \"needs_text>=0.7\" },\n\n  // ARITHMETIC — ordinary TypeScript.\n  { from: \"classify\", to: \"hand_off\", when: (s) => Number(s.complexity) >= 1.8 },\n\n  // No condition: the default. Also satisfies the exhaustiveness check.\n  { from: \"review\", to: \"ship\" },\n]\n```\n\n| `on:` form | Means |\n|---|---|\n| `\"kind=photo\"` | a choice answered with that option |\n| `\"needs_text\"` / `\"!needs_text\"` | a noul at or above / below 0.5 |\n| `\"needs_text>=0.7\"` | an explicit threshold — `>=`, `>`, `<=`, `<` |\n\nA score has no `on:` form on purpose: a score is a number, so it goes in `when:`.\nEdges are tried in declaration order, first match wins, and `maxLoops` on an edge\nis a loop budget that, once spent, lets the next edge take over.\n\n**The confidence gate** fires before any edge: below `min` the run diverts to\n`to`, and the step records `took: \"gate\"`. An unsure classifier should not act.\n\n---\n\n## What it emits\n\n**This library draws nothing.** It emits two JSON documents and leaves rendering\nto whatever you already use. A renderer is opinionated and goes stale; a schema\nis neither. Both are flat `nodes[]` / `edges[]` with stable ids — what dagre,\nelk, graphviz, cytoscape and d3 already eat.\n\n### `graph.json` — what *could* happen\n\n```jsonc\n{\n  \"$schema\": \"https://ghostmind.dev/ensemble/graph-v1.json\",\n  \"runner\": { \"name\": \"triage\", \"hash\": \"sha256:9c92f2f1a59ff24d\", \"entry\": \"classify\",\n              \"inputs\": [\"goal\"], \"memory\": [\"seen\"] },\n  \"nodes\": [\n    { \"id\": \"classify\", \"kind\": \"decide\", \"cost\": \"cheap\", \"reads\": [\"goal\"], \"writes\": [\"team\"],\n      \"decide\": { \"model\": \"jev-latest\", \"questions\": [ /* every option, in full */ ],\n                  \"gate\": { \"on\": \"team\", \"min\": 0.7, \"to\": \"escalate\" } } },\n    { \"id\": \"assess\", \"kind\": \"decide\", \"join\": \"all\" }\n  ],\n  \"edges\": [\n    { \"id\": \"e0\", \"from\": \"classify\", \"to\": \"to_billing\", \"on\": { \"question\": \"team\", \"option\": \"billing\" } },\n    { \"id\": \"e1\", \"from\": \"sense\", \"to\": \"look\", \"fork\": true },\n    { \"id\": \"e2\", \"from\": \"review\", \"to\": \"redo\",\n      \"when\": { \"source\": \"(s) => Number(s[\\\"quality\\\"]) < 1.5\", \"reads\": [\"quality\"] } }\n  ],\n  \"data\": [\n    { \"key\": \"goal\", \"producedBy\": [\"$input\"],            \"readBy\": [\"classify\"] },\n    { \"key\": \"seen\", \"producedBy\": [\"$memory\", \"recall\"], \"readBy\": [\"recall\"] }\n  ]\n}\n```\n\n- **`edges[].on`** names the question *and* the option, so a branch is labelled\n  without guessing.\n- **`edges[].when`** carries the predicate's own source text and the keys it\n  touches. A code branch cannot be enumerated, so instead of pretending, the\n  document tells the truth. Nothing is executed to produce it.\n- **`nodes[].cost`** is a class, not a number: `cheap` is a Jev call, `metered`\n  is your handler, `free` is plain code. Colour by it and the money is visible.\n\n### `run.json` — what *did* happen\n\n```jsonc\n{\n  \"$schema\": \"https://ghostmind.dev/ensemble/run-v1.json\",\n  \"run\": { \"id\": \"20260918T003102-triage\", \"graph\": \"sha256:9c92f2f1a59ff24d\",\n           \"status\": \"completed\", \"cost\": { \"total\": 0.0213, \"currency\": \"USD\" } },\n  \"steps\": [\n    { \"n\": 1, \"node\": \"classify\", \"kind\": \"decide\", \"lane\": \"main\",\n      \"started\": \"2026-09-18T00:31:02.113Z\", \"ended\": \"…\", \"ms\": 96, \"cost\": 0.000021,\n      \"asked\": { \"goal\": \"I was charged twice for A-104\" },\n      \"answers\": { \"team\": { \"type\": \"choice\", \"value\": \"billing\", \"confidence\": 0.91,\n                             \"probabilities\": { \"billing\": 0.91, \"orders\": 0.06, \"account\": 0.03 } } },\n      \"gate\": { \"on\": \"team\", \"passed\": true, \"min\": 0.7, \"measured\": 0.91 },\n      \"took\": \"e0\" }\n  ],\n  \"state\": { \"goal\": \"…\", \"team\": \"billing\", \"reply\": \"…\" }\n}\n```\n\n**The join is one field.** `steps[].took` is an edge id from `graph.json`, and\n`run.graph` is that document's hash. Highlighting the path taken is a\nset-membership test; finding the hot path across fifty runs is a `groupBy`.\n`asked` records what each node was *given*, which is what an audit needs — for a\ndecide node it is exactly what Jev saw.\n\n---\n\n## The CLI\n\nReached through `package.json` scripts, never installed globally.\n\n```sh\nnpm run validate  -- <file>                 # prove the graph      — free, offline\nnpm run graph     -- <file> | jq            # emit graph.json      — free, offline\nnpm run check     -- <file>                 # can it run HERE?     — reads the live catalogue\nnpm run calibrate -- <file> cases.jsonl     # score its decisions  — ~$0.00002 a case\nnpx ensemble run  <file> \"goal\" --budget 0.05     # asks you at a terminal; pauses (exit 3) without one\nnpx ensemble resume <file> paused.json --answer ok=no --by dana\n```\n\nData goes to stdout so it can be piped; commentary goes to stderr.\n\n### The development loop\n\nEach step is cheap and catches a class of mistake the next one cannot:\n\n1. **`validate`** — every option wired, every key with an origin, every lane\n   disjoint. Free.\n2. **dry run** — the bundled `dryrun.mts` stubs Jev, OpenRouter and MCP and runs\n   *your* handlers for real, once per declared answer, then lists the edges no\n   run ever took. Free.\n3. **`check`** — does the model you named exist, can it see, are the keys set.\n4. **`calibrate`** — are the decisions right, and where should the gate sit.\n5. **`run`** — the first one that costs money.\n\n### Let an agent build it\n\nThis repo is also a Claude Code plugin marketplace:\n\n```sh\n/plugin marketplace add ghostmind-labo/ensemble\n/plugin install ensemble@ghostmind-ensemble\n```\n\n| Skill | For |\n|---|---|\n| `ensemble-build` | Use case → a runner that validates and has been dry-run down every branch |\n| `ensemble-questions` | Writing `choice` / `score` / `noul` that Jev answers well, gates and thresholds |\n| `ensemble-runs` | Reading `run.json` and supervised journals, explaining a path, calibrating |\n\nThe plugin is not part of the npm package; the library itself ships no skills.\n\n---\n\n## Skills and MCP, without an agent loop\n\n**Skills** follow the [Agent Skills standard](https://agentskills.io).\n`loadSkills()` reads them from `.claude/skills`, `.ensemble/skills`,\n`~/.claude/skills`, `~/.ensemble/skills` and installed plugins;\n`skillOptions()` turns them into a `choice`. Choosing a skill *is* a\nclassification, so a classifier should do it —\nTypeSafe measured the case at 182 skills: an agent working from truncated index\nentries loaded the wrong one 16.8% of the time, against 7.3% when a System One\nmodel ranked them first. Skills are local files, so the options are knowable\noffline and the graph stays complete.\n\n**MCP** is one server, one tool, one call. Because both are named in the node,\n`graph.json` says exactly what a workflow can reach *before it runs* — the thing\na tool-calling agent can never tell you. Servers start lazily and stop with the\nrun.\n\nA server is a local process or a URL — Streamable HTTP, legacy SSE or\nWebSocket, found automatically — with any auth a hosted server asks for:\n\n```ts\nmcpServers: {\n  fs:     { command: \"npx\", args: [\"-y\", \"@modelcontextprotocol/server-filesystem\", \".\"] },\n  potion: { url: \"https://mcp.potion.run\", headers: { workspace: \"home\" }, auth: { type: \"oauth\" } },\n  search: { url: \"https://api.example.com/mcp\", auth: { type: \"bearer\", token: \"${SEARCH_TOKEN}\" } },\n  keyed:  { url: \"https://x.example/mcp\", auth: { type: \"api_key\", in: \"header\", name: \"X-API-Key\", value: \"${X_KEY}\" } },\n  svc:    { url: \"https://svc.example/mcp\",\n            auth: { type: \"oauth\", grant: \"client_credentials\", clientId: \"svc\", clientSecret: \"${SVC_SECRET}\" } },\n  bank:   { url: \"https://bank.example/mcp\", auth: [{ type: \"mtls\", cert: \"client.pem\", key: \"client.key\" }, { type: \"oauth\" }] },\n}\n```\n\nAlso `basic`, `custom` (a function that returns headers, for SSO or signed\nrequests), device-code login and `private_key_jwt`. Secrets are written as\n`${NAME}` and resolved at connect time through `secretResolver` (default:\n`process.env`); a literal one is a `validate` warning. A person logs in once with\n`npx ensemble mcp login potion` (or `--device` on a machine with no browser),\ntokens live in a 0600 file per server under `~/.ensemble/mcp-tokens/` and refresh\non their own, and a run that needs a login fails at once with that command —\nit never waits on a browser. A hosted app passes `tokenStore` per user.\n\n**A model node never needs tool-calling support.** The `mcp` node makes the call\nitself and puts the result on the blackboard; skills are inlined as text. So a\nsmall model, or a local one, still sits downstream of every tool and skill you\nown. Capability constrains only what a model must do *itself* — vision is the\nreal case, and `ensemble check` catches it against the live catalogue.\n\n---\n\n## Jagged edges\n\nTypeSafe [publishes Jev's known failure modes](https://docs.typesafe.ai/model-jaggedness/jev-1.13).\nThey are design constraints, and several are enforced here:\n\n| Weakness | What this library does about it |\n|---|---|\n| Counting and arithmetic are unreliable | `when:` and `code` nodes exist. Never gate on a Jev-computed number |\n| Dates are read as text, not ordered quantities | Extract with a model, compare in code |\n| Accuracy falls as irrelevant state grows | `reads` is required on every decide node, and is a hard filter |\n| Multi-hop questions lose accuracy | One question, one property. Ask several — they are parallel |\n| State is not treated as hostile | Guard before routing on unvetted text; a watcher reads supervisor-written facts by default |\n| No structural invariants | Calibrate each question on your own data; don't derive one threshold from another |\n| Literal reading | `not_for` on every option. State boundaries, don't imply them |\n| It does not generate | Generation is a model node or your handler, never a decision |\n\n---\n\n## What this deliberately does not do\n\nNo prompts of its own, no built-in agent loop, no vendor SDKs *in the package* —\nyour handlers may use any of them. Skills and MCP are here as choices and single\ncalls, never a model picking its own next tool. No server, no browser viewer, no\nmermaid or markdown exporter. No variable-width fan-out (that is a handler's\njob), no replay.\n\nThose are not oversights — they were removed. Keeping them would have made this a\nframework you live inside rather than a function you call, and the whole point is\nthat **your code owns the control flow**.\n\n---\n\n## Examples\n\n```sh\nnpm run validate -- examples/01-triage/triage.mts\nnode plugin/skills/ensemble-build/scripts/dryrun.mts examples/07-senses/senses.mts \"watch the door\" --explore\n```\n\n| | |\n|---|---|\n| [`01-triage`](examples/01-triage/triage.mts) | The smallest whole idea: one choice, three branches, a gate |\n| [`02-picture`](examples/02-picture/picture.mts) | Real image generation: ask the durable question, resolve today's model in code, draw |\n| [`03-refine`](examples/03-refine/refine.mts) | A loop that knows when to stop — a score gate, a loop budget, counting in code |\n| [`04-robot`](examples/04-robot/brain.mts) | A little brain: a vision model looks, Jev decides, your handler acts |\n| [`05-assistant`](examples/05-assistant/assistant.mts) | Skills and MCP, chosen rather than looped over |\n| [`06-watch`](examples/06-watch/watch.mts) | A conscience for a loop that runs for days — and it supervises `01-triage` when run directly |\n| [`07-senses`](examples/07-senses/senses.mts) | Look, listen and count at once: three forked lanes, one join, a memory key |\n| [`08-studio`](examples/08-studio/studio.mts) | The complex shape: four models in sequence, a budgeted loop, both branch forms, safety first |\n| [`09-frontdesk`](examples/09-frontdesk/frontdesk.mts) | **Everything at once**: five node kinds, three lanes, memory, a skill, MCP, a loop, both branch forms, a person in the loop, and a fallback |\n\n---\n\n## API\n\n```ts\nimport {\n  runner,                           // define one\n  choice, score, noul,              // ask\n  validate, toGraph, execute,       // prove, emit, run\n  calibrate,                        // score the decisions against labelled cases\n  supervise,                        // run it as a loop that lives for days\n  resume,                           // continue a run that paused for a person\n  jev, openrouter, reporter,        // the decider, the caller, the terminal view\n  catalog, shortlist, modelOptions, // the live model list, filtered in code\n  loadSkills, skillOptions,         // Agent Skills from disk\n  connect, pool, toolOptions,       // MCP, local or remote\n  login, logout, fileTokenStore,    // remote MCP auth\n  preflight, searchServers,         // discovery\n} from \"@ghostmind-dev/ensemble\";\n```\n\nEvery seam is a function type, so anything can be replaced: `Decider` (Jev),\n`Human` (a person), `Caller` (OpenRouter), `Handler` (your code). That is what\nmakes the test suite free and offline — and, with `fallback:` on a decide node,\nwhat keeps one young vendor from being a single point of failure.\n\n```ts\nawait triage(inputs, { decider: myStub, caller: myStub });\n```\n\n---\n\nMIT · [ghostmind-labo/ensemble](https://github.com/ghostmind-labo/ensemble) ·\nbuilt to be operated by [Claude Code](https://claude.com/claude-code)\n","readmeFilename":"README.md"}