{"_id":"@gr8ful/spf","_rev":"38-b6fa718345b04089c740f1e011c45d95","name":"@gr8ful/spf","dist-tags":{"latest":"0.23.0"},"versions":{"0.1.0":{"name":"@gr8ful/spf","version":"0.1.0","license":"MIT","_id":"@gr8ful/spf@0.1.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"27e2f031044911feb56a10fca7f4e244b8844949","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.1.0.tgz","fileCount":153,"integrity":"sha512-jmQWbPujRVxS+c6SJVH6Q/oHip4+Bom4nsE4NaZCuLuIDoyTk1sn6RIyHo3tLZzggXmM3Nf8NajRoNAie89AvQ==","signatures":[{"sig":"MEUCIDNfBrL9BCtS5Y2BPNYkA6s93w032J1dO75QV+yGNa2sAiEAy4uq8xGvKXF+ezk4IdLZAdMiVB+kpM6PWFw20DAIf0g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":716002},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"5bf07eaa63ce4764ffd5bc8c47b6a94e24ca954e","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"ryang8","email":"ryan@grateful8.us"},"_npmVersion":"10.9.8","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.1","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.1.0_1787246671826_0.2829971451079305","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@gr8ful/spf","version":"0.1.4","license":"MIT","_id":"@gr8ful/spf@0.1.4","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"dde683888045c94b426d763fb06119465210f870","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.1.4.tgz","fileCount":153,"integrity":"sha512-53xuvErXeIT7gm2JzVqop3Puli2yfXqX3J1PL5wo+Rzqs2wXN/3pR+Rr7Pu+Bg9/hnUOrZxoeeFgxw8AfBzVGg==","signatures":[{"sig":"MEYCIQCwfyKRURg/HMNIOSx0dKn+xF2v7eC4Q7GgJz2mhLgiXwIhAKD7piFHuCJqGcQXMuI5W554N/HJTF603lFcpAe3ohB1","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.1.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":716120},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"87ff571c09e5880760c617203d96a1baef28aa4f","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.1.4_1787247617261_0.22672737383427055","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@gr8ful/spf","version":"0.1.5","license":"MIT","_id":"@gr8ful/spf@0.1.5","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"b832a1ec578747c597728f286fffa68b68c4d733","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.1.5.tgz","fileCount":153,"integrity":"sha512-G51n+esQluUHDDGiaVkY51bBnWzSuP/bcag/583RNdW82Z9nVdVxPEZozJYqASuP1pq26Bovg26+OSUfkNgYxA==","signatures":[{"sig":"MEQCIAdpTNKY0BX6bo0lsDZJkU7TMGdOxwVDo4jZwIePYs2YAiAMaei65wYTRgEeNvB7oYPhi0EMxkm3AdsdY8a0lH1Reg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.1.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":716120},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"739b6c1bc3c77ece9df25e3d194cedaa05fd42bc","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.1.5_1787247859234_0.8885278031052608","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@gr8ful/spf","version":"0.1.6","license":"MIT","_id":"@gr8ful/spf@0.1.6","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"c6fb5ea4cfe90fd0372b24380c124f48c22f54e0","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.1.6.tgz","fileCount":160,"integrity":"sha512-3tfPFnuOg8oz71io0MCqlRNUwu2fk801FgdCpBmFsitnt34ZbO/uoV+0JmMa087jsUaFMZ/HAdfPthD7LZWFRQ==","signatures":[{"sig":"MEQCIGerT/Bt1YXmkG1y/C/CovJcaUxFFQ7AgGzQvN+OoGeqAiBjXHkFPoaAhDmYDXBqkL78WJFDmRwoxGm9/WkfIleQDA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.1.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":753392},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"054e68b30e6cf447c4e44fbd7ab6c8262d70bd70","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.1.6_1787253320811_0.4218979970277348","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"@gr8ful/spf","version":"0.1.7","license":"MIT","_id":"@gr8ful/spf@0.1.7","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"b8f2ea8362edf4ba03b90108b3922c7d1950ba9c","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.1.7.tgz","fileCount":160,"integrity":"sha512-Omaj0XIAHMfEFe9m03StOaBzXqleZGPx+k8uQUY3gzkE8EHZxr2JBZ+w80VjdnsHpPNPehaonCoyVHJdqBPnJg==","signatures":[{"sig":"MEUCIQD4ph5xGu5c+pQwbHRptbJguqFjAG9/pbXbIBMn8f7f8QIgJP01m5ldkUqq2i9dTOocCWFljBUZcYzFyecBHN835qE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.1.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":762467},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"6767ccab6b65ac7fbc029b03f4e20b6cd79d8048","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.1.7_1787259430566_0.9776553474352834","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@gr8ful/spf","version":"0.2.1","license":"MIT","_id":"@gr8ful/spf@0.2.1","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"224907e82cba0ca1b113ffb780f60e6d1ab09799","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.2.1.tgz","fileCount":158,"integrity":"sha512-vM2giSY/gWKXJkuXvNyNf58azWZ44AOApLlSrgtfVgdzfqoZ63iuyFrMUcWU8m8dBhZiMjKvcFat4NYdbrmRKA==","signatures":[{"sig":"MEQCIGKMFzMN54TBef9KLtwwJrFcU/OXU4aopF3JC+iXWrLGAiBPnLngiimDUJevgyjEiFbQt9gNMToceNiIwBQuhP+P+A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":816928},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"58b076a533f65aae4785b8656749ba935cfa63f7","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.2.1_1787317978942_0.7620658360197652","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@gr8ful/spf","version":"0.3.0","license":"MIT","_id":"@gr8ful/spf@0.3.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"20eeca98d600006009a0290c6e820ab83684d8df","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.3.0.tgz","fileCount":170,"integrity":"sha512-spjtZPKxeAYVo8zcfHETJ5as36fVdPnzT/rZNBoBBHa3prP+l7kL/f7puCQplCDj1guWHfr/u+KeUtrYT5MmiQ==","signatures":[{"sig":"MEUCIEpxKZr+a36tUj+79CdlJvq6MevF0mpGbHToqxxYo94cAiEA8sG7JuDoLwP8z4tAS9AmqZre7W8rAc1oQ3IWIahAQGg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":876814},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"c8adcd9f3e4ab0c0f68af4c683ba40af6a75b28d","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.3.0_1787326137004_0.451685258839744","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@gr8ful/spf","version":"0.4.0","license":"MIT","_id":"@gr8ful/spf@0.4.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"81e9ab12e0c4ad33f650f527a4ff11f7c1f51c94","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.4.0.tgz","fileCount":176,"integrity":"sha512-Ied5pMMsqtIx/iWs38vyhPklKJMdpkwwHIo3/8Yw2U4/KVWTW+QZaPZgSAHke0p3THWVuJeGHhpANHluSCq9rg==","signatures":[{"sig":"MEUCIBgG+SjgCIFqeJiUA6BpYLQhPw2aOP6EGxBk/8iTPPbBAiEAgoeLr8nZAaUEKi+kYJcW31kRVRgivdFlg+Lyi4Wy+5k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":964478},"type":"module","engines":{"node":">=22.19.0"},"exports":{".":"./dist/index.js","./core":"./dist/core/index.js"},"gitHead":"238daf47e2642932676403f6393bd5b0668c2fc8","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.4.0_1787406197342_0.36665776070170897","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@gr8ful/spf","version":"0.5.0","license":"MIT","_id":"@gr8ful/spf@0.5.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"0d8901dea19a35523795e59ddd14b5b57c6fa127","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.5.0.tgz","fileCount":196,"integrity":"sha512-rBn2qmCOZd/NHNJJ8bm6Da+QC2KB0/BS/nQ72uh0kYbZZ6MYAdMeKVVSIkHShvOMRc5ZqZTeQEMXgAbludwpeg==","signatures":[{"sig":"MEYCIQCSdIJ9Ip3UScKdg0ZbvrvZ8631uiD4mo5dExtNVk0nqAIhAK9rs5RyOjfpRY/o2xaBgLnzUsNpvVMOInbhc5qU/nht","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1356414},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"9380fb04545890e861bad785acc8b44e47898ef9","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.5.0_1787431353337_0.7815118114741222","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@gr8ful/spf","version":"0.5.1","license":"MIT","_id":"@gr8ful/spf@0.5.1","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"2af35981204f089834b2b9a0c7132bca7bd4faf6","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.5.1.tgz","fileCount":198,"integrity":"sha512-Fw0WAsSpxfZLtdgZPnL6ucEqCDL3jZQBkLtASUsNIM/bwxiEYsV4KSz4JRdnWRcUoZ4DxekiqcEJctq4h+FeSg==","signatures":[{"sig":"MEUCIBLg8hwhGGlO4yJd/ts50RF05P5+fhiDuqHRWTSh3dhqAiEAsXtMR7eLe3/778UtA0cxNWLc7d5cuBdRpAoSSjEzhmk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1363520},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"5a67dd60ca7e66173c8b98468256390848861903","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.5.1_1787432902586_0.97851842563427","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@gr8ful/spf","version":"0.6.0","license":"MIT","_id":"@gr8ful/spf@0.6.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"b40596602821a36c9906ba89f79d3fc02d691804","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.6.0.tgz","fileCount":168,"integrity":"sha512-DOUMrBl688UCqnkWp5OCWBHzvA46rVuh2C5jan4rTVy9z3Zi8R9vLIT8bIVEt18azgdW9oUqt+eNCOsylm+bvQ==","signatures":[{"sig":"MEQCIBtuJSyryiufrJlc9U3LvQAlGA/pHLllrQ7//F1oNS+vAiB/hJ4loAOdWOaRdYOwMJS4O42RsCN1Zn14zbdbL1oiJw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1379056},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"29d2383b36b533ec0a3398484c223b2754244492","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.6.0_1787499586272_0.4723195454884437","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"@gr8ful/spf","version":"0.7.0","license":"MIT","_id":"@gr8ful/spf@0.7.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"7c3c3534ef5f67e2bd9986aaa9343c45eae7879e","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.7.0.tgz","fileCount":168,"integrity":"sha512-scRO0LA+Nh7MMCgKgSorM9s6nGN8fv433gN4GARdf2LRSNcXqujNdfTj9r8d1fnvsUsLtfJ4/Dwdaf++I1KhWA==","signatures":[{"sig":"MEUCIQCRdTTNlNiOYHAvrQfboIOxxYHm+yutMcm2r/cXkqbTuQIgSETSrix2gkwegIVMFAOTd2s3dHN0q2NIOsajEZFyhK0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1455729},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"c1211c188e9644507b332a7f2e6d9662112a86be","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"hono":"^4.13.3","yaml":"^2.5.1","valibot":"^1.4.2","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.7.0_1787579776456_0.4650660746872597","host":"s3://npm-registry-packages-npm-production"}},"0.8.0":{"name":"@gr8ful/spf","version":"0.8.0","license":"MIT","_id":"@gr8ful/spf@0.8.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"19edfb6985cf3e336e34a8613aff474910b66b73","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.8.0.tgz","fileCount":178,"integrity":"sha512-co4KSM92o12RcEfJjUXtsM0LZN+2Wp24YWOvAfhj/hfjI8id2gJ2FI/kYRY72yO7h4s9IZfvA53exWSXJPapRQ==","signatures":[{"sig":"MEQCIFd5OJGkNZmTMX7dAzzYuowNVk2ZLDRjr89Ul5a0NSmEAiBiFAD1rvT9I+D2aCPHTpv/7MmJWNjUyTfi/AP238GiEg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1516461},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"73bc94119f5babc2bd89054607d6275ed49dec91","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.8.0_1787590887583_0.0016021298709505416","host":"s3://npm-registry-packages-npm-production"}},"0.8.1":{"name":"@gr8ful/spf","version":"0.8.1","license":"MIT","_id":"@gr8ful/spf@0.8.1","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"fa067ceba96ac4b0d8a086ec5821c9882c8729fd","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.8.1.tgz","fileCount":178,"integrity":"sha512-t6XsLXxdjDopRNSHCb8DEFq2aEdpgax9hCyXUL81ilJAmYtmFRi/3zjISldk5awaJh4V+DZ7YQE3xfB5GRciJg==","signatures":[{"sig":"MEYCIQDtmo60uIx9cDXb11svSLjMz6gcuCYlxcyNzCyS101tIQIhANhyRXafRXg2XsgQg+9IdTChu7jRPM7Qw0/GaIcl7j4S","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.8.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1519830},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"e926d7f863894bbba70daf06d2a31b29b8802e6b","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.8.1_1787595305690_0.4797971397004259","host":"s3://npm-registry-packages-npm-production"}},"0.8.2":{"name":"@gr8ful/spf","version":"0.8.2","license":"MIT","_id":"@gr8ful/spf@0.8.2","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"61bd03fd178aa77dc8b9d9ae9d3ab53cb8e312d9","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.8.2.tgz","fileCount":178,"integrity":"sha512-GfBMiTqDSrOUsV4strL1uMRFxHJ4rGNrk6Hpa+54/QO89Yg0ucsHOBwrKxM1tlwXPApBDVS5EdIL7KY2UV3rJw==","signatures":[{"sig":"MEQCIAtjs+au2mEjfsey/DiQJzWe0Gfkp3YHzpO5IQH1vOyHAiBC8nt3TIzuItt9R7CBQoIKoC0Ibu464g3MRBkqfomy5g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.8.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1521902},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"5f34a6edface9a5065f74fba40ee18eb2d9d23f4","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.8.2_1787599099949_0.3051518456574349","host":"s3://npm-registry-packages-npm-production"}},"0.8.3":{"name":"@gr8ful/spf","version":"0.8.3","license":"MIT","_id":"@gr8ful/spf@0.8.3","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"93efe685c652d09dba4ca3078d1bd6ab6e191eeb","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.8.3.tgz","fileCount":178,"integrity":"sha512-0ncUSY/ArZd/tZjC6YlXP4q+OKCMLb6oqOcPLUuNiAv/ax09cTT7S9MT139L8q68RDwlcPvhDiU20+QzAp2CJw==","signatures":[{"sig":"MEQCIGfNAVmz020Zf7jFSr67YdfIxf9x29fuNOjtcztJtzDiAiBb26sMuvPmn5jtfBPX9+IknwSFXxIaWUYXL9rXuM6bFA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.8.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1523617},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"7de0e10a2846ac68277b497db51bc3d4363b2afd","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.8.3_1787601767821_0.4280469830479745","host":"s3://npm-registry-packages-npm-production"}},"0.9.0":{"name":"@gr8ful/spf","version":"0.9.0","license":"MIT","_id":"@gr8ful/spf@0.9.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"1811d675ca910f3036762e00325d7b2c5a1f2718","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.9.0.tgz","fileCount":178,"integrity":"sha512-B4ez9bhStAG2gLc0HVygcMC9vW5i8gWqxacp44nu9drtUvVosw4TmRMWTPuCCK12EV05JIxj7rcuJx+HaulIqw==","signatures":[{"sig":"MEQCIFBmUeLVCNNWQwxFpquvO2aJkL9PrefXYhkvYB3EYl9SAiARTg5ktAv0T0mQ0qpZu7cKab9yFPGn88385GS3MeUrGQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.9.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1536261},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"01287661bde7d1db7f82edd219e7c304eca7230d","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.9.0_1787656215776_0.5592977054274988","host":"s3://npm-registry-packages-npm-production"}},"0.9.1":{"name":"@gr8ful/spf","version":"0.9.1","license":"MIT","_id":"@gr8ful/spf@0.9.1","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"40a6d7e9d57ef5b73303d449938f42e8aeaf7c16","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.9.1.tgz","fileCount":178,"integrity":"sha512-uKNLQ0geHLgb/ImTLu0TuFv9leHXB6AWC9fVDvweDwZqr2wEXQNhANimFrspHEZz/KIEDXL/f5i2HcygSIeUeg==","signatures":[{"sig":"MEYCIQDV6+R77ba5v0dH+UibHZE/Y0xUu+wkJA7BUByaeJQkSAIhANMi1hKgPaeYMERXGn7B1n8nQ84VTLiZnLEyE9OnUQGe","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.9.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1536734},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"a8aac2c3508aab8bbd368edcf34e302c24ee0ad6","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.9.1_1787656672062_0.6038385565593496","host":"s3://npm-registry-packages-npm-production"}},"0.9.2":{"name":"@gr8ful/spf","version":"0.9.2","license":"MIT","_id":"@gr8ful/spf@0.9.2","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"154dd3c9b146e405e2d728485b27e914822fb974","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.9.2.tgz","fileCount":178,"integrity":"sha512-9381pj9GywPNopAELeCgcE2yE+yodl8TX+G5BIqmKgi3OMOmP7QOr2UGjWNpIkwbXR/N/Qb3AZ3ec1DkdAPSPQ==","signatures":[{"sig":"MEUCIQCvvZljGScYH4dFdjja4e9AZfzvLQDDou9jFlli4TCQAAIgaC58kPdNHRhE19jRZzNwxouwTQ5r0le+o/OqLt+dgaY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.9.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1538038},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"6fffb0e1b2f09c9f5e943dc3c4c73c5863837e78","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.9.2_1787657301795_0.7026992785999626","host":"s3://npm-registry-packages-npm-production"}},"0.10.0":{"name":"@gr8ful/spf","version":"0.10.0","license":"MIT","_id":"@gr8ful/spf@0.10.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"bc22626a06fd490d31010c360ea14967fc2db06d","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.10.0.tgz","fileCount":192,"integrity":"sha512-i9ZR/w5td+07JFaxVOzsQV7FER4TNlGziDUiDC6erLxPfMiIusn2TtosBymsoG88ctp+B4+M0O1yXjhDGElUTA==","signatures":[{"sig":"MEUCIQC9XJBTCk72v0nXPcPYf+C9TDiO0lmQqRe8TijaFmaz9AIgLU9EjJyF0Hnm5fmtbbfwX4kzViZZbTETbfAEtG9p9jk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.10.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1831704},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"cf1506ddd63004080d7f4a84d11b99cca345d575","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.10.0_1787857529294_0.5930447253212028","host":"s3://npm-registry-packages-npm-production"}},"0.10.1":{"name":"@gr8ful/spf","version":"0.10.1","license":"MIT","_id":"@gr8ful/spf@0.10.1","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"6103be7cbb5368577cbdf5a733ac2b88086e51df","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.10.1.tgz","fileCount":192,"integrity":"sha512-z/gQqDaXFocW9RvIqqomgQKK4ggfZTPxqqR7BhWSWGIl3hQ0g/p7EOycwrUL7kRNlWeyiw1S10FaExd1Z9k1fg==","signatures":[{"sig":"MEQCIGMuFcPI14VKcVDbH5439+HZdZ9jKbHB3XN2wXQ9r1irAiBxziIBQLz1gqMfpGXF0+x4DFoFMZsafORpFC8JcXCV9g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.10.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1831958},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"02816a870e41eaeecab3f0ab085b9a2cb7c22328","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.10.1_1787858044220_0.6051145153964144","host":"s3://npm-registry-packages-npm-production"}},"0.10.2":{"name":"@gr8ful/spf","version":"0.10.2","license":"MIT","_id":"@gr8ful/spf@0.10.2","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"67555c7c70e038fdb7c4dd0fbcf648104888d0ac","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.10.2.tgz","fileCount":192,"integrity":"sha512-dxw9od93+DdC1w0slWl7yeYQE4dN7LXVYnXikidpWLKaWDSsmRTTtQT8EEW/mTzj9Ez/NMzVZP50pXHrVkmwtA==","signatures":[{"sig":"MEQCIH3SHQaiGnp8e+uIYGtR2dtswaGtuC0XzZVOwyCkD+0cAiAk5FVR3nLWuLpw5BLjtekCUrNMmMSkV1Q94tT10dbFCA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.10.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1832327},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"337defd7443aedf3a75aaa8fb58a5986f8473162","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.10.2_1787860660004_0.5676873507716673","host":"s3://npm-registry-packages-npm-production"}},"0.11.0":{"name":"@gr8ful/spf","version":"0.11.0","license":"MIT","_id":"@gr8ful/spf@0.11.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"c99ff320343f9e6a0f083707f949d240da6acf81","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.11.0.tgz","fileCount":195,"integrity":"sha512-t19mKPZML3v0e0AIgNNwDsBV4sOZOVH5c3a2rkMurwKGixvkfoyFRdWdwXZv6RLIKE78jQ+ZV6NjPxBEEr5vZQ==","signatures":[{"sig":"MEYCIQCWzeG70g1vSiAhCC+CqAPQVkNtPlE0Wsc2E6iwKV4byQIhAM6e8r91vh5YNh7K72Vn0MIup5UkxPQqx/uV5G/elOYq","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.11.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1867540},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"e7673a0fde74f9edb98cd4131df6c1baad19e6ba","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.11.0_1787920455292_0.33330929664348474","host":"s3://npm-registry-packages-npm-production"}},"0.11.1":{"name":"@gr8ful/spf","version":"0.11.1","license":"MIT","_id":"@gr8ful/spf@0.11.1","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"2b76b0ea642e9dd8978c2dc4f00a7c8b6e4c29e2","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.11.1.tgz","fileCount":195,"integrity":"sha512-p7udAUX5jNnicPetmFyL0UNNnz8u94kuJwxBgifHgw1jgj1oi8ZzBzrjbzv5jsLKWy96wYHdbKeGCfBIPSx5SA==","signatures":[{"sig":"MEYCIQChVY32xWWyUQo8OXfn0uneZ6SFf9CqMxvyAd/mldGyMgIhANb8lB18Lh+nU8PdoYe7IzWemH+JVMwa0q8ZUyE6svgl","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.11.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1869599},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"3c1aaa49b517c19ae0edd0b57fbe9c32c5a79a7b","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.11.1_1787925714893_0.7449492600057646","host":"s3://npm-registry-packages-npm-production"}},"0.11.2":{"name":"@gr8ful/spf","version":"0.11.2","license":"MIT","_id":"@gr8ful/spf@0.11.2","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"285415368efb8cd9106ed0b857b151c71cb08ab7","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.11.2.tgz","fileCount":195,"integrity":"sha512-SrrSzYDaz4N54lS8tw7edxxWoBDbTknSq9NmCJL3jUq5eVfPRzp7lHfPdrG5W/RUSb4gBVbz6X1MsZN5Etnypw==","signatures":[{"sig":"MEQCIAzPOX+8/1SnxBA/6haVWlLlAVmPXV5eziSxA65mYCVOAiB5qfEbzRHcmahj2b7TFur5Mjhwg7ws5XZmuq7G5UA1sA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.11.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1877598},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"3181423e7897b2718976bfd3e78de0ab8a2d3ec6","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.11.2_1787932890109_0.5871662720552699","host":"s3://npm-registry-packages-npm-production"}},"0.12.0":{"name":"@gr8ful/spf","version":"0.12.0","license":"MIT","_id":"@gr8ful/spf@0.12.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"41870077cada5b08c04a202d8596ae8df9af92b0","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.12.0.tgz","fileCount":195,"integrity":"sha512-0EindT9lYOyABXh4Kfr+ffEHbfdZeuDJT0xfKrKQ/DoEOSreZwzKuO3KR15iCcVkfXKwm7tlgd72mqklgKpu3A==","signatures":[{"sig":"MEQCIFXcCl3lt/8CQu+V5Wft4kVqtbmn4P1h0q+DQYjO1kW7AiATss1uU3e1CX7UKOp1ROJOlYBpMB1tUhGKEvPw6++lIw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.12.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1887144},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"c37d50935967134e4ae9ffb62bd07dd2bb500b14","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.12.0_1787934982795_0.5373963996846252","host":"s3://npm-registry-packages-npm-production"}},"0.13.0":{"name":"@gr8ful/spf","version":"0.13.0","license":"MIT","_id":"@gr8ful/spf@0.13.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"e913e97f60323bb94e86a16162eb00836691e65e","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.13.0.tgz","fileCount":195,"integrity":"sha512-EtLEB3Tv58FLbrWE0AOYM82y9mXlj6SNnDC7fTDrTgpoVdRtzQHy+xHARr2KiWPxMPZlAKESua8hYESrZhzx0A==","signatures":[{"sig":"MEYCIQCyYWH5WlG3PUpxs6pXkED3jc0sknzAmJukasqsa6e55gIhALquSFV5sKuFcL9roh8rfDcs3IXuvdK7rXZG724GvBPE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.13.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1962203},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"fe2d94c61b6853685e6c49461f307725d88a5303","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.13.0_1788100800507_0.9817058989302938","host":"s3://npm-registry-packages-npm-production"}},"0.14.0":{"name":"@gr8ful/spf","version":"0.14.0","license":"MIT","_id":"@gr8ful/spf@0.14.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"c2e5fbebb217e0efb09b3e8155921d63d03bd4d4","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.14.0.tgz","fileCount":195,"integrity":"sha512-oL7KDJ7b5WNJMHGxOA5ZOfKh7o6pGyb0zPX0A/8QWOQAOQ9PkhfRXwI7LrUjcYnrJhiZ/9fhNeQ0YMnOuGnc8g==","signatures":[{"sig":"MEYCIQCracYgU+8CYs2usn9NzE0cN2ZP4raRPo1SNUDG9yozpAIhANodTDlYY41G66PnNyKinba4itQi5UkNOFnXxBSxd1yB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.14.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1967103},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"dd1bd3947e56ed569d6a03570cc50c61da0aa588","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.14.0_1788183665886_0.489280929642566","host":"s3://npm-registry-packages-npm-production"}},"0.15.0":{"name":"@gr8ful/spf","version":"0.15.0","license":"MIT","_id":"@gr8ful/spf@0.15.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"458383bffdf0126315253af2531eaad17a418f90","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.15.0.tgz","fileCount":198,"integrity":"sha512-Or7jfOy/UuZBg1//rsmoXYD+6rvG1NgKU6X1fTtKxL0Im0BSjAWbiyiDQkoJWq9My1G7eS8TvJEjK1hIEr00/w==","signatures":[{"sig":"MEYCIQCT6qITV/5C8eJaxtD4FPEBxocQM0yxPo4Nezx+HzZF+AIhAO/0B1MUGtqQJHj6GI6hJr4rFEeB8bm0zt9Odnzt7yhN","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.15.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2057960},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"2b7e08f88035eddf251a1afa2c39c0d23ea73041","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.15.0_1788265889636_0.5537132025948679","host":"s3://npm-registry-packages-npm-production"}},"0.16.0":{"name":"@gr8ful/spf","version":"0.16.0","license":"MIT","_id":"@gr8ful/spf@0.16.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"4dc18f736cd7c0bc1186ec777c91ca6de923e0e4","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.16.0.tgz","fileCount":203,"integrity":"sha512-IKG0VX9jHhlci7kHdi19tBXGwpgmJEt1T+FAHymixpwQAjBKETrPTQ0RpMCJg/5ezW0hH2Lf9tDYcJcz3Jv2mQ==","signatures":[{"sig":"MEUCIFLiJZAcOegK2y1cWypQy13jyjgMcJgu3BdRqwuJ3u1IAiEAgXl5WwJ+kzVcPorLegygbC0gEL4j/LJjqyxhNvokf9Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.16.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2230378},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"c1b51ac980ce94029736c7c5a7703e7782954eb5","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.16.0_1788386197879_0.6050203448436617","host":"s3://npm-registry-packages-npm-production"}},"0.17.0":{"name":"@gr8ful/spf","version":"0.17.0","license":"MIT","_id":"@gr8ful/spf@0.17.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"d34cf854d1c260508ee2b34be4d3810b670eca19","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.17.0.tgz","fileCount":203,"integrity":"sha512-sQvQJZtSCFTQmEymDT44b+n6Dbq0uHyG+DC5D+Qx4zdrFORJj4OjznLLdZd4zyzkZ2uxaPyaRgeqC+j9XOAAJA==","signatures":[{"sig":"MEYCIQCYoTReZIjUFUbmYCNOAQyQPtB3G8Xc2PgvnootpqPhSwIhAPvn1upYmB/sPcGSe/W9V7onLKG8ULyMKQEAvFpavAFG","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.17.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2230378},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"ca4e79b159b3798ddac1edc6709bab10d1e39d66","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.17.0_1788527445367_0.6820069105129614","host":"s3://npm-registry-packages-npm-production"}},"0.18.0":{"name":"@gr8ful/spf","version":"0.18.0","license":"MIT","_id":"@gr8ful/spf@0.18.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"11881144b011223666391578f5003fed5f653036","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.18.0.tgz","fileCount":207,"integrity":"sha512-Fsvna5h2dJIITz7coIVDRd5Sn2+BrD1PfxDp8mk5ys+eDNz/N3f6Ln/bbp3j28kUDuOc5qh8TYNYRRxW1PLxUQ==","signatures":[{"sig":"MEUCIQDVhERsNMjJo1NokAW2MsIMBedcGXIWLBfTwVkQJUdbKQIgfiLv4BzdrsqcQN7lWJdcfWol7w3nMWZZbo3bHR9uEMI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.18.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2328604},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"c88844167b7ebfba695723dd6063f08a7adf2539","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.3","@hono/node-server":"^2.1.1","@opentelemetry/api":"1.9.1","@flue/opentelemetry":"2.0.4","@opentelemetry/core":"2.11.0","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1","@opentelemetry/resources":"2.11.0","@opentelemetry/sdk-metrics":"2.11.0","@opentelemetry/sdk-trace-base":"2.11.0","@opentelemetry/instrumentation":"0.222.0","@opentelemetry/context-async-hooks":"2.11.0","@opentelemetry/instrumentation-http":"0.222.0","@opentelemetry/semantic-conventions":"1.43.0","@opentelemetry/instrumentation-undici":"0.32.0","@opentelemetry/exporter-trace-otlp-http":"0.222.0","@opentelemetry/exporter-metrics-otlp-http":"0.222.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.18.0_1789190040347_0.748022744105407","host":"s3://npm-registry-packages-npm-production"}},"0.19.0":{"name":"@gr8ful/spf","version":"0.19.0","license":"MIT","_id":"@gr8ful/spf@0.19.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"7adc3d525002ce8897667886c4e34c9fe94b8006","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.19.0.tgz","fileCount":209,"integrity":"sha512-O1Sqd4Df2i3SYUoIr5Jj5CMhGG+7JIKIVJi9v8Imx7t0c7bw+mQEVE7Gc9O7bVZsW7/LuoeX4dNY1HtdiJMqKw==","signatures":[{"sig":"MEQCIBrfa3hRZH/v1Frd/B+W0898tjXwHYq9iJ+nTlTK48imAiAG5wBI6mF60fCW0wGWmD08/YXIc9fJaIv1QsWJmYrJow==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.19.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2364956},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"9d7952e6058ef440519963946248c706f1952e1d","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.5","@hono/node-server":"^2.1.1","@opentelemetry/api":"1.9.1","@flue/opentelemetry":"2.0.5","@opentelemetry/core":"2.11.0","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1","@opentelemetry/resources":"2.11.0","@opentelemetry/sdk-metrics":"2.11.0","@opentelemetry/sdk-trace-base":"2.11.0","@opentelemetry/instrumentation":"0.222.0","@opentelemetry/context-async-hooks":"2.11.0","@opentelemetry/instrumentation-http":"0.222.0","@opentelemetry/semantic-conventions":"1.43.0","@opentelemetry/instrumentation-undici":"0.32.0","@opentelemetry/exporter-trace-otlp-http":"0.222.0","@opentelemetry/exporter-metrics-otlp-http":"0.222.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.19.0_1789190321896_0.5928474673236994","host":"s3://npm-registry-packages-npm-production"}},"0.19.1":{"name":"@gr8ful/spf","version":"0.19.1","license":"MIT","_id":"@gr8ful/spf@0.19.1","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"9339f581cfa8181c5707338dfc34348e006c3d00","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.19.1.tgz","fileCount":209,"integrity":"sha512-dEqbaaqrtuNqj19fURvWny21TfRMo6/07GUkdJr1SW5AJ5FXpeaJsuuV4zgxtjlU3vtunNV2PK8P1hzZZwmkXw==","signatures":[{"sig":"MEUCIF5e7kmoaX7k+S2w8xcldqryijXf2OZBbBsbd6ikP0X3AiEA1Mcqdrbxn1SAGrrj953/qTSvgBljDD40gFqUo3cL9ro=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIFJuAYVkXERo+hg51OOzgK0UOelx8SYcWQ7dXM9eKDG6AiEAxhVbPaknM+REVcNLwjINnYfpN3dDRKWoFxYIoWapv80=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.19.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2490917},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"34ff13da2d5e91c9c62e852add79debdb3f02a94","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.5","@hono/node-server":"^2.1.1","@opentelemetry/api":"1.9.1","@flue/opentelemetry":"2.0.5","@opentelemetry/core":"2.11.0","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1","@opentelemetry/resources":"2.11.0","@opentelemetry/sdk-metrics":"2.11.0","@opentelemetry/sdk-trace-base":"2.11.0","@opentelemetry/instrumentation":"0.222.0","@opentelemetry/context-async-hooks":"2.11.0","@opentelemetry/instrumentation-http":"0.222.0","@opentelemetry/semantic-conventions":"1.43.0","@opentelemetry/instrumentation-undici":"0.32.0","@opentelemetry/exporter-trace-otlp-http":"0.222.0","@opentelemetry/exporter-metrics-otlp-http":"0.222.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.19.1_1789909938942_0.36943861298369685","host":"s3://npm-registry-packages-npm-production"}},"0.20.0":{"name":"@gr8ful/spf","version":"0.20.0","license":"MIT","_id":"@gr8ful/spf@0.20.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"4560bc4ec7c6554daee52b768c5791ad91b9989d","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.20.0.tgz","fileCount":209,"integrity":"sha512-+8+e8rZ/fimJoJjjjqSoBWCRRrxGbJaTQ8WMPxYMOmpIgspf5OAvdLmsO2DYX5+VYtFSIoVtkJPCLBaTqRmFYQ==","signatures":[{"sig":"MEUCIQDju0EPlcQKYQaGtG5/eP/2h307kqH9JrLgn03WUFLAowIgO4MEKdZWFpEE7AZ5L8Ci8WXSmrC31h4bD4falacT3UQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIBBxKLy7Yxbw/y4WFOaPIqjwzQ37nE/83C4Ma92c4QU4AiEAtiWBYkD/QBYQge45WDXVocES490V8js8/ysQ+hDOY7Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.20.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2490917},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"f05bab1b2fb2af13b45fb90b6e48e910e8735217","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.5","@hono/node-server":"^2.1.1","@opentelemetry/api":"1.9.1","@flue/opentelemetry":"2.0.5","@opentelemetry/core":"2.11.0","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1","@opentelemetry/resources":"2.11.0","@opentelemetry/sdk-metrics":"2.11.0","@opentelemetry/sdk-trace-base":"2.11.0","@opentelemetry/instrumentation":"0.222.0","@opentelemetry/context-async-hooks":"2.11.0","@opentelemetry/instrumentation-http":"0.222.0","@opentelemetry/semantic-conventions":"1.43.0","@opentelemetry/instrumentation-undici":"0.32.0","@opentelemetry/exporter-trace-otlp-http":"0.222.0","@opentelemetry/exporter-metrics-otlp-http":"0.222.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.20.0_1790078393506_0.16236397173199002","host":"s3://npm-registry-packages-npm-production"}},"0.21.0":{"name":"@gr8ful/spf","version":"0.21.0","license":"MIT","_id":"@gr8ful/spf@0.21.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"bbe22ddb013c0a0432ce70aaa5112570312adf9b","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.21.0.tgz","fileCount":211,"integrity":"sha512-jHFPgRzjJb4qPB7+e9SQ4Nc2a5Pgymr962cVLaiafoNECn2Qoyz8mV3+NRU7Y4mXJGnr1eWrOMqamKgJ65xiAg==","signatures":[{"sig":"MEYCIQC+oxUgFXEVpSoMF+hotbtowqZK3/RkjzJRq2ze9R7EIgIhAISjOBIC97A9pQIqP7CAsmJNF5TIcguSyzRzxsMEQSq+","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQClsXffUTERfijRcEP+STZbCSVQscR4CLQYVU1f0rREawIhANfzDTYoupOVUuyJ++blgvBLsQnrwMqsoIdcl2LfTB7D","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.21.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2504920},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"eaf0928354b327688e6a912c4f3b4f130ddebf87","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.0.2","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.5","@hono/node-server":"^2.1.1","@opentelemetry/api":"1.9.1","@flue/opentelemetry":"2.0.5","@opentelemetry/core":"2.11.0","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1","@opentelemetry/resources":"2.11.0","@opentelemetry/sdk-metrics":"2.11.0","@opentelemetry/sdk-trace-base":"2.11.0","@opentelemetry/instrumentation":"0.222.0","@opentelemetry/context-async-hooks":"2.11.0","@opentelemetry/instrumentation-http":"0.222.0","@opentelemetry/semantic-conventions":"1.43.0","@opentelemetry/instrumentation-undici":"0.32.0","@opentelemetry/exporter-trace-otlp-http":"0.222.0","@opentelemetry/exporter-metrics-otlp-http":"0.222.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.21.0_1790078556755_0.3933798105685262","host":"s3://npm-registry-packages-npm-production"}},"0.22.0":{"name":"@gr8ful/spf","version":"0.22.0","license":"MIT","_id":"@gr8ful/spf@0.22.0","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"bin":{"spf":"dist/cli/bin.js"},"dist":{"shasum":"07ca63de8aa8237d185c0b2f2be441015ed620f4","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.22.0.tgz","fileCount":211,"integrity":"sha512-DXGEjq1OYch4sDCYaczQcjc2Vg5fSoT/rkiHGerFLZR+u1OwQ30npyaNfJZPnO68o3aw7FZXOuCocM7Q8W1vUA==","signatures":[{"sig":"MEYCIQDsFgh0hdnzqDfFHEKDqEdjaFCPrY1QzJWbeLi82ObMVAIhAPyw8en5gC9P+0TwRs9MLb25eaWZZivrbNNh3ODRAn5D","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDpb/2WBgpfDd82YjdS0q9xEcrwz6LV3qYvl4rNYyWbgwIgQaQohNN1BnTxUBguvzzaLDYOfriBnxJ9ETZLaF+3V20=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@gr8ful%2fspf@0.22.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":2542065},"type":"module","engines":{"node":">=22.19.0"},"gitHead":"5e5112fb8ed6ef511e0fbd76f18b4d18101cd5bb","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.1.0","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"_nodeVersion":"22.23.2","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.5","@hono/node-server":"^2.1.1","@opentelemetry/api":"1.9.1","@flue/opentelemetry":"2.0.5","@opentelemetry/core":"2.11.0","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1","@opentelemetry/resources":"2.11.0","@opentelemetry/sdk-metrics":"2.11.0","@opentelemetry/sdk-trace-base":"2.11.0","@opentelemetry/instrumentation":"0.222.0","@opentelemetry/context-async-hooks":"2.11.0","@opentelemetry/instrumentation-http":"0.222.0","@opentelemetry/semantic-conventions":"1.43.0","@opentelemetry/instrumentation-undici":"0.32.0","@opentelemetry/exporter-trace-otlp-http":"0.222.0","@opentelemetry/exporter-metrics-otlp-http":"0.222.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"tmp":"tmp/spf_0.22.0_1790257733449_0.24540932742472998","host":"s3://npm-registry-packages-npm-production"}},"0.23.0":{"_id":"@gr8ful/spf@0.23.0","bin":{"spf":"dist/cli/bin.js"},"bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"dist":{"shasum":"f1f68a2910cfebf7dd9481cfbc6b6af924b121ea","tarball":"https://registry.npmjs.org/@gr8ful/spf/-/spf-0.23.0.tgz","fileCount":228,"integrity":"sha512-B2wYHRH2JXjx00Vkkrlc6201PA4tu7k/9/mQWfC7mO7gsbjjpIW4c8hIjIuKcQq3thrAQK9zMYs9w5fRMK1yLA==","signatures":[{"sig":"MEUCIDwjZ2CWQn031no6URp1JB4vZrAbJ7JubuBCEZa6FajlAiEAugPZwh/JGmchu/Exr9CmSLZQxq49nKC5v2q15ACmdPQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGhlG609d5k/CX8V7ltQGfrhv3Q1S5S7OCWh5mxqgwQEAiA++2FhBti91WLz0IksrrDAewwQ7ny9NuQYchJIgd5amA=="}],"unpackedSize":2934695},"name":"@gr8ful/spf","type":"module","engines":{"node":">=22.19.0"},"gitHead":"26de602966348a8f31b85536419f26d4ed2cb349","license":"MIT","scripts":{"test":"node --test \"dist/**/*.test.js\"","build":"npm run clean && npm run build:cli && npm run build:app","clean":"rm -rf dist","prepack":"node scripts/check-pack-ready.js","prepare":"lefthook install","pretest":"npm run build:cli","build:app":"npm --prefix app ci && npm --prefix app run build","build:cli":"tsc -p tsconfig.build.json && chmod +x dist/cli/bin.js","tag:major":"node scripts/tag-release.js major","tag:minor":"node scripts/tag-release.js minor","tag:patch":"node scripts/tag-release.js patch","typecheck":"tsc -p tsconfig.json --noEmit","size-check":"node scripts/check-tarball-size.js"},"version":"0.23.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"0e6d7784-8e35-4fd8-8262-e63cc57f53b3"}},"homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","overrides":{"@earendil-works/pi-ai":"0.83.0"},"repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"_npmVersion":"12.2.0","description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","directories":{},"maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"_nodeVersion":"22.23.3","dependencies":{"ink":"^7.1.1","hono":"^4.13.3","yaml":"^2.5.1","react":"^19.2.8","valibot":"^1.4.2","@inkjs/ui":"^2.0.0","@flue/runtime":"2.0.5","@hono/node-server":"^2.1.1","@opentelemetry/api":"1.9.1","@flue/opentelemetry":"2.0.5","@opentelemetry/core":"2.11.0","@earendil-works/pi-ai":"0.83.0","@valibot/to-json-schema":"^1.7.1","@opentelemetry/resources":"2.11.0","@opentelemetry/sdk-metrics":"2.11.0","@opentelemetry/sdk-trace-base":"2.11.0","@opentelemetry/instrumentation":"0.222.0","@opentelemetry/context-async-hooks":"2.11.0","@opentelemetry/instrumentation-http":"0.222.0","@opentelemetry/semantic-conventions":"1.43.0","@opentelemetry/instrumentation-undici":"0.32.0","@opentelemetry/exporter-trace-otlp-http":"0.222.0","@opentelemetry/exporter-metrics-otlp-http":"0.222.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"lefthook":"^2.1.10","typescript":"^7.0.2","@types/node":"^22.10.0","@types/react":"^19.2.18","ink-testing-library":"^4.0.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/spf_0.23.0_1790957361724_0.20685432221946365"}}},"time":{"created":"2026-08-20T17:24:31.703Z","modified":"2026-10-02T16:09:22.031Z","0.1.0":"2026-08-20T17:24:31.975Z","0.1.4":"2026-08-20T17:40:17.458Z","0.1.5":"2026-08-20T17:44:19.417Z","0.1.6":"2026-08-20T19:15:20.952Z","0.1.7":"2026-08-20T20:57:10.734Z","0.2.1":"2026-08-21T13:12:59.099Z","0.3.0":"2026-08-21T15:28:57.202Z","0.4.0":"2026-08-22T13:43:17.497Z","0.5.0":"2026-08-22T20:42:33.469Z","0.5.1":"2026-08-22T21:08:22.732Z","0.6.0":"2026-08-23T15:39:46.408Z","0.7.0":"2026-08-24T13:56:16.602Z","0.8.0":"2026-08-24T17:01:27.776Z","0.8.1":"2026-08-24T18:15:05.921Z","0.8.2":"2026-08-24T19:18:20.124Z","0.8.3":"2026-08-24T20:02:48.014Z","0.9.0":"2026-08-25T11:10:15.932Z","0.9.1":"2026-08-25T11:17:52.288Z","0.9.2":"2026-08-25T11:28:21.971Z","0.10.0":"2026-08-27T19:05:29.535Z","0.10.1":"2026-08-27T19:14:04.408Z","0.10.2":"2026-08-27T19:57:40.186Z","0.11.0":"2026-08-28T12:34:15.455Z","0.11.1":"2026-08-28T14:01:55.112Z","0.11.2":"2026-08-28T16:01:30.327Z","0.12.0":"2026-08-28T16:36:23.035Z","0.13.0":"2026-08-30T14:40:00.713Z","0.14.0":"2026-08-31T13:41:06.062Z","0.15.0":"2026-09-01T12:31:29.793Z","0.16.0":"2026-09-02T21:56:38.062Z","0.17.0":"2026-09-04T13:10:45.548Z","0.18.0":"2026-09-12T05:14:00.532Z","0.19.0":"2026-09-12T05:18:42.076Z","0.19.1":"2026-09-20T13:12:19.063Z","0.20.0":"2026-09-22T11:59:53.617Z","0.21.0":"2026-09-22T12:02:36.881Z","0.22.0":"2026-09-24T13:48:53.554Z","0.23.0":"2026-10-02T16:09:21.833Z"},"bugs":{"url":"https://github.com/seesharpguy/super-portable-software-factory/issues"},"license":"MIT","homepage":"https://github.com/seesharpguy/super-portable-software-factory#readme","repository":{"url":"git+https://github.com/seesharpguy/super-portable-software-factory.git","type":"git"},"description":"Super Portable Factory — a global CLI for repeatable agents-plus-code workflows (ADWs)","maintainers":[{"name":"ryang8","email":"ryan@grateful8.us"}],"readme":"# Super Portable Factory\n\n> **Repeatable agents-plus-code workflows, as a global CLI you run against any repo.**\n> Deterministic TypeScript owns the graph. Coding agents are bounded nodes inside it.\n\nA software factory does one thing: it gives you more leverage on your prompt. How much leverage depends entirely on what you invest in it. At the low end you chain two agents together and hope. At the high end you build a system of agents plus code that runs without you, and does the job about as well as you would.\n\nEveryone can get an agent to write code once. Almost nobody gets the same result twice. This fixes that by moving the control plane out of the prompt and into TypeScript. A chain script owns sequencing, retries, and acceptance. Agents work inside named phases. Typed JSON envelopes carry context across the seams. Every event streams into SQLite while it is still happening. **Agent proposes, code disposes.**\n\n> **Beta.** SPF is under active development — config schema, chain/CLI surface, and trace/event shapes may change between releases without a deprecation period. Pin a version if you depend on any of these staying stable.\n\n---\n\n## Install\n\n```bash\nnpm i -g @gr8ful/spf\n```\n\nNo Bun, no separate coding-agent binary to install first, no template stamped into your repo. `spf` ships with a packaged default agent roster and default prompts — it runs against any repo with zero setup, and only writes files into that repo if you explicitly ask it to (`spf init`, which also installs the Claude Code skill unless you pass `--no-skills`; `spf install-skill` does just the skill by hand).\n\n```bash\ncd your-repo\nspf doctor                          # confirm everything resolves — paths, roster, provider keys\nspf scout \"describe this repo\"      # a real, read-only run, no setup required\n```\n\n`spf doctor` is the answer to \"why did nothing happen\": it resolves and prints every path, validates the whole roster and every quality suite, and checks the things that fail silently otherwise — a missing provider key, a quality check whose binary isn't on `PATH`, a stale `protected_files` pattern.\n\n### Customizing a repo\n\n```bash\nspf init                       # on a TTY: an interview — agent, model, quality checks, spf watch, secrets\nspf init --yes                 # skip the interview — seed the commented, all-defaults starter config instead\nspf init --template ts-cc      # or start from a packaged, ready-to-run template instead\nspf list                       # every chain this install knows, its phases, what it needs\n```\n\nOn a real terminal, `spf init` asks a short interview — which coding agent (`claude_code`, `flue`, or `opencode`) and model (optionally customized per agent instead of one model for the whole roster), which quality checks to gate on, whether to turn on `spf watch` and against which tracker/code host, and whether to push notifications to Slack/Teams/a webhook — and writes `.spf/spf.config.yaml` with only what you answered differently from the packaged defaults, plus whatever secrets those answers imply appended to `.env` (already gitignored, and already auto-loaded by every command) and their key names mirrored into a committable `.env.example`. Re-running it later shows any existing `.env` value masked and keeps it on an empty answer, so rotating one secret doesn't mean re-answering everything. Piped input, `--yes`, or `--template <name>` all skip the interview and fall back to the original non-interactive behavior — a scripted `spf init` never blocks on stdin.\n\nWithout an interview, `spf init` writes the same small starter `.spf/spf.config.yaml`, commented, that merges on top of the packaged built-ins field by field. `--template <name>` writes a real, filled-in config instead of the commented-out starter — every packaged template's name prints after `spf init` runs, and the same files live in [`assets/templates/`](assets/templates/) to browse directly. Nothing here needs to exist for `spf` to run; it's how you make one repo's roster diverge from the defaults.\n\nEvery `spf init` run — interview or not — also installs the repo-local Claude Code skill (`.claude/skills/spf`), the same work `spf install-skill` does by hand: pass `--no-skills` to skip it. It's idempotent (a no-op once the skill is already current, and writes a `.new` sibling instead of overwriting a file you've locally edited), so re-running `spf init` never clobbers anything there. `spf install-skill --user` (installing to `~/.claude/skills/spf` instead) is still its own separate invocation.\n\n### Local development\n\nWorking from a clone instead of the published package:\n\n```bash\ngit clone git@github.com:seesharpguy/super-portable-software-factory.git\ncd super-portable-software-factory\nnpm install\nnpm run build     # builds both the CLI (dist/) and the trace visualizer SPA (web/)\nnpm link          # makes `spf` resolve globally to THIS checkout\n```\n\n`npm link` beats a real `npm i -g` here: it symlinks the global `spf` bin into this checkout, so every later `npm run build` takes effect immediately, no re-linking. Run it from any repo you want to test against.\n\n```bash\nnpm run typecheck   # tsc --noEmit\nnpm test            # node --test against dist/**/*.test.js (runs build:cli first)\nnpm run size-check  # tarball size gate — what `npm pack` would actually publish\n```\n\nFor a one-off check without touching global npm state at all, run the built CLI directly: `node dist/cli/bin.js doctor --cwd /path/to/repo`. When you're done with the linked version, `npm unlink -g @gr8ful/spf` removes it.\n\n---\n\n## Why this exists\n\nHand a capable model your whole SDLC and you get a machine with no seams. There is no phase boundary, so you cannot say which step failed. There is no acceptance criterion you can name, so \"done\" means \"the agent stopped talking.\" A retry is a cold start that throws away everything the agent just learned. The only trace is a transcript you have to read like a novel. Run it twice, get two different systems.\n\nThe fix is not a better prompt. The fix is deciding, deliberately, that **code owns sequencing, retries, and acceptance, and the agent owns only the work inside one bounded phase**. Everything else falls out of that one line. Phases become the unit of the trace. Envelopes become the only way context crosses a seam. Gates become the definition of done. A correction becomes cheaper than a restart, because the session is still alive.\n\n### Agents are great. You do not always need one.\n\nThis is the part most engineers are going to skip, and pay for later.\n\nCode costs nothing. It runs at the speed of light. You can change it in a second. And you actually own it, which is not true of any model you are renting by the token.\n\nSo when the invocation is already known, write it down. `npm test` is not a judgement call. Neither is `tsc --noEmit`. An agent rediscovering your test runner burns a context window to learn what a subprocess already knows, and it charges you for the privilege every single run. Worse, it puts a passing test suite into a context window, which buys you nothing at all.\n\nAgents are for the parts that need reading and deciding. Everything else is a `kind: \"code\"` phase — SPF's own `quality:` config section names the commands, and a chain runs them as code, not as an agent's rediscovery project. When code fails, the failure comes back to the builder as an envelope, through the same door an agent's report would have used. The repair loop is identical. You just stopped paying an agent to do arithmetic.\n\nThe bill for skipping this is not only tokens. It is cost, speed, and consistency, and you pay it on run one hundred and run one thousand, not on run one.\n\n> *Same models. Same prompts. The difference is who owns the loop.*\n\n---\n\n## The agent roster\n\n`spf.config.yaml` answers one question per entry: who is this agent. One agent, one prompt, one purpose. `spf init` seeds `.spf/spf.config.yaml`, merged on top of the packaged defaults — an entry only states what differs.\n\n```yaml\ndefaults:\n  coding_agent: flue                 # the engine agents run on\n  model: google/gemini-3.6-flash     # provider/model-id — a bare id can match several providers\n  thinking: medium                   # off | minimal | low | medium | high | xhigh | max\n  protected_files: [.spf/, spf.config.yaml]   # no agent may edit the machinery that grades it\n  data_dir: .spf/data\n\nagents:\n  - name: planner\n    model: fireworks/accounts/fireworks/models/kimi-k3\n    thinking: high\n    color: \"#a78bfa\"                 # this agent's lane color in the trace UI\n    purpose: Turn a request into a plan the builder can implement without asking questions.\n    prompt_engineering:\n      system: planner/system.md\n      user: planner/user.md\n    writes: [specs/]                 # the plan is all it may leave in the repo\n```\n\nSix starter agents ship in the box: `planner`, `builder`, `scout` (read-only recon), `refiner` (decomposes a product spec for `spf watch`'s refine lane — see \"`spf watch`\" below), `reviewer`, and `documenter`. There is no tester, because running a suite is a known command and therefore code, not an agent's job.\n\nEvery agent gets its own model, thinking level, prompts, and tools. Give the planner a frontier model and the builder a cheap fast one. Give the reviewer no ability to write code at all.\n\n**`tools` is a capability list. `writes` is the boundary.** They are not the same thing: `bash` runs anything, including `git checkout`, and `write` reaches any path. So \"this agent changes nothing\" is enforced in code, after every call, by comparing the repo before and after. Unauthorized changes are rolled back and the phase fails. A read-only agent is read-only with respect to your repo, never unable to write its own report.\n\nConfig defines who an agent **is**. The chain call site defines how it is **used**. That split is what lets one agent serve many different calls. **Chains name agents, never models.**\n\n### A second backend: Claude Code\n\nSet `coding_agent: claude_code` on any agent (or in `defaults`) to run it on your own installed [Claude Code](https://claude.com/product/claude-code) CLI instead of Flue — `spf doctor` checks whatever `SPF_CLAUDE_CMD`'s first token resolves to on `PATH` (`claude` itself, by default). Model names follow Claude Code's own vocabulary (a bare alias like `sonnet`, not `provider/model-id`); everything else — `tools`, `writes`, `thinking` — stays the same shape. Pointing a `claude_code` agent at a local or cloud [Ollama](https://ollama.com) server needs no config at all — just `ANTHROPIC_BASE_URL`/`ANTHROPIC_AUTH_TOKEN` set before you run `spf`, since Claude Code's CLI reads those itself.\n\n#### Proxy or wrapper launchers\n\nTo route the `claude` command through a wrapper, proxy server, or launcher (e.g., [Ollama](https://ollama.com)), set `SPF_CLAUDE_CMD` — as a declarative `env:` entry in `spf.config.yaml`, since it's a launcher choice, not a secret (see [Declarative env vars](#declarative-env-vars) below), or as a plain shell export for a one-off override. Space-separated command chains are supported:\n\n```yaml\nenv:\n  SPF_CLAUDE_CMD: \"ollama launch claude --model {model}\"\n```\n\n```bash\nspf build \"your prompt\"\n```\n\n`ollama launch <cmd>` uses cobra flag parsing, which treats anything typed after it as its own flags unless a literal `--` says otherwise — without one, `claude`'s own flags (`-p`, `--json-schema`, ...) fail with `unknown shorthand flag: 'p' in -p` before `claude` is ever reached. `agent_cc.ts` detects exactly this `ollama launch ...` shape and inserts that `--` automatically, so you never add the separator by hand for this specific launcher.\n\nThat `--` alone is not enough to reach `claude`, though: `ollama launch` also needs its OWN `--model <tag>` flag, typed BEFORE the auto-inserted `--`, whenever it runs headless — which it always does under SPF, since SPF spawns with piped stdio. Without it, `ollama launch` falls back to an interactive model picker that can never run, and fails one step later than the `--` problem, with `model selection requires an interactive terminal; use --model to run in headless mode`. A `--model` typed after the `--` doesn't help — at that point it belongs to `claude`, not to `ollama launch`. So `SPF_CLAUDE_CMD` must include `ollama launch`'s `--model` yourself; `spf doctor` hard-fails if it's missing.\n\n**Per-agent model choice:** a literal `{model}` token in `SPF_CLAUDE_CMD` is substituted with each call's own agent-config `model:` field before spawning. Since `ollama launch`'s `--model` (its OWN flag) is what actually pins the model serving the whole launched process — not `claude`'s own `--model`, appended after the `--` — a FIXED tag in `SPF_CLAUDE_CMD` means every `claude_code` agent runs on that one model regardless of what each agent's `model:` says. Using `{model}` instead makes it genuinely per-agent:\n\n```yaml\nenv:\n  SPF_CLAUDE_CMD: \"ollama launch claude --model {model}\"\nagents:\n  - name: planner\n    coding_agent: claude_code\n    model: kimi-k2.7-code:cloud\n  - name: builder\n    coding_agent: claude_code\n    model: qwen3-coder:cloud\n```\n\n```bash\n# Or use a custom wrapper script\nexport SPF_CLAUDE_CMD=/path/to/my-wrapper\nspf build \"your prompt\"\n```\n\nThe command/launcher must support the full Claude Code CLI interface: `-p` for prompt, `--json-schema`, `--model`, `--session-id`/`--resume`, `--output-format stream-json`, and all other flags `agent_cc` uses. When unset, `SPF_CLAUDE_CMD` defaults to `claude` (resolved from `PATH` normally). A cmdSpec that already contains its own literal `--` is left completely alone — `agent_cc.ts` never inserts a second one.\n\n#### Declarative env vars\n\n`spf.config.yaml` supports an `env:` block for settings like `SPF_CLAUDE_CMD` that are configuration, not secrets — so they can be committed as plain, reviewable text instead of hidden in an out-of-band shell export:\n\n```yaml\nenv:\n  SPF_CLAUDE_CMD: \"ollama launch claude --model {model}\"\n  SOME_TOKEN: \"${SOME_SECRET_FROM_DOTENV}\"\n```\n\nApplied to `process.env` before any command runs. A plain value commits as literal text; `${VAR}` interpolates from whatever's already in `process.env` at that point (the real shell, or `.env`, both of which load first) — so a real secret can live in `.env` (gitignored) and be referenced here without ever being written into this file. An already-set `process.env` value always wins over `env:`'s — `spf.config.yaml` supplies the default, a real export still overrides it per machine/session. A `${VAR}` reference to something that's genuinely unset fails loudly at startup, naming the missing variable, rather than silently interpolating to an empty string.\n\n### A third backend: opencode\n\nSet `coding_agent: opencode` on any agent (or in `defaults`) to run it on your own installed [OpenCode](https://opencode.ai) CLI instead of Flue or Claude Code — install it with `npm install -g opencode-ai` (the package is `opencode-ai`; the binary it puts on `PATH` is `opencode`). `spf doctor` checks that `opencode` resolves on `PATH` and that `~/.local/share/opencode/auth.json` exists, the same informational, not-enforced posture as its `claude_code` check for `ANTHROPIC_API_KEY`. Model names follow the same `provider/model-id` shape Flue uses (e.g. `anthropic/claude-sonnet-4-20250514`, `ollama/qwen3-coder:30b`) — not Claude Code's own bare-alias vocabulary (`sonnet`, `opus`, ...); everything else — `tools`, `writes`, `thinking` — stays the same shape.\n\nAuthentication is handled entirely outside spf: run `opencode auth login` once (interactive), or `opencode auth list` to check non-interactively what's already configured. spf never drives this itself.\n\nLike `claude_code`, routing the `opencode` command through a wrapper or launcher uses the equivalent `SPF_CLAUDE_CMD`-style env var for this backend, with the same `{model}` token-substitution mechanic — see [Declarative env vars](#declarative-env-vars) above and check `opencode --help` for the flags a wrapper needs to forward.\n\n### flue + local Ollama\n\nPoint the default `flue` backend at a local Ollama server the same way you'd pick any other Flue provider — the model string's own prefix, `ollama/<tag>` (whatever `ollama list` shows on your machine) instead of `openai/...`/`anthropic/...`:\n\n```yaml\ndefaults:\n  coding_agent: flue\n  model: ollama/qwen3.8:27b-mlx\n```\n\n```bash\nexport OLLAMA_BASE_URL=http://localhost:11434/v1   # default if unset\nspf build \"your prompt\"\n```\n\nThat's the whole config change. `ollama` is a keyless provider — `spf doctor` and the `spf init` interview both know this: no API key is ever asked for or checked, and interview.ts asks for `OLLAMA_BASE_URL` instead when you pick `ollama` as your provider. A ready-to-run starting point ships at [`assets/templates/ts-flue-ollama.spf.config.yaml`](assets/templates/ts-flue-ollama.spf.config.yaml) (`spf init --template ts-flue-ollama`).\n\nTwo things worth knowing before pointing a full roster at local models: tool-calling — the injected `sf_report` contract every agent's structured output rides on — worked reliably in testing down to a 3B-parameter model, which isn't a \"only frontier models get tools\" situation. And context-window occupancy reporting is disabled for `ollama/*` models specifically, which turns off threshold-based compaction rather than reporting a number Ollama's OpenAI-compatible API doesn't actually provide per model.\n\n### flue + Cloudflare Workers AI\n\nPoint the default `flue` backend at a [Cloudflare Workers AI](https://developers.cloudflare.com/ai/) model the same way you'd pick any other Flue provider — the model string's own prefix, `cloudflare/<model-id>`, where `<model-id>` is the full `@cf/...` catalog id (the slash inside the id is fine; spf splits on the first slash only):\n\n```yaml\ndefaults:\n  coding_agent: flue\n  model: cloudflare/@cf/zai-org/glm-5.3-flash\n```\n\n```bash\nexport CLOUDFLARE_ACCOUNT_ID=your-account-id        # derives https://api.cloudflare.com/client/v4/accounts/$ID/ai/v1\nexport CLOUDFLARE_API_TOKEN=your-token               # Workers AI > Read permission\nspf build \"your prompt\"\n```\n\nThat's the whole config change. `cloudflare` is a keyed provider (a real Bearer token, unlike keyless `ollama` — Cloudflare's API 401s on an empty Authorization header). `spf init` asks for the token plus either `CLOUDFLARE_ACCOUNT_ID` (the standard endpoint) or an explicit `CLOUDFLARE_AI_BASE_URL` (a custom domain or an AI Gateway endpoint), and overrides the three packaged-roster agents that a Workers AI account can't serve. `spf doctor` probes the resolved endpoint (informational, never a hard failure). A ready-to-run starting point ships at [`assets/templates/ts-flue-cloudflare.spf.config.yaml`](assets/templates/ts-flue-cloudflare.spf.config.yaml) (`spf init --template ts-flue-cloudflare`).\n\nTwo things worth knowing, both inherited from the `ollama/*` convention for self-served OpenAI-compatible endpoints: context-window occupancy reporting is disabled for `cloudflare/*` models (`contextWindow: 0`, turning off threshold-based compaction rather than fabricating a number Workers AI's API doesn't provide per model), and `reasoning: false` — the model's own `reasoning_effort` parameter is not wired through, so an agent's `thinking:` level is moot for `cloudflare/*` models today.\n\n### claude_code + Cloudflare AI Gateway\n\nTo route the `claude_code` backend through a [Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) (so the gateway holds the Anthropic credentials via Unified Billing or BYOK, and you authenticate to the gateway), pick **Cloudflare AI Gateway** at the `Authentication` step in `spf init`. spf writes the three env vars the gateway needs:\n\n```bash\nANTHROPIC_BASE_URL=https://gateway.ai.cloudflare.com/v1/<ACCOUNT_ID>/<GATEWAY_ID>/anthropic\nANTHROPIC_API_KEY=<CF_AIG_TOKEN>                                   # any value — the gateway ignores it; Claude Code requires it set\nANTHROPIC_CUSTOM_HEADERS=cf-aig-authorization: Bearer <CF_AIG_TOKEN>\n```\n\n`spf doctor` probes the gateway's `/v1/messages` with the `cf-aig-authorization` header (informational, never a hard failure). This is the `claude_code` backend — it speaks the Anthropic API, so it's independent of the Workers AI `flue` provider above; you can run some agents on Workers AI (`flue`) and others through the gateway (`claude_code`) in the same roster.\n\n---\n\n## Isolation: post-hoc, not a sandbox\n\nAgent isolation in SPF is enforced **after the fact**, not upfront. This matters because the `tools:` capability list is not a sandbox — a `bash` tool can run `git checkout` to discard changes, and a `write` tool can reach any path, regardless of the allowlist you write. So permission is verified the way every other claim in this system is: the working tree is fingerprinted before an agent runs, then compared after. If the agent touched anything outside its `writes:` allowlist (or a `protected_files:` path it wasn't given access to), the phase fails and anything the agent *introduced* outside its allowlist is rolled back. What it cannot undo, it names: a file that was already dirty before the agent ran is left alone rather than discarded, and uncommitted work the agent reverted cannot be restored. And because the check is post-hoc and tree-scoped, nothing outside the working tree is in scope at all — a push, a network call, a write above `repo_root`. When running an agent on the claude_code backend, SPF spawns it with `--permission-mode bypassPermissions --dangerously-skip-permissions` because the backend has no need to enforce — SPF will enforce in code instead, within those bounds.\n\nOne narrow, explicit exception: `defaults.read_only_ignore` (default: the lockfiles of npm/pnpm/yarn/bun) names paths a **true read-only** agent (`writes: []`) may touch without failing the phase — a read-only agent that runs a dependency-manager command to inspect a package's real shape rewrites its lockfile as a side effect of a *read*, not an edit. The path is still always rolled back; the phase only *passes* when the path was clean before the phase started (so the rollback is a real restore) — a path already dirty when the phase began fails exactly like any other breach, whether the agent left it modified or reverted an operator's own uncommitted work. And the exemption is scoped to true read-only roles only: a write-restricted agent (`writes: [...]`) that changes a lockfile alongside something it *was* given (say `package.json`) left an inconsistent tree, not incidental bookkeeping, and fails like any other breach.\n\n`protected_files` always takes precedence over `read_only_ignore`: a path matching `protected_files` is never exempt, even for a true read-only agent, even when it also happens to match a `read_only_ignore` pattern. `read_only_ignore` is a narrow \"this churn is incidental\" carve-out for dependency-manager bookkeeping — it is never a backdoor around a path an operator explicitly locked down with `protected_files`. That path is still rolled back like any ignored churn, but it fails the phase like any other breach.\n\nFor unattended work, `spf watch`'s PR-merge is the only human accountability checkpoint: the daemon opens a PR for each automated run, and a human approves the merge. For any other workflow, this enforcement is the backbone of letting a bounded agent proposal survive code's inspection without a human having to read it in between — but it is bounded, not a sandbox, and the scope above is what a reviewer should actually rely on. (Attended `simple-sdlc` runs get a second checkpoint of their own — see below.)\n\nSee `core/permissions.ts` for the implementation — the snapshot/compare logic, not the config terms.\n\n`simple-sdlc`'s `commit_build` phase is the one place in this codebase where an AI reviewer's `approved` flag alone would otherwise gate a commit — everywhere else the reviewer either doesn't run (`plan-build-test`, ...) or nothing commits on its verdict (`build-review` has no commit step). Run attended, that phase asks before committing — default **no**, never `review.approved` itself, bounded by `review.signoff_timeout_seconds` (default 300s; expiry answers no) — and only an explicit, recorded \"yes\" ever earns a `Signed-off-by:` trailer, built from `git config user.name`/`user.email` at the repo, never an env var. Run unattended (`spf watch`, CI), there is nobody to ask: `spf watch`'s own human gate is the PR merge above, informed by the reviewer's digest in the PR body, and the phase either proceeds on the AI verdict alone with a loud warning (`review.require_human_signoff: false`, this release's default — fail-open until `spf watch` itself becomes signoff-aware) or fails closed and asks you to rerun attended (`require_human_signoff: true`). See `assets/skill/references/config.md`'s `review` section for the two knobs, and [`assets/skill/cookbooks/ocr_reviewer.md`](assets/skill/cookbooks/ocr_reviewer.md) if you want the reviewer to fold a third-party review tool's findings into its own verdict as one more piece of evidence.\n\n---\n\n## Phases: three lanes, one primitive\n\nEvery run is a sequence of phases, and every phase is the same async scope no matter who owns it.\n\n```ts\nconst REQUIRED_AGENTS = [\"planner\", \"builder\"];   // names, never models\n\nconst cfg = agents.loadConfig(configPaths);\nagents.validate(cfg, REQUIRED_AGENTS, REQUIRED_SUITES, cwd);   // a missing agent fails before anything spawns\nconst run = session.ensure(cfg, adwId, cwd);                   // pin-or-create the session\n\nconst plan = await run.phase(\n  makePhaseParams({ name: \"plan\", kind: \"agent\", owner: \"planner\", description: \"Turn the request into a plan\" }),\n  (ph) => ph.call(makeAgentCall({ output_type: PlanOutput, prompt, gates: [gates.artifactsExist] })),\n);\n\nawait run.phase(\n  makePhaseParams({ name: \"commit\", kind: \"code\", owner: \"git\", description: \"Commit the working tree\" }),\n  async () => run.git.commitAll(build.commit_message || `spf: ${prompt.slice(0, 72)}`),\n);\n\nreturn run.finish();\n```\n\nThree kinds, three swim lanes. **engineer** is the human lane. **agent** is `ph.call(...)`: prompt in, typed envelope out, gates verified. **code** is a deterministic step that stands on its own — a commit, a quality suite — and is never buried inside an agent phase, so the trace shows exactly when code ran and when an agent was working.\n\n**Success must be earned.** Every phase defaults to `fail`. A clean exit flips it, and an agent phase also needs its envelope to parse and every gate to come back green. `run.finish(accepted, reason)` adds the second question, because phases passing is not the same as the run being acceptable: a test phase that ran a red suite did its job perfectly. One call settles the exit code, the session status, and the banner together, so they cannot disagree.\n\n---\n\n## Envelopes and gates\n\nAn agent has exactly two output channels: reference files written into `context_handoff/`, and a final valid-JSON response validated against the output type the call declared. Code persists that response as `envelope.json`, records it, and injects it into the next agent's prompt. Context transfers in code, not in conversation.\n\n```ts\nconst BuildOutput = envelopeType(\"BuildOutput\", {\n  changed_files: v.optional(v.array(v.string()), () => []),\n  commit_message: v.optional(v.string(), \"\"),   // consumed by the git commit phase\n});\n```\n\nDeterminism is wired into every step. Agents must return a specific structure, every time. If it does not validate, they get asked again until it does.\n\nGates verify claims, never predictions. Nobody knows which files an agent will touch before it finishes, so gates run **after** the fact against the envelope's own declarations: `artifactsExist`, `filesNonEmpty`, `jsonParses`, `diffMatchesClaims`, `testsPass(...)`. A gate is a function with the signature `gate(envelope, run) -> GateReport`, one `check(item, ok, note)` per thing it examined, so a green gate tells you *what* it verified.\n\nWhen validation fails or a gate returns violations, **nothing restarts**. The harness re-prompts the same session with a correction naming exactly what was wrong, and the context window stays intact. A cold restart throws away everything the agent learned. A correction costs one message.\n\nThe output contract lives in three places and they are one thing: the type in `data_types.ts`, the JSON example in that agent's `user.md` `## Report` section, and `output_type:` at the call site. **Change one, change all three in the same edit** — the synced triad.\n\n---\n\n## The trace\n\nOne data path, no exceptions: **agents write to SQLite, readers poll SQLite.** Every event lands in `.spf/data/spf.db` while the agent is still working, not batched at the end — tool calls are visible mid-run.\n\n```bash\nspf sessions                       # recent runs\nspf phases <adw_id>                # phase-by-phase status for one run\nspf events <adw_id> --follow       # the live trace, tailable\nspf ui                             # a browser-based visualizer over the same db\n```\n\nThat's the entire transport: a rowid-cursor poll query, run on demand. No push, no WebSocket, no ingest endpoint — live view and full history are the same query at different cadence.\n\nFiles stay the raw record (`envelope.json`, `agent_map.json`, Flue's own conversation store). The db is the queryable mirror. Losing it loses nothing you cannot rebuild.\n\n---\n\n## The chains\n\n```bash\nspf list                                              # every chain, its phases, what it needs\nspf <chain> \"<prompt or path/to/prompt.md>\" [--config <path>] [--adw-id a1b2c3d4] [--cwd <dir>] [--suite <name>]\n```\n\n| Chain | Phases | Reach for it when |\n|---|---|---|\n| `prompt` | engineer → \\<agent\\> | one agent, one prompt, `--agent NAME` picks who |\n| `scout` | engineer → scout | read-only recon, nothing changes |\n| `plan` | engineer → planner | you want the spec before any code |\n| `build` | engineer → builder | the plan already exists |\n| `quality` | engineer → code(quality) | lint, typecheck, build, no agents at all |\n| `plan-build` | planner, builder, git(commit) | small, well-understood work |\n| `build-test` | builder, code(test), bounded fix loop | there is a suite to satisfy |\n| `build-review` | builder, reviewer, bounded revise loop | \"is this what was asked for\" matters more than \"does it run\" |\n| `plan-build-test` | plan, build, code(test), git(commit) | the standard chain |\n| `plan-build-test-quality` | same, plus lint/typecheck/build gates | the repo has quality commands worth enforcing |\n| `document` | code(git diff), documenter | write up what just shipped |\n| `simple-sdlc` | plan, build, test, review, document | the work is real and its shape is not obvious |\n\nA chain with a compiled-in quality suite (`build-test`, `plan-build-test`, `plan-build-test-quality`, `quality`) accepts `--suite <name>` to override it for one run — `spf list` marks which chains this applies to with `(--suite overrides)`. `simple-sdlc`'s suite is not overridable this way; passing `--suite` to it is rejected rather than silently ignored.\n\n`--adw-id` is optional everywhere. Omit it and a fresh id is minted and printed. Supply it and the run joins that session — same session directory, each agent **resumes its existing context window** instead of starting cold. That's how you chain runs:\n\n```bash\nspf plan \"add a /health endpoint\"                        # prints adw_id a1b2c3d4\nspf build-test \"implement the plan\" --adw-id a1b2c3d4\n```\n\n### Repo-local chains\n\nEvery chain above is built in. A target repo can also compose its own out of\nthe same step factories, with zero forking and zero build step, by dropping a\nfile in `.spf/chains/*.yaml` — `spf init` scaffolds `.spf/chains/example.yaml`\n(fully commented out) showing the shape, plus `.spf/chains/review-fix.yaml`\nshowing how to put an external CLI (e.g. a code reviewer like\n`open-code-review`, or a linter) into the sequence as a gated fix loop:\n\n```yaml\n# .spf/chains/ship-it.yaml — spf ship-it \"<prompt>\" / spf run ship-it \"<prompt>\"\nname: ship-it\ndescribe: plan, build, test, land — with our own reviewer in the loop\nsteps:\n  - step: request\n  - step: plan\n    owner: architect\n  - step: build\n    extraGates: [jsonParses]   # additive only — a step's built-in gates can never be removed\n  - step: fixLoop\n    suite: test\n  - step: commit\n    onlyIfAccepted: true\n```\n\nIt shows up in `spf list`/`spf doctor` exactly like a built-in, and runs on\nthe identical `stepChain()` driver — there is no second interpreter. The full\nstep vocabulary, the gate rules, and the `spf watch` main-anchor divergence\n(a chain edited on an issue branch is *not* what an in-flight `spf watch` run\nuses) are documented in the installed skill's \"Repo-local chains\" section\n(`.claude/skills/spf/cookbooks/authoring_chains.md`, after `spf init`).\n\n---\n\n## `spf watch`\n\nPolls an issue tracker for issues labeled `<prefix>:ready`, runs a configured chain against each in its own git worktree, opens a PR against a code host, and tracks it through to merged or blocked — driving the same chains above rather than reimplementing an SDLC. Labels are the whole state machine: `ready → working → review → done`/`blocked`, plus `blocked ⇄ feedback` — see \"Revising a rejected (or still-open) PR\" below.\n\nA second, optional lane (`watch.refine`, off by default) decomposes a `<prefix>:spec-ready` product spec into a feature/story-or-bug tree of real issues instead — see \"Refining specs\" below.\n\nThe tracker (`issue_provider`) and the code host (`code_host`) are independent config choices, not one bundled \"provider\" — a tracker and a host are independent choices in practice (Jira issues against a Bitbucket repo is a real setup). Supported today: `issue_provider: github | jira`, `code_host: github | bitbucket` — any combination works, including Jira+GitHub or GitHub-issues+Bitbucket.\n\nThe easiest way into any of this is `spf init`'s interview: it asks whether to enable `spf watch`, which tracker and code host, and collects exactly the env vars that combination needs (below) straight into `.env` — no hand-editing YAML or hunting down which credential pair a given combination wants.\n\n```yaml\n# .spf/spf.config.yaml — GitHub issues + GitHub PRs (the default)\nwatch:\n  issue_provider: github     # default\n  code_host: github          # default\n  repo: owner/name\n  label_prefix: spf          # polls issues labeled spf:ready\n  chain: plan-build-test     # any registered chain\n  base_branch: main\n  poll_ms: 60000\n  concurrency: 2\n```\n\n```yaml\n# .spf/spf.config.yaml — Jira issues + Bitbucket PRs\nwatch:\n  issue_provider: jira\n  code_host: bitbucket\n  repo: workspace/repo_slug  # Bitbucket's own two-part identifier\n  label_prefix: spf          # polls Jira issues labeled spf:ready\n  chain: plan-build-test\n  base_branch: main\n  jira:\n    base_url: https://your-domain.atlassian.net\n    project_key: PROJ\n```\n\n```yaml\n# .spf/spf.config.yaml — GitHub issues + Bitbucket PRs, in TWO DIFFERENT repos\nwatch:\n  issue_provider: github\n  code_host: bitbucket\n  repo: workspace/repo_slug     # Bitbucket's repo — the CODE HOST always reads plain `repo`\n  issue_repo: owner/name        # GitHub's repo — only needed here, where issue tracker != code host\n  label_prefix: spf             # polls GitHub issues labeled spf:ready\n  chain: plan-build-test\n  base_branch: main\n```\n\n`repo` always names the code host's own repo; `issue_repo` overrides it for\nthe issue-tracker side. This only matters for `issue_provider: github` +\n`code_host: bitbucket` — the one combination where they're genuinely\ndifferent repos in different systems, not the same repo worn two ways\n(`github`+`github` is one repo by construction; `issue_provider: jira` never\nreads `repo` at all, so it's never ambiguous). Leave `issue_repo` unset\neverywhere else. `spf doctor` flags this specific combination when\n`issue_repo` is missing, since the silent failure mode — polling GitHub with\nthe Bitbucket identifier — finds no matching issues and looks exactly like\nnothing being configured at all.\n\n```bash\nspf watch init                # idempotently seed tracker state (labels are a no-op report on Jira — see below); run this first\nspf watch                    # foreground daemon; Ctrl-C drains in-flight claims first\nspf watch --once             # one poll tick, then exit — good for cron\nspf watch --dry-run          # log intended claims/transitions, mutate nothing\n```\n\nNo GitHub App, no webhook, no Jira/Bitbucket app install — it's a plain REST poll against whichever combination is configured, same philosophy as the trace db's own polling contract. See [`assets/templates/`](assets/templates/) for full worked configs (also usable directly via `spf init --template <name>`), and `spf install-skill`'s installed skill (`roster.md`, `references/config.md`) for the field-by-field reference.\n\n### `watch.allowed_authors` — the label isn't the trust boundary\n\n`<prefix>:ready` is a label, and on GitHub only accounts with Triage+ access can add one. But on a repo that accepts public issues, ANYONE can open an issue and write whatever they want in its body — labeling and authoring are different permissions, held by different people. A collaborator who labels a plausible-looking public issue `ready` without catching an embedded instruction hands that issue's body to a coding agent with real Bash/write access as if it were trusted input. The label gate alone doesn't stop this, because the person who can label and the person who wrote the content aren't the same person.\n\n```yaml\nwatch:\n  allowed_authors: [octocat, some-other-trusted-login]   # empty (default) = unrestricted\n```\n\nEmpty (the default) is unrestricted — identical to every `spf watch` release before this field existed. A non-empty list is a hard refusal, checked against `Issue.author` (the account that OPENED the issue, never whoever most recently labeled or edited it): an issue from anyone else is transitioned straight to `blocked` with an explanatory comment, before a worktree, a lock, or a chain run ever exist for it. Re-labeling it `ready` again does nothing — the fix is either adding that author to the list, or opening an equivalent issue yourself. `spf doctor` reports whether this is set.\n\nThis applies to both lanes — `claimNewWork` (`<prefix>:ready`) and `claimSpecs` (`<prefix>:spec-ready`/`continue-refinement`). It does not get in your own way: an issue the refine lane creates itself (a spec's decomposed children) carries whichever tracker identity your own configured credential creates issues as, so if you're in your own `allowed_authors` list (the common case — you're the one who filed the spec), its children pass too.\n\n### Priority, dependencies, and picking what's next\n\nAmong every `<prefix>:ready` issue, `spf watch` claims in this order:\n\n1. **Priority** — the `<prefix>:priority:p0|p1|p2|p3` label (`p0` drop-everything, `p2` the default, `p3` someday). `spf watch init` seeds all four. A human relabeling an issue is the whole override mechanism — there's no separate priority command.\n2. **Sibling affinity** — among issues at the same priority, one whose parent feature already has a sibling in flight goes first. This is what tends to finish one feature before starting the next without giving up the one-PR-per-story design (see \"Refining specs\" below): each story is still its own claim, its own worktree, its own PR — affinity only orders which claim happens next.\n3. **Creation order** (oldest first) — the final tiebreaker.\n\nBefore claiming anything, `spf watch` also checks the **frontier**: an issue's `blocked_by` dependencies (set by the refine lane, or by hand) must all carry `<prefix>:done` first. A leaf whose blockers aren't done yet is skipped, not blocked — it's simply reconsidered next tick, once the log line naming what it's waiting on stops applying.\n\nThis is a **label**, not this repo's own GitHub Projects v2 \"Priority\" field (if your board has one — Urgent/High/Medium/Low, say). `spf watch` never reads or writes Projects v2: no GraphQL, no `project` token scope, no Jira equivalent. If you use both, they're independent — nothing reconciles them, and `spf watch` obeys only the label. Keep them aligned yourself, or don't use the board field for this repo's issues.\n\n### Revising a rejected (or still-open) PR (`<prefix>:feedback`)\n\nA declined PR used to be a dead end: relabeling the issue back to `ready` threw away the PR entirely and started over from `origin/<base>` with the original issue text — no memory of what was wrong, and (until this label existed) a `git push` non-fast-forward rejection against the still-live remote branch. `<prefix>:feedback` fixes both: leave your corrections as **comments on the PR itself** (not the issue), add the label, and `spf watch` reruns the same issue with that PR's comment thread folded into the prompt.\n\n```text\nreview ──(you decline the PR)──→ blocked   \"leave corrections as comments on PR #N,\n                                    │        then add <prefix>:feedback\"\n                                    ▼\n                                 feedback ──claim──→ working ──┬─→ PR still open:   rebuild from the PR's\n                                                                │   own branch head, push, SAME PR updates\n                                                                └─→ PR closed:       fresh branch, new PR\n                                                                                      superseding the old one\n                                                                    → review\n```\n\nNo decline required first: add `<prefix>:feedback` to an issue whose PR is **still open** (leave a review comment, then label it) and `spf watch` rebuilds from that PR's own branch head and pushes the fix onto the *same* PR — no new PR number, just a new commit landing on what's already under review. That's the primary path this exists for. A PR that was actually closed/declined instead gets a fresh `-rN`-suffixed branch and a new PR whose body notes it supersedes the old one, since there's no branch head left to build on top of.\n\nCorrections come from **PR comments**, not issue comments — deliberately a different channel from the refine lane's `continue-refinement` loop above, matching where a human actually reviews code. Reading them needs `CodeHostProvider.listPrComments`, implemented for both GitHub (issue comments + inline review comments + review verdicts, merged into one thread) and Bitbucket; a code host without it degrades honestly — the issue blocks again with an explanation instead of silently rebuilding with no corrections.\n\n`spf watch init` seeds `<prefix>:feedback` alongside the other state labels — **re-run it** after upgrading to this version.\n\n### Refining specs (`watch.refine`)\n\nA product spec isn't individually workable — it needs to become a feature,\nbroken down into user stories and bugs, before the build lane above has\nanything to claim. `watch.refine` is a second lane over the same poll loop\nthat does exactly that: it polls `<prefix>:spec-ready`, runs a decomposition\nchain (`refine` by default — `request → scout → refiner → publish`) against\nthe spec in its own worktree, and publishes what it produces as real tracker\nissues — a feature/epic container plus story/bug/task leaves, linked into a\nreal hierarchy: GitHub's native sub-issues API, or Jira's `parent` field.\n\n```yaml\nwatch:\n  issue_provider: github    # or jira — both implement issue authoring\n  repo: owner/name\n  refine:\n    enabled: true\n    chain: refine           # any chain that ends in steps.publishIssues()\n    concurrency: 1          # this lane's own budget, independent of watch.concurrency\n    max_leaves: 4           # optional — shown are the defaults; the decomposition BUDGET, see below\n    max_nodes: 6\n    max_depth: 2\n```\n\n(A third, independent budget lives at `watch.fanout.concurrency` — best-of-N\nattempts per claimed issue, not specs. See \"Best-of-N per issue\" below.)\n\n**The decomposition budget.** Every leaf the refiner emits becomes its own\nworktree, its own chain run, and its own pull request a human reads once\npromoted — so leaf count is human review count. `assets/prompts/refiner/\nsystem.md` targets one feature and three or four leaves; `refine.max_leaves`\n(default 4), `refine.max_nodes` (default 6), and `refine.max_depth` (default\n2) are the hard CEILINGS `gates.refinementWellFormed` enforces on top of that\ntarget, one slice past where a good decomposition sits so the gate never\nmakes the target a floor. `max_nodes` doesn't bind at the defaults — it\nexists so raising `max_leaves` or `max_depth` alone can't silently uncap the\nwhole tree. Raising `max_depth` above 2 is unsafe on Jira specifically: see\n\"On Jira\" just below. A tree with a container wrapping exactly one child also\nfails — a container that groups nothing is pure ceremony — and every leaf\nmust carry a one-sentence `user_outcome` (rendered as a `## Outcome` section\non the tracker issue) naming who benefits and what changes for them; a\nprocess/QA/rollout leaf has no honest sentence to write and gets folded into\nwhichever leaf's acceptance criteria it actually belongs to instead. See\n\"Splitting an over-large spec\" below for what happens when a spec honestly\ndoesn't fit.\n\nOn Jira, every `RefinedIssue.kind` (`epic`/`feature`/`story`/`bug`/`task`),\nplus `spec` (a standalone spec proposed by splitting an over-large one — see\n\"Splitting an over-large spec\" below), maps to a real Jira issue type through\n`watch.jira.issue_types` — defaults `epic`/`feature` → `Epic`, `story`/`spec`\n→ `Story`, `bug` → `Bug`, `task` → `Task`, overridable per kind since real\nprojects rename or customize these:\n\n```yaml\nwatch:\n  issue_provider: jira\n  jira:\n    base_url: https://your-domain.atlassian.net\n    project_key: PROJ\n    issue_types:        # optional — shown are the defaults\n      epic: Epic\n      feature: Epic\n      story: Story\n      bug: Bug\n      task: Task\n      spec: Story\n  refine:\n    enabled: true\n```\n\nHierarchy uses Jira's modern `parent` field only (no legacy \"Epic Link\"\ncustom-field support) — this works on team-managed projects and on\ncompany-managed projects with Jira's current issue-hierarchy setting; a\nproject not configured for it surfaces Jira's own API error, unmodified.\nOne accepted platform limitation: Jira doesn't support Epic-under-Epic\nnesting the way GitHub's sub-issues API supports up to 8 levels, so a\n`feature` node parented under another `epic`/`feature` (both `Epic` by\ndefault) will fail at publish time on Jira specifically — a real platform\ndifference, not a bug. `refine.max_depth`'s default of 2 makes this\nunreachable in practice (see \"The decomposition budget\" above); raise it\npast 2 only on a tracker where deeper nesting is actually supported. A `spec`\nnever parents another `spec` either way — see \"Splitting an over-large spec\"\nbelow. Both `spf watch init` and `spf watch`'s own startup check validate\n`watch.jira.issue_types` against the real project before anything unattended\nruns — see \"Jira\" below.\n\nEvery generated issue carries a `<prefix>:type:epic|feature|story|bug|task`\nlabel AND a `<prefix>:priority:p0|p1|p2|p3` label (see \"Priority, dependencies,\nand picking what's next\" above) — the refiner proposes the priority, a human\ncan relabel it before promoting. A container (a feature/epic — something\nelse names it as `parent`) gets only those two labels; a leaf additionally\ngets `<prefix>:refined` — **never** `<prefix>:ready`. Promoting a leaf to\n`<prefix>:ready` is a deliberate human decision: the refine lane never\nauto-promotes anything. This is the SECOND line of defense against a\ndecomposition nobody looked at before it turns into unattended chain runs and\nPRs — the first is the decomposition budget itself (see above), which keeps\nthat number small (four leaves by default, not twenty) rather than relying on\nmanual promotion alone to absorb an oversized tree. Once you do promote a\nleaf, the existing build lane picks it up completely unchanged — including\nthe frontier check: a promoted leaf isn't claimed until every issue named in\nits `blocked_by` is `<prefix>:done`.\n\nA spec issue's own `<prefix>:priority:pN` label, if it has one, reaches the\nrefiner as a **ceiling**: no generated node may be more urgent than the spec\nitself (enforced regardless of what the refiner emits — see\n`core/refine.ts`'s `publish()`). `spf refine ... --priority p1` sets the same\nceiling for a bare manual run with no spec issue to read a label from.\n\nGrounding the decomposition in real code is structural, not just prose: a\n`scout` phase maps the subsystems the spec touches before the refiner ever\nruns, and its findings flow straight into the refiner as context. This makes\n`scout` a required agent for the `refine` chain — a roster that pruned it\nfails `spf watch` startup by name, the same as any other missing required\nagent.\n\n#### Human-in-the-loop escalation\n\nThe refiner is instructed not to guess on anything material (scope, data\nmodel, an external dependency choice, a UX contract, a breaking change, or\nanything that would contradict an existing ADR — see\n`assets/prompts/refiner/system.md`'s \"Ask, don't decide\"). When it hits real\nambiguity it raises questions instead of publishing a partial tree, and the\nspec moves through an extra loop before it's even fully published:\n\n```text\nspec-ready → refining ──┬─→ spec-in-progress → done / blocked   (published a tree, THEN tracked to completion)\n                         ├─→ needs-feedback                      (raised questions)\n                         │        │  a human answers in the issue's comments,\n                         │        │  then adds continue-refinement\n                         │        ▼\n                         │   refining (again, same adw_id) → ...\n                         └─→ split-proposed                       (spec too large — see below)\n```\n\nAnswer the refiner's questions as comments on the spec issue, then add the\n`<prefix>:continue-refinement` label. `spf watch` resumes the **same**\n`adw_id` — the refiner's own coding-agent session continues, with the\ncomment thread folded into its prompt — so it never re-derives context it\nalready had, and it can loop through as many rounds as it takes; there's no\ncap. If channels are configured (see \"Notifications\" below), a\n`spec_needs_feedback` event fires every round.\n\n**Publishing a tree does not mean the spec is done.** A product manager\nwatching a spec's status needs \"done\" to mean the work is actually finished,\nnot merely that a decomposition happened — so once the refiner publishes,\nthe spec moves to `<prefix>:spec-in-progress`, not `<prefix>:done`. It stays\nthere — with a summary comment listing every issue it created, noting how\nmany rounds of feedback it took, if any — until **every one of those\nissues** reaches `<prefix>:done` (a leaf that lands, or a feature/epic\ncontainer once `rollUp` has already finished it — see \"Container roll-up\"\nbelow). Only then does `spf watch` transition the spec to `<prefix>:done`,\npost a closing comment, and close it on the tracker where the tracker\nsupports closing at all — GitHub does (best-effort: a failed close never\nturns completed work back into `blocked`); Jira doesn't have this wired up,\nso a Jira spec still relabels and comments correctly, just stays open. A\n`spec_done` event fires either way, distinct from the earlier\n`spec_refined`. A spec whose\ngenerated leaf never gets promoted, or whose work stalls `blocked`, simply\nstays `spec-in-progress` — which is the truthful state, not a bug.\n\nThe spec issue's full lifecycle: `spec-ready → refining → needs-feedback ⇄\nrefining → spec-in-progress → done`/`blocked` (the `needs-feedback ⇄\nrefining` loop only when the refiner actually escalates), or, when the spec\nis too large rather than ambiguous, `spec-ready → refining → split-proposed →\n...` — see \"Splitting an over-large spec\" just below. Try it by hand first,\nagainst a real spec, before turning on the daemon:\n\n```bash\nspf refine \"<spec text or path/to/spec.md>\" --issue 42               # --issue renders a \"## Parent\" section, \"Decomposed from #42.\"\nspf refine \"<spec text or path/to/spec.md>\" --issue 42 --priority p1 # --priority clamps every generated node to p1 or less urgent\n```\n\n#### Splitting an over-large spec\n\nAmbiguity isn't the only reason a refiner can't publish a tree this round —\nsometimes the spec is simply too big, honestly, for the decomposition budget\nabove. Rather than force-fit an oversized tree (or worse, merge unrelated\nslices into a handful of leaves that hit the number but blur past what a\nreviewer can hold in their head), the refiner proposes a concrete **split**\ninto two or more standalone specs — each with its own user value, each\nindependently shippable, never \"phase 1\"/\"phase 2\" of the same thing:\n\n```text\nspec-ready → refining ──→ split-proposed\n                                │  a human reviews the proposal comment, then either\n                                │    · adds split-approved      → executed deterministically, NO agent re-run\n                                │    · comments + continue-refinement → refiner revises the proposal\n                                ▼\n                          N new specs created (spec-ready, type:spec), recorded\n                          on the ORIGINAL spec, which moves to spec-in-progress\n```\n\nApproving with `<prefix>:split-approved` is a deliberate, different label\nfrom `continue-refinement`'s \"resume the refiner\" — creating exactly what a\nhuman already read in the proposal comment is a `code`-shaped action (no\nscout, no refiner session, no worktree), the same way publishing a tree is.\nEach created spec carries `<prefix>:type:spec` and `<prefix>:spec-ready` (never\n`<prefix>:refined` — a spec is not itself a workable leaf) and a `## Parent`\nback-reference to the original spec it was split from; on Jira it maps to a\n`Story` by default (`watch.jira.issue_types.spec`), never nested under\nanother spec, since Jira has no Story-under-Story hierarchy to use. The\n**original** spec's own `spec-in-progress` tracking now waits on both child\nspecs finishing their own trees, transitively — the same roll-up mechanism\n\"Publishing a tree does not mean the spec is done\" above already describes,\nwith no separate tracking needed for a split. A child spec that is itself\nstill too large can split again — a genuinely huge spec bottoming out over a\ncouple of rounds is expected; watch for repeated split proposals on the same\noriginal spec as the signal something is off, rather than a hard generation\ncap.\n\n#### Container roll-up\n\nA feature or epic isn't itself a unit of work, so it's never claimed and\nnever opens a PR — but it isn't abandoned once its children exist, either.\nEvery time a leaf's PR merges, `spf watch` checks that leaf's parent: once\n**every** child under a container carries `<prefix>:done`, the container\ngets a summary comment (every child it rolled up, by id), transitions to\n`<prefix>:done`, and closes on the tracker if the tracker supports closing\nat all (GitHub does; Jira doesn't have this wired up, so a Jira container\nstill relabels and comments, just stays open) — then the same check runs on\n*its* parent, so an epic of features rolls up once its last feature does.\nA container with even one unfinished child (including one still sitting at\n`<prefix>:refined`, never promoted) is left exactly as it is; nothing times\nout or force-closes it.\n\nRoll-up needs to read back the hierarchy `publish()` created — GitHub's\nnative sub-issues API, or a Jira `parent = \"<id>\"` JQL search — so it works\non both providers today, same as authoring itself. A tracker that isn't\nauthoring-capable at all gets a logged no-op, not a startup failure, since\nthe build lane still works fine without roll-up.\n\n`spf watch init` seeds the type labels alongside the state ones — **re-run\nit** after upgrading to this version, so it can create the new\n`<prefix>:type:spec`, `<prefix>:split-proposed`, and\n`<prefix>:split-approved` labels, alongside the earlier\n`<prefix>:needs-feedback` and `<prefix>:continue-refinement`. This lane's\nprompt (`assets/prompts/refiner/`) is adapted from a \"tracer-bullet ticket\"\ndecomposition skill — vertical slices, a `blocked_by` dependency graph, and\nan expand/migrate/contract sequence for wide mechanical refactors — with a\ngate (`gates.refinementWellFormed`) added on top to enforce the container/\nleaf shape that skill left as prose convention rather than a checked rule:\ncontainer/leaf kind agreement, no container with a single child, a depth\ncap, a leaf/node count ceiling, a required per-leaf user-outcome sentence,\nand that a refinement never publishes issues alongside questions or a split\nproposal in the same round.\n\n### Best-of-N per issue (`watch.fanout`)\n\n`spf fanout` runs N sibling attempts of one prompt and lets code pick the\nwinner (`pickBest`: succeeded > fewest gate failures > most gate passes >\nlowest cost > fewest tokens > lowest wall time > adw_id, see the `spf fanout`\nsection above). `watch.fanout` is that same mechanism pointed at `spf watch`'s\nper-issue dispatch: a claimed issue runs `n` sibling attempts instead of one,\nand everything downstream of the winner — push, PR, review digest, marker,\ntransition, notify — is the same code that already runs for a single attempt.\n\n```yaml\nwatch:\n  repo: owner/name\n  chain: plan-build-test    # must have a commit step once n > 1 — see below\n  concurrency: 2             # issues claimed and run at once — UNCHANGED meaning\n  fanout:\n    n: 1                     # attempts per claimed issue. 1 (the default) = today's single dispatch, no-op for the daemon\n    concurrency: 2            # attempts of ONE issue's fan-out in flight — NOT watch.concurrency\n```\n\nTwo budgets, two names, on purpose: `watch.concurrency` counts **issues** in\nflight (unchanged); `watch.fanout.concurrency` counts **attempts of one\nissue's fan-out** in flight. They multiply rather than share one number — an\noperator who wants \"2 issues at a time, 1 attempt each\" (serialize attempts,\nkeep issue-level parallelism) can say exactly that by setting\n`fanout.concurrency: 1`, which a single shared knob couldn't express. `spf\ndoctor`'s `watch.fanout` line prints the product (`concurrency × fanout.concurrency`\nchain runs in flight) so nobody has to compute it by hand.\n\n**Disk, not just chain runs.** `fanout.concurrency` bounds attempts *in\nflight*; it does **not** bound worktrees *on disk*. A successful attempt's\nworktree is kept until every sibling in its fan-out has settled (it's still a\nselection candidate), so peak disk per wave is `watch.concurrency ×\nwatch.fanout.n` full checkouts, not `watch.concurrency × watch.fanout.concurrency`\n— at `concurrency: 4, fanout.n: 8` that's 32 working copies at once under\n`worktreesDir` (`~/.spf/watch/<repo>/worktrees`). Plan disk against `n`, not\nagainst `fanout.concurrency`.\n\n`n > 1` requires `chain` to have a commit step — `spf watch` refuses to start\notherwise. The reason is sharper than `spf fanout`'s own version of this\ncheck: best-of-N force-removes every losing attempt's worktree once a winner\nis picked, `--force` included, and a chain that never commits leaves its\nentire payload as uncommitted edits — fan-out would destroy N-1 candidates\noutright rather than just fail one attempt. `n: 1` has no such requirement (a\nchain that commits nothing is handled the same honest way it always has been:\nblocked, worktree cleaned, nothing discarded).\n\n`n: 1` (the default) changes nothing about a running daemon's observable\nbehaviour — same adw_id, same branch, same worktree, same fetch semantics,\nsame marker, same PR. `spf doctor` still prints one informational\n`watch.fanout` line either way, so the posture is visible even when best-of-N\nis off.\n\n### GitHub (`issue_provider: github` and/or `code_host: github`)\n\n```bash\nexport GITHUB_TOKEN=...   # classic PAT; spf doctor checks it's set\n```\n\n`spf watch init` seeds every `<prefix>:<state>` label (`ready`/`working`/`review`/`done`/`blocked`/`feedback`/`spec-ready`/`refining`/`refined`/`needs-feedback`/`continue-refinement`/`spec-in-progress`/`split-proposed`/`split-approved`), plus `<prefix>:type:epic`/`feature`/`story`/`bug`/`task` (used by the refine lane whether or not it's enabled) and `<prefix>:priority:p0`-`p3`, each with a color and description — safe to re-run any time (creates what's missing, corrects any that drifted, leaves the rest alone).\n\nA **classic** PAT (fine-grained tokens use different permission names — not covered here), scoped to the minimum that covers every call `spf watch`/`spf watch init` makes on GitHub: creating/editing labels, reading and labeling issues, posting comments, opening PRs, reading PR/check-run status, and — with `watch.refine.enabled` — creating issues and linking them via the sub-issues API. All of it is already covered by `repo`/`public_repo`; refine needs no additional scope.\n\n| Target repo | Scope | Covers |\n|---|---|---|\n| Private | `repo` | Everything above, full read/write |\n| Public only | `public_repo` | The same, restricted to public repos |\n\nThere's no dedicated \"issues\" or \"pull requests\" scope on classic PATs — GitHub bundles both into `repo`/`public_repo`, which is why that table covers everything by default.\n\nNative GitHub Projects v2 board status (the board's Status column) is a separate, optional layer on top, off by default — labels alone don't move it, so an issue's Status sits wherever it started unless you opt in with `watch.github.project_number` and `watch.github.status_map`:\n\n```yaml\nwatch:\n  issue_provider: github\n  repo: owner/name\n  github:\n    project_number: 3   # owner's Projects v2 board number — see the board's own URL\n    status_map:          # optional — unset by default, per state\n      ready: Todo\n      working: In Progress\n      review: In Review\n      done: Done\n```\n\nOnly the states you map are touched; an unmapped state keeps today's label-only behavior, and `project_number: 0` (the default) disables sync outright regardless of `status_map`. This needs the **`project`** scope in addition to `repo`/`public_repo` — Projects v2 has no REST API at all, only GraphQL, and that surface is gated by its own scope; grant it only if you're using `status_map`. A configured option name with no matching Status option (or a rejected mutation) is logged and skipped, never thrown — the label update is what `spf watch` actually depends on; status sync is a best-effort convenience on top of it. `spf watch init` and `spf watch`'s own startup check both validate a configured `status_map` against the real project's Status options, read-only, and exit non-zero on a mismatch, the same way Jira's `issue_types` is validated below.\n\n### Jira (`issue_provider: jira`)\n\n```bash\nexport JIRA_EMAIL=you@example.com\nexport JIRA_API_TOKEN=...   # id.atlassian.com -> Security -> API tokens\n```\n\nState is modeled as Jira **labels** (`<prefix>:ready`, etc.), mirroring GitHub exactly — labels are spf's actual state machine and always get written unconditionally, with zero per-project setup. One caveat: colons are a legal Jira label character and JQL matches on them fine, but they won't show up in Jira's own label autocomplete UI — cosmetic only.\n\nNative Jira workflow status (the board's Status column) is a separate, optional layer on top, off by default — labels alone don't move it, so an issue's Status sits wherever it started unless you opt in with `watch.jira.status_map`:\n\n```yaml\nwatch:\n  issue_provider: jira\n  jira:\n    base_url: https://your-domain.atlassian.net\n    project_key: PROJ\n    status_map:        # optional — unset by default, per state\n      ready: To Do\n      working: In Progress\n      review: In Review\n      done: Done\n```\n\nOnly the states you map are touched; an unmapped state keeps today's label-only behavior. This is opt-in rather than automatic because Jira workflows vary by project/scheme — status names and which transitions are reachable from where isn't something spf can assume, unlike labels. A configured name with no reachable transition (or a rejected one) is logged and skipped, never thrown — the label update is what `spf watch` actually depends on; status sync is a best-effort convenience on top of it.\n\n`spf watch init` still doesn't create any labels here (Jira labels are freeform strings with no color/description registry to seed, unlike GitHub's) — it reports the labels this run will use. With `watch.refine.enabled`, it also validates `watch.jira.issue_types` against the real project's issue types, read-only, and exits non-zero on a mismatch — see \"Refining specs\" above. Independent of `refine.enabled`, if `watch.jira.status_map` has any entry configured, both `spf watch init` and `spf watch`'s own startup check validate it against the real project's statuses the same way, and exit non-zero on a mismatch.\n\nWhen refining a spec into a tree, the published root(s) get linked back to the spec they came from via `watch.jira.link_type` (default `\"Relates\"`), a plain Jira issue link — never the hierarchical `parent` field, since the spec's own issue type frequently can't legally parent a root node's type. **`link_type` must name a symmetric link type**: the code fixes which side is which (the published root is always `inwardIssue`, the spec always `outwardIssue`) rather than exposing direction as a separate config knob, which is harmless for a symmetric type like \"Relates\" but would silently assert the opposite relationship for a directional one (e.g. \"blocks\"). If the issue-link API itself is unavailable (a renamed/removed link type, a restr","readmeFilename":"README.md"}