{"_id":"@alexzhaosheng/huko","_rev":"8-82fe97753ac9aac75d3f64d2f5ecf389","name":"@alexzhaosheng/huko","dist-tags":{"latest":"0.5.1"},"versions":{"0.1.0":{"name":"@alexzhaosheng/huko","version":"0.1.0","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"author":{"name":"alexzhaosheng"},"license":"MIT","_id":"@alexzhaosheng/huko@0.1.0","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"bin":{"huko":"bin/huko.mjs"},"dist":{"shasum":"97d644ad62cab68706b049a5695252de6cb2b382","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.1.0.tgz","fileCount":4,"integrity":"sha512-myacknfi5lzkN3Ht0NBbbNirgL7/njRLpvFFd+96pM2FUpl8CW66eySVma6loZ1s3XZzuwOLmpgzFq7+JetPCA==","signatures":[{"sig":"MEUCIQDZYWPheiYqXBGSWKWd/3lExedoNTS3thYXEjUYgy59PgIgfM6zbsIMy8lHTS2WNrb1/2G/POPLjQ/LsQdPkriCV2M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":489396},"type":"module","engines":{"node":"24.x"},"gitHead":"b520c1835ebc2a2a61530a3da5cd3971aff00819","scripts":{"huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","check":"tsc --noEmit","build:cli":"esbuild server/cli/index.ts --platform=node --packages=external --bundle --format=esm --outfile=dist/cli.js","db:migrate":"tsx scripts/db-migrate.ts","prepublishOnly":"npm run check && npm run build:cli"},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"repository":{"url":"git+https://github.com/alexzhaosheng/huko.git","type":"git"},"_npmVersion":"11.11.0","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"zod":"^4.0.0","dotenv":"^16.0.0","nanoid":"^5.0.0","express":"^4.21.0","socket.io":"^4.8.0","iconv-lite":"^0.6.3","drizzle-orm":"^0.44.0","@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","socket.io-client":"^4.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","esbuild":"^0.25.0","cross-env":"^7.0.3","typescript":"^5.9.0","@types/node":"^22.0.0","drizzle-kit":"^0.31.0","@types/express":"^4.17.0","@types/better-sqlite3":"^7.6.0"},"_npmOperationalInternal":{"tmp":"tmp/huko_0.1.0_1778580975774_0.5170298410666077","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alexzhaosheng/huko","version":"0.2.0","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"author":{"name":"alexzhaosheng"},"license":"MIT","_id":"@alexzhaosheng/huko@0.2.0","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"bin":{"huko":"bin/huko.mjs"},"dist":{"shasum":"3c2c9d07448c4363cd2f6de869475f0620c7144d","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.2.0.tgz","fileCount":4,"integrity":"sha512-bGSV5fhwZV9hAhJGM+s7oO1cj09vRMQ6+5WLv4nlg/LK8QhV2BbR1i959Zdn6t2tJf576v2+stdefpdRPm5ZUA==","signatures":[{"sig":"MEYCIQDezovgYGF8gevZMmmxD++FOT6rH2DlmUqE6DgYpvdeyAIhAJIpHvZ95NwgqV1c2xt3nmkaG+7CNnlZgSJ2bvWaBC9H","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":531101},"type":"module","engines":{"node":"24.x"},"gitHead":"30ec6c45c60f5242278648ca0bd28ef605b88929","scripts":{"huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","check":"tsc --noEmit","build:cli":"esbuild server/cli/index.ts --platform=node --packages=external --bundle --format=esm --outfile=dist/cli.js","db:migrate":"tsx scripts/db-migrate.ts","prepublishOnly":"npm run check && npm run build:cli"},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"repository":{"url":"git+https://github.com/alexzhaosheng/huko.git","type":"git"},"_npmVersion":"11.11.0","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"zod":"^4.0.0","dotenv":"^16.0.0","nanoid":"^5.0.0","express":"^4.21.0","socket.io":"^4.8.0","iconv-lite":"^0.6.3","drizzle-orm":"^0.44.0","@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","socket.io-client":"^4.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","esbuild":"^0.25.0","cross-env":"^7.0.3","typescript":"^5.9.0","@types/node":"^22.0.0","drizzle-kit":"^0.31.0","@types/express":"^4.17.0","@types/better-sqlite3":"^7.6.0"},"_npmOperationalInternal":{"tmp":"tmp/huko_0.2.0_1778635979201_0.15381663498271636","host":"s3://npm-registry-packages-npm-production"}},"0.2.1":{"name":"@alexzhaosheng/huko","version":"0.2.1","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"author":{"name":"alexzhaosheng"},"license":"MIT","_id":"@alexzhaosheng/huko@0.2.1","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"bin":{"huko":"bin/huko.mjs"},"dist":{"shasum":"327e35e258abace6c705a6f6b20175d9e80f368d","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.2.1.tgz","fileCount":5,"integrity":"sha512-S0DX17ZM0CdUlOgRFseh0+a6ecDndXcdB360uQv3v2N0xmkGNt83zoyJQKu584Wf9xOjzejnu4M6fpGEXaxpHw==","signatures":[{"sig":"MEQCIF8ee1/yjozYHZGxXOF3usu4mdCuPt2T/yT5RMDAfNlKAiBktoW1ocbQZg2C3jIauIxKuU0XAbFynwjNwcNRGJ0cew==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.2.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":534273},"type":"module","engines":{"node":"24.x"},"gitHead":"0edc97782cb9eee30643ad549e83b9637dab4c3c","scripts":{"huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","check":"tsc --noEmit","build:cli":"node scripts/build-cli.mjs","db:migrate":"tsx scripts/db-migrate.ts","prepublishOnly":"npm run check && npm run build:cli"},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"repository":{"url":"git+https://github.com/alexzhaosheng/huko.git","type":"git"},"_npmVersion":"11.11.0","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"zod":"^4.0.0","dotenv":"^16.0.0","nanoid":"^5.0.0","express":"^4.21.0","socket.io":"^4.8.0","iconv-lite":"^0.6.3","drizzle-orm":"^0.44.0","@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","socket.io-client":"^4.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","esbuild":"^0.25.0","cross-env":"^7.0.3","typescript":"^5.9.0","@types/node":"^22.0.0","drizzle-kit":"^0.31.0","@types/express":"^4.17.0","@types/better-sqlite3":"^7.6.0"},"_npmOperationalInternal":{"tmp":"tmp/huko_0.2.1_1778642489797_0.3911781042981737","host":"s3://npm-registry-packages-npm-production"}},"0.2.4":{"name":"@alexzhaosheng/huko","version":"0.2.4","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"author":{"name":"alexzhaosheng"},"license":"MIT","_id":"@alexzhaosheng/huko@0.2.4","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"bin":{"huko":"bin/huko.mjs"},"dist":{"shasum":"5cf680b8796532d8a8949405f5cdee2ed208b8a6","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.2.4.tgz","fileCount":5,"integrity":"sha512-lPSArjp3fT9SXaZWIa6hqM7yWV0UfNElHFyJFopxS8JX56hqAqf8IrEa5FKyxlkivtTyhERHH/j38tjjGfmgdw==","signatures":[{"sig":"MEUCIQD4I8Hhjzl1kGwTXs9F4jsRwNkFfG6Uylg/Tq2jvLFHBQIgKi6BxHxI7fRALWa4p27/lRPGf58u/aLHhMEoZCtgiqY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.2.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":554244},"type":"module","engines":{"node":"24.x"},"gitHead":"ac75f829ca66eb712eacd489432da2a0c32cab04","scripts":{"huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","check":"tsc --noEmit","build:cli":"node scripts/build-cli.mjs","db:migrate":"tsx scripts/db-migrate.ts","prepublishOnly":"pnpm run check && pnpm run build:cli"},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"repository":{"url":"git+https://github.com/alexzhaosheng/huko.git","type":"git"},"_npmVersion":"11.12.1","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"zod":"^4.0.0","dotenv":"^16.0.0","nanoid":"^5.0.0","express":"^4.21.0","socket.io":"^4.8.0","iconv-lite":"^0.6.3","drizzle-orm":"^0.44.0","@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","socket.io-client":"^4.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","esbuild":"^0.25.0","cross-env":"^7.0.3","typescript":"^5.9.0","@types/node":"^22.0.0","drizzle-kit":"^0.31.0","@types/express":"^4.17.0","@types/better-sqlite3":"^7.6.0"},"_npmOperationalInternal":{"tmp":"tmp/huko_0.2.4_1778801209196_0.3295600584880749","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@alexzhaosheng/huko","version":"0.3.0","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"author":{"name":"alexzhaosheng"},"license":"MIT","_id":"@alexzhaosheng/huko@0.3.0","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"bin":{"huko":"bin/huko.mjs"},"dist":{"shasum":"bf022ca79567b9d8f75a41b76ca7987f940dfa7c","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.3.0.tgz","fileCount":5,"integrity":"sha512-4L0gT0LKYWddTkMBWmYKIuZWlyX4lTwcJJJg93qVOfgqMGJ+tsWWrJebYv+JeNyaUof2Z+kSHdAN5KMfIgxRjw==","signatures":[{"sig":"MEUCIA0gohe4v3quJMQCu/TN9xxOyzaO4sDQSpiSM6h3tLX1AiEAvcMDXOaVSqkLEzI7gL6NjpuGKcfHdGgxyV8xYaf4Cig=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":635523},"pnpm":{"onlyBuiltDependencies":["better-sqlite3","esbuild"]},"type":"module","engines":{"node":"24.x"},"gitHead":"2a2c6e801084547bc5b51a7e9b9b03d4594b2a4c","scripts":{"huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","check":"tsc --noEmit","build:cli":"node scripts/build-cli.mjs","db:migrate":"tsx scripts/db-migrate.ts","prepublishOnly":"pnpm run check && pnpm run build:cli"},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"repository":{"url":"git+https://github.com/alexzhaosheng/huko.git","type":"git"},"_npmVersion":"11.12.1","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"ws":"^8.20.1","zod":"^4.0.0","dotenv":"^16.0.0","marked":"^15.0.12","nanoid":"^5.0.0","express":"^4.21.0","socket.io":"^4.8.0","iconv-lite":"^0.6.3","drizzle-orm":"^0.44.0","@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","marked-terminal":"^7.3.0","socket.io-client":"^4.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","esbuild":"^0.25.0","@types/ws":"^8.18.1","cross-env":"^7.0.3","typescript":"^5.9.3","@types/node":"^22.0.0","drizzle-kit":"^0.31.0","@types/express":"^4.17.0","@types/better-sqlite3":"^7.6.0","@types/marked-terminal":"^6.1.1"},"_npmOperationalInternal":{"tmp":"tmp/huko_0.3.0_1779073301819_0.7018273441176983","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@alexzhaosheng/huko","version":"0.4.0","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"author":{"name":"alexzhaosheng"},"license":"MIT","_id":"@alexzhaosheng/huko@0.4.0","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"bin":{"huko":"bin/huko.mjs"},"dist":{"shasum":"f3005c31d295c70e2904e605c0701c5110da47a0","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.4.0.tgz","fileCount":5,"integrity":"sha512-HBpga4D6cldEJC2pB6O5hS9teF0p19XDuXnQUK7he8pnFIO64cfugi+X37brJ3kTSMrY9yQYT2+1qyBN+O1mEg==","signatures":[{"sig":"MEYCIQDw4uiRqaZRpx0r3X12SSDM0AMohSuWpjkAXrdiZXoJBgIhAPe8G0Wy02nrDm5OyvJraF4b34ExMEE/egJ/wQoqmtPT","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":711447},"pnpm":{"onlyBuiltDependencies":["better-sqlite3","esbuild"]},"type":"module","engines":{"node":"24.x"},"gitHead":"d356c14c864a730702a9e5cf9b38bf2c5e7c7086","scripts":{"huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","build":"pnpm run build:cli && pnpm run build:web","check":"tsc --noEmit","build:cli":"node scripts/build-cli.mjs","build:web":"pnpm --filter @huko/web build","check:web":"pnpm --filter @huko/web typecheck","db:migrate":"tsx scripts/db-migrate.ts","prepublishOnly":"pnpm run check && pnpm run check:web && pnpm run build"},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"repository":{"url":"git+https://github.com/alexzhaosheng/huko.git","type":"git"},"_npmVersion":"11.12.1","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"ws":"^8.20.1","zod":"^4.0.0","dotenv":"^16.0.0","marked":"^15.0.12","nanoid":"^5.0.0","express":"^4.21.0","socket.io":"^4.8.0","iconv-lite":"^0.6.3","drizzle-orm":"^0.44.0","@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","marked-terminal":"^7.3.0","socket.io-client":"^4.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","esbuild":"^0.25.0","@types/ws":"^8.18.1","cross-env":"^7.0.3","supertest":"^7.2.2","typescript":"^5.9.3","@types/node":"^22.0.0","drizzle-kit":"^0.31.0","@types/express":"^4.17.0","@types/supertest":"^7.2.0","@types/better-sqlite3":"^7.6.0","@types/marked-terminal":"^6.1.1"},"_npmOperationalInternal":{"tmp":"tmp/huko_0.4.0_1779353582960_0.9649995122743964","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@alexzhaosheng/huko","version":"0.5.0","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"author":{"name":"alexzhaosheng"},"license":"MIT","_id":"@alexzhaosheng/huko@0.5.0","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"bin":{"huko":"bin/huko.mjs"},"dist":{"shasum":"2fe459beb8d4d3df2b4627fac1e407e9ba2596c7","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.5.0.tgz","fileCount":9,"integrity":"sha512-4VpBnPSh6mowUHesWtuaADPrh2DFbPBhuXBI5z3WBw9iVm56dWZYC3vY/tNytEAcOu2KvCFfeUDkqMBWHsjNIw==","signatures":[{"sig":"MEUCIQCAC/yCm23jj+ZHrP6uSWsedXOlN6y+0tl35mRvN52pOAIgYiyCt64WXz+Ux64s8qvfZoM+xAMDoeeinzG8AJ5sfYc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":3346872},"pnpm":{"onlyBuiltDependencies":["better-sqlite3","esbuild"]},"type":"module","engines":{"node":"24.x"},"gitHead":"19408d803bd798084ab910f0de905ab38494b043","scripts":{"huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","build":"pnpm run build:cli && pnpm run build:web","check":"tsc --noEmit","build:cli":"node scripts/build-cli.mjs","build:web":"pnpm --filter @huko/web build","check:web":"pnpm --filter @huko/web typecheck","db:migrate":"tsx scripts/db-migrate.ts","prepublishOnly":"pnpm run check && pnpm run check:web && pnpm run build"},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"repository":{"url":"git+https://github.com/alexzhaosheng/huko.git","type":"git"},"_npmVersion":"11.12.1","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"ws":"^8.20.1","zod":"^4.0.0","croner":"^10.0.1","dotenv":"^16.0.0","marked":"^15.0.12","nanoid":"^5.0.0","express":"^4.21.0","socket.io":"^4.8.0","iconv-lite":"^0.6.3","drizzle-orm":"^0.44.0","@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","marked-terminal":"^7.3.0","socket.io-client":"^4.8.0"},"_hasShrinkwrap":false,"devDependencies":{"tsx":"^4.0.0","esbuild":"^0.25.0","@types/ws":"^8.18.1","cross-env":"^7.0.3","supertest":"^7.2.2","typescript":"^5.9.3","@types/node":"^22.0.0","drizzle-kit":"^0.31.0","@types/express":"^4.17.0","@types/supertest":"^7.2.0","@types/better-sqlite3":"^7.6.0","@types/marked-terminal":"^6.1.1"},"_npmOperationalInternal":{"tmp":"tmp/huko_0.5.0_1779502182009_0.1731359458235835","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@alexzhaosheng/huko","version":"0.5.1","description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"homepage":"https://github.com/alexzhaosheng/huko#readme","bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"repository":{"type":"git","url":"git+https://github.com/alexzhaosheng/huko.git"},"license":"MIT","author":{"name":"alexzhaosheng"},"type":"module","engines":{"node":"24.x"},"bin":{"huko":"bin/huko.mjs"},"scripts":{"build:cli":"node scripts/build-cli.mjs","build:web":"pnpm --filter @huko/web build","build":"pnpm run build:cli && pnpm run build:web","check":"tsc --noEmit","check:web":"pnpm --filter @huko/web typecheck","db:migrate":"tsx scripts/db-migrate.ts","huko":"tsx server/cli/index.ts","test":"node --import tsx --test \"tests/*.test.ts\"","prepublishOnly":"pnpm run check && pnpm run check:web && pnpm run build"},"dependencies":{"@trpc/client":"^11.0.0","@trpc/server":"^11.0.0","better-sqlite3":"^12.0.0","croner":"^10.0.1","dotenv":"^16.0.0","drizzle-orm":"^0.44.0","express":"^4.21.0","iconv-lite":"^0.6.3","marked":"^15.0.12","marked-terminal":"^7.3.0","nanoid":"^5.0.0","socket.io":"^4.8.0","socket.io-client":"^4.8.0","ws":"^8.20.1","zod":"^4.0.0"},"pnpm":{"onlyBuiltDependencies":["better-sqlite3","esbuild"]},"devDependencies":{"@types/better-sqlite3":"^7.6.0","@types/express":"^4.17.0","@types/marked-terminal":"^6.1.1","@types/node":"^22.0.0","@types/supertest":"^7.2.0","@types/ws":"^8.18.1","cross-env":"^7.0.3","drizzle-kit":"^0.31.0","esbuild":"^0.25.0","supertest":"^7.2.2","tsx":"^4.0.0","typescript":"^5.9.3"},"gitHead":"9d8f565866eccd823ce9f6730fd3231b69e67a10","_id":"@alexzhaosheng/huko@0.5.1","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-KG97j54c5KbFsdN1cdpbLyk+ujKvEEfhc29aT08FF1ZcOkpTf9CXxcWya16x+0jAQSZl53Mb0wEMhmD5K+ycgw==","shasum":"90ed93707d65a2057162563f15e1e3d207ee3a16","tarball":"https://registry.npmjs.org/@alexzhaosheng/huko/-/huko-0.5.1.tgz","fileCount":24,"unpackedSize":3422726,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexzhaosheng%2fhuko@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCPOyRXrXYNIv5jKdU7KJzkGr5YW5bbOqQEiGUMBlxt4QIhAL0AQtD+F+wbwR/XB9AEHePF2Z1ZOeLC4lb0tomsw5O0"}]},"_npmUser":{"name":"alexzhaosheng","email":"woodheadz@gmail.com"},"directories":{},"maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/huko_0.5.1_1779508619405_0.7940720843934939"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-12T10:16:15.533Z","modified":"2026-05-23T03:56:59.908Z","0.1.0":"2026-05-12T10:16:15.922Z","0.2.0":"2026-05-13T01:32:59.358Z","0.2.1":"2026-05-13T03:21:29.952Z","0.2.4":"2026-05-14T23:26:49.410Z","0.3.0":"2026-05-18T03:01:42.002Z","0.4.0":"2026-05-21T08:53:03.117Z","0.5.0":"2026-05-23T02:09:42.277Z","0.5.1":"2026-05-23T03:56:59.580Z"},"bugs":{"url":"https://github.com/alexzhaosheng/huko/issues"},"author":{"name":"alexzhaosheng"},"license":"MIT","homepage":"https://github.com/alexzhaosheng/huko#readme","keywords":["ai","agent","cli","llm","claude","openai","anthropic","deepseek"],"repository":{"type":"git","url":"git+https://github.com/alexzhaosheng/huko.git"},"description":"An explicit, scriptable AI agent for the command line. Pipe data in, get the answer out.","maintainers":[{"name":"alexzhaosheng","email":"woodheadz@gmail.com"}],"readme":"# huko\n\n> A project-scoped AI agent for the command line — end-to-end task planning, tool use, and code-reading built in.\n\n`huko` is not a prompt utility. Give it a *goal* — *\"find why the /api/users endpoint started returning 500\"*, *\"add Google OAuth following the existing auth patterns\"*, *\"audit deps for known CVEs\"* — and the agent drives the loop: planning next steps, reading your project's code, running shell, calling tools, deciding when the work is actually done. Multiple turns happen inside one invocation, automatically.\n\n**You pick how much memory the agent gets.** Five presets — `--compact=concise|standard|extended|large|max` — set an *absolute conversation budget* (32K / 64K / 128K / 256K / full window). The same level means the same recall whether you're on a 200K Claude or a 1M GPT-5.5. Compaction is pure-algorithmic — no extra LLM call, no summary tokens billed.\n\nState (`sessions`, agent history, `keys`) lives in your project's `.huko/` like `.git`; optional Docker sandbox; per-tool safety policy; multi-provider.\n\n```bash\n# Install\nnpm install -g @alexzhaosheng/huko\n\n# Configure: a chat-based setup where you describe the project and\n# huko picks the right defaults (compaction, safety, features…) for you.\n# First-run? It falls back to a Q&A wizard for provider + key + model.\nhuko setup\n\n# Use\nhuko -- \"the /api/users endpoint is returning 500 — read the handler, follow the imports, find the root cause\"\nhuko -- \"add Google OAuth to the login flow, follow the existing auth patterns in src/auth/\"\ncat logs/recent.log | huko -- \"are these errors caused by my recent commits? check git history and tell me which commit\"\nhuko docker run -- \"audit dependencies for unmaintained packages and known CVEs\"   # sandboxed\n```\n\n---\n\n## Why huko\n\n- **Agent loop, not prompt+reply.** Give huko a goal and the model drives — reads your code, runs shell, plans next steps, calls tools, decides when it's done. \"Fix this bug\" instead of \"tell me about this bug\". Multi-turn happens inside one invocation, automatically; the framework manages context-window compaction, orphan recovery, and the task lifecycle so you don't have to wire any of it.\n- **Project as context.** State (`sessions`, `keys`, `config`) lives in `<cwd>/.huko/` like `.git`. CD into a repo and huko has its memory; CD out and you're in a different world. The agent reads files relative to that cwd, edits within it, and never reaches into a sibling project unless you point it there.\n- **Provider-agnostic.** Anthropic / OpenAI / DeepSeek / Zhipu / MiniMax / OpenRouter / Moonshot / your own gateway. Switch with `huko provider current <name>` or `huko model current <id>`.\n- **Sandboxable.** `huko docker run -- \"...\"` runs the agent in a container with your project mounted at `/work`. Filesystem isolation by default; pipes still work.\n- **Tool-level safety.** Per-tool `disable` / `deny` / `allow` / `requireConfirm` rules. Disabled tools disappear from the LLM's surface entirely — it can't call what it can't see. Per-project by default; layered with global.\n- **Three-layer redaction.** Built-in regex scrubs OpenAI / Anthropic / GitHub / AWS / PEM / JWT shapes from every outbound message; a global vault registers exact strings (`huko vault add github-token`) that never leave the machine; auto-allocated placeholders work BOTH ways — the LLM uses `[REDACTED:foo]` symbolically in tool calls and we expand to the real value before execution.\n- **Explicit configuration.** Layered: built-in → `~/.huko/` → `<cwd>/.huko/`. Every value `huko config show` reports its layer of origin.\n- **Two modes.** `full` for production-grade agent work (planning, ~13 tools, project context). `lean` for one-shot questions (~85% smaller per-call overhead — the loop still runs, just with one tool and a minimal system prompt).\n- **Compaction levels.** Five presets (`concise` / `standard` / `extended` / `large` / `max`) pick how much conversation huko keeps before it summarises and drops the older turns. Same level → same conversation budget across models (target tokens are absolute, clamped to 95% of the model window). One-shot `huko --compact=extended -- \"...\"`; persist with `huko config set compaction.level extended`.\n- **Pipes work, when you want them.** `cat data | huko -- \"...\"` combines: stdin is data, argv is the instruction. Good for ad-hoc workflows where the agent should ingest pipe content as its starting input — but pipe-friendliness is a convenience here, not the product.\n\n---\n\n## Install\n\n### npm\n\n```bash\nnpm install -g @alexzhaosheng/huko\nhuko --version   # confirm install — output includes commit + build date\nhuko --help\n```\n\nRequires Node.js 24+.\n\n### Docker\n\n```bash\ndocker pull ghcr.io/alexzhaosheng/huko:latest\nhuko docker run -- \"fix the bug in main.ts\"\n```\n\nThe `huko docker run` wrapper auto-mounts `$PWD` and `~/.huko`, forwards your shell's API-key env vars, and hands the rest of the argv to the inner huko. Full convention in [`docs/docker.md`](docs/docker.md).\n\n---\n\n## Quick start\n\n```bash\n# 1. Tell huko what kind of project you're working on — it picks the right defaults.\nhuko setup\n\n# 2. Run something.\nhuko -- \"summarise what changed in this branch since main\"\n\n# 3. Talk back and forth.\nhuko --chat\n```\n\nThat's the full happy path. Everything else is variations on the same shape.\n\n---\n\n## Setup, your way (the chat-based configurator)\n\n`huko setup` drops you into a short conversation with the agent. Tell it **what kind of project this is** — *\"coding in this TS repo\"*, *\"running maintenance scripts in CI\"*, *\"long REPL for data exploration\"* — and it picks sensible defaults across the knobs that actually matter: compaction level, safety policy, recommended features. It then proposes them in plain language and applies after you confirm.\n\nThree ways to begin (you'll see them as a banner the moment you run `huko setup`):\n\n```\nhuko setup — agent mode (memory session, nothing persists)\n\nThree ways to start. Say whichever sounds right:\n\n  1. Describe what you'll use huko for\n     e.g. \"coding in this TS repo\", \"data analysis with Python\",\n          \"running maintenance scripts in CI\"\n     → I'll propose sensible defaults (compaction, safety, features)\n       and confirm before applying.\n\n  2. State a specific goal\n     e.g. \"switch to OpenAI gpt-5\", \"block rm -rf for safety\",\n          \"set up a morning git digest schedule\"\n\n  3. Ask about current state\n     e.g. \"what's configured?\", \"where's my API key resolved from?\",\n          \"is the daemon running?\"\n```\n\nWhy path 1 (use-case description) is the recommended default: **compaction level alone makes a big difference**, and the right choice depends on what you'll actually do. The agent picks for you:\n\n| You said you'll use huko for… | huko picks `compaction.level` | Why |\n|---|---|---|\n| Coding / refactoring / multi-file changes | `large` (256K) | Files + plan + tool results all need to stay in scope |\n| Long REPL / deep exploration | `max` (95% of model window) | Use everything the model offers |\n| Maintenance / one-off scripts / CI | `standard` (64K) | Tasks complete quickly; bigger budget wastes prefill tokens |\n| Quick triage / light queries | `concise` (32K) | Aggressive compaction is fine; turns are short |\n\nThe agent also folds in use-case-driven recommendations beyond compaction: safety tripwires (`safety deny bash 're:^rm -rf'`) for CI / unattended runs, `huko vault add` for credential redaction in scripts, `huko skills` for projects with coding conventions, and so on. Nothing is applied without your confirmation.\n\n**First-time setup**: if no provider + model + key is configured yet, `huko setup` automatically falls back to the classic Q&A wizard (pick a provider → supply a key → pick a default model). The chat configurator kicks in afterwards on subsequent `huko setup` runs.\n\n**Skip the chat**: `huko setup --no-chat` forces the classic wizard. Use this when saved config looks present but is actually broken (expired key, dead provider URL) — chat mode would boot up and immediately fail at the first LLM call.\n\nThe setup session is a memory session — nothing about the conversation persists on disk. Your configuration changes (provider, keys, safety rules, etc.) are persistent; the conversation that led to them is not.\n\n---\n\n## Patterns\n\n### Pipe data in, get the answer out\n\n```bash\ncat logs/recent.log | huko -- \"are these errors caused by my recent commits? check git and find culprits\"\ngit diff            | huko -- \"review for risky changes — read the affected files for context if needed\"\nss -tulpn           | huko --json -- \"list open ports as JSON\" > ports.json\necho \"say hi\"       | huko                    # stdin alone is the prompt (lean-style usage)\nhuko < prompt.txt                             # file redirect works the same\n```\n\nWhen stdin is piped AND argv has a prompt, they combine: stdin is treated as input data, argv as the instruction. Mirrors how `grep`/`jq`/`awk` feel.\n\n### Sessions\n\n```bash\nhuko sessions list                           # all chats in this project\nhuko sessions current                        # the active one\nhuko sessions switch 7                       # rejoin chat #7\nhuko --new -- \"start a fresh thread\"         # new session, becomes active\nhuko --new --title=\"auth-refactor\" -- \"...\"  # name it on creation\nhuko --session=7 -- \"follow-up question\"     # one-shot send into session 7\nhuko --memory -- \"one-off, leaves no trace\"  # ephemeral, no on-disk state\nhuko --chat                                  # interactive REPL\n```\n\nShort flags for the high-frequency ones: `-n` = `--new`, `-m` = `--memory`, `-c` = `--chat`. (No POSIX bundling — write them separately: `huko -n -m -- \"...\"`.)\n\n`--no-markdown` (`--no-md`) skips terminal markdown rendering — useful when the LLM output contains literal `*` or `|` that the renderer would misinterpret (shell globs, regex patterns).\n\n### Output formats\n\n```bash\nhuko -- \"...\"           # default text (assistant answer to stdout, diag to stderr)\nhuko --json -- \"...\"    # one JSON document at task end\nhuko --jsonl -- \"...\"   # streaming events line-delimited\nhuko --format=json -- \"...\"   # same as --json (when you want to make the mode explicit)\n```\n\nVerbosity + diagnostics:\n\n```bash\nhuko -v -- \"...\"         # --verbose: print every event the kernel emits\nhuko --quiet -- \"...\"    # the inverse — final answer only, drop progress diag\nhuko --show-tokens -- \"...\"   # append a token / cost summary line to stderr\n```\n\n### Scripting / non-interactive\n\n```bash\nhuko -y -- \"...\"                  # --no-interaction: agent CANNOT call message(type=ask);\n                                  # ideal for cron, CI, and any pipe where no human\n                                  # is at the keyboard\nhuko -y --json -- \"...\" > out.json\n```\n\n`-y` strips the `ask` enum from the `message` tool's schema entirely (the LLM literally can't request input). For tasks that genuinely need an answer, the agent must surface the question via `message(type=result)` instead.\n\n### Provider / model / key management\n\n```bash\nhuko provider list\nhuko model list\nhuko model show deepseek/deepseek-v4-pro     # full record + effective context window + source\nhuko model update deepseek/deepseek-v4-pro --context-window=128000\n                                             # pin the budget when your gateway's real limit\n                                             # differs from the heuristic\nhuko keys list                               # shows source layer per ref\nhuko keys set deepseek                       # hidden prompt → writes <cwd>/.huko/keys.json (chmod 600)\nhuko model current anthropic/claude-sonnet-4-6\nhuko --lean -- \"single-shot, minimal overhead\"\nhuko --compact=extended -- \"big refactor — keep more history before compacting\"\n```\n\n### Docker (sandboxed runs)\n\n```bash\nhuko docker run -- \"audit deps for CVEs\"\ncat config.yaml | huko docker run -- \"is this safe for production?\"\nhuko docker run --image myorg/huko-fork:dev -- \"...\"   # custom image\n```\n\nThe container has filesystem isolation (only `$PWD` + `~/.huko` are mounted) but full network egress by default. See [`docs/docker.md`](docs/docker.md) for the precise security model.\n\n### Safety (tool-level controls)\n\n```bash\nhuko safety tool                              # list every tool + status + rule counts\nhuko safety disable web_fetch                 # remove from LLM surface entirely\nhuko safety enable web_fetch                  # put it back\nhuko safety deny bash 're:^rm -rf'            # block matching calls\nhuko safety allow bash '^ls '                 # auto-approve matching calls\nhuko safety require write_file 're:/etc/'    # prompt operator before matching calls\nhuko safety unset bash 'rm -rf'               # remove a single pattern\nhuko safety unset bash                        # wipe the whole entry\nhuko safety list                              # full pattern dump per tool\nhuko safety check bash command='rm -rf /'     # dry-run a hypothetical call\n```\n\nEditing verbs default to **project** (`<cwd>/.huko/config.json`); pass `--global` for `~/.huko/config.json`. `disabled` is stronger than `deny` — the LLM never sees the tool's name or schema, so it can't try to call it.\n\n### Vault (per-string redaction)\n\n```bash\nhuko vault add github-token                   # hidden prompt for the value\nhuko vault add prod-db-pw --value 'p@ssw0rd!' # direct (scripting only — leaks to history)\nhuko vault list                               # names + lengths (NEVER values)\nhuko vault remove old-token                   # unregister\necho \"my password is p@ssw0rd!\" | huko vault test   # debug: see what gets redacted\n```\n\nThree-layer redaction every outbound message goes through:\n\n1. **Built-in regex** (always on) — known shapes like `sk-...`, `ghp_...`, `AKIA...`, PEM private keys, JWTs.\n2. **`safety.redactPatterns`** (project / global config) — your own regex for environment-specific secret shapes.\n3. **Vault** (`~/.huko/vault.json`, chmod 600) — exact strings you registered. **Round-trips**: when the LLM emits a tool call referencing a placeholder, huko expands it back to the real value before the tool runs — the LLM never sees raw, but can still USE the secret symbolically.\n\nStorage is global only; project-specific redactions belong in regex (Layer 2). For real isolation use `huko docker run` to sandbox the whole agent.\n\n---\n\n## Compaction levels — pick how much memory the agent gets\n\nEvery long agent run eventually fills the context window. huko's compactor watches the conversation token count and, when it crosses a configurable budget, summarises the older turns into a structured digest and drops the original bulk. This is **pure algorithmic compression** — no LLM call, no extra tokens spent on summarisation (see [`docs/architecture.md`](docs/architecture.md) for the digest format).\n\nThe trigger budget is exposed as **five presets** plus a literal `max`, all targeting **absolute token counts** so a level means the same conversation length regardless of which model is running:\n\n| Level | Target tokens | Behaviour |\n|---|---|---|\n| `concise` | 32k | Aggressive — quick tasks, small context |\n| `standard` *(default)* | 64k | Sensible middle ground |\n| `extended` | 128k | Bigger tasks, more recall |\n| `large` | 256k | Long sessions; clamps to 95% on smaller-window models |\n| `max` | 95% of model window | Use everything the model offers (≈ 190K on Claude Sonnet, ≈ 950K on Opus-1M / GPT-5.5) |\n\n**Coding work? Use `--compact=large` by default.** Reading source, following imports, applying multi-file edits all chew through context fast — `large` (256K target) gives the agent enough room to keep file content, plan state, and recent tool results all in scope at once. Drop to `standard` for chat-style questions; reach for `max` only when you're explicitly working on something that needs the full window (large refactors, long-running REPLs).\n\n```bash\n# One-shot — coding tasks default to large\nhuko --compact=large -- \"refactor server/auth/ following the existing module patterns\"\nhuko --chat --compact=max                                   # long REPL: use everything\n\n# Persistent\nhuko config set compaction.level large --project           # this project (good default for code repos)\nhuko config set compaction.level standard                  # globally\n```\n\nFor the rare case where a preset doesn't fit, the raw ratio escape hatch still works:\n\n```bash\nhuko --compact-threshold=0.4 -- ...      # custom: triggers at 40% of window\n```\n\nSetting `--compact-threshold` (or `config.compaction.thresholdRatio`) overrides any preset and the effective display flips to `custom`. Inspect the live setting with `huko info` (under `Compaction:`) — it shows the active level, the resolved threshold/target percentages, and the absolute token budget on the current model.\n\n---\n\n## Browser Control\n\nAn opt-in feature that lets the agent operate your real Chrome browser through a lightweight extension. All cookies, logins, and sessions are live — the agent sees and interacts with exactly what you see.\n\n### Quick start\n\n```bash\n# 1. Load the extension (one-time setup)\nhuko extension         # prints the install path + the two-click steps\n#    → open chrome://extensions, toggle \"Developer mode\",\n#    → click \"Load unpacked\" and pick the path huko printed\n\n# 2. Enable browser-control in chat mode\nhuko --chat --enable=browser-control\n```\n\nThe extension icon shows connection status: red = disconnected, green = connected.\n\n### How it works\n\nWhen browser-control is enabled in chat mode, huko starts a local WebSocket server (default port 19222). The Chrome extension connects to this server and executes commands in the user's real browsing environment. When chat mode exits, the server stops and the extension disconnects.\n\n### Configuration\n\nBrowser-control parameters live under `tools.browser` in huko's layered config. Inspect or change them with `huko config`:\n\n| Parameter | Default | Description |\n|---|---|---|\n| `tools.browser.wsPort` | `19222` | WebSocket port for the Chrome extension to connect to |\n| `tools.browser.defaultTimeoutMs` | `30000` | Per-action timeout in milliseconds |\n| `tools.browser.maxScreenshotBytes` | `5242880` | Maximum screenshot image size in bytes (5 MiB) |\n\n```bash\n# Change the port for this project (e.g. port conflict)\nhuko config set tools.browser.wsPort 19224 --project\n\n# Increase screenshot size limit\nhuko config set tools.browser.maxScreenshotBytes 10485760 --project\n\n# Inspect current values\nhuko config show\n```\n\n### Limitations\n\n- **Chat mode only.** One-shot runs (`huko -- prompt`) never start sidecars — browser commands will fail with a clear \"server not running\" error.\n- **Single client.** Only one Chrome extension can connect at a time.\n- **Local only.** The WebSocket server binds to `127.0.0.1` — no remote browser control.\n\n### Actions\n\nThe `browser` tool surfaces these actions to the LLM:\n\n- `navigate` — open a URL in a new tab, return visible page text\n- `click` — click the first element matching a CSS selector\n- `type` — type text into an input matching a CSS selector\n- `scroll` — scroll the active page (up / down / top / bottom)\n- `get_text` — return visible text content of the active page\n- `get_html` — return full HTML source of the active page\n- `screenshot` — capture a PNG screenshot\n- `wait` — wait for a selector to appear or a plain timeout\n- `list_pages` — list all open tabs (URL + title)\n- `switch_page` — switch the active tab by index\n\n---\n\n## Skills\n\nSkills are operator-authored markdown files that get spliced into the system prompt when activated — recipes, project conventions, deploy procedures, anything you'd otherwise re-type at the top of every chat. They are **off by default**: dropping a file in the skills directory has no effect until you explicitly turn it on.\n\nDistinct from the planner's per-phase capability tagging (`roles/`, model-driven): skills are operator-driven and stay active for the whole session.\n\n### Authoring\n\nTwo layouts work, both recognised by file/folder name as the skill's identity:\n\n```\n~/.huko/skills/<name>.md             # global, single file\n~/.huko/skills/<name>/SKILL.md       # global, folder-style (supporting assets fine)\n<cwd>/.huko/skills/<name>.md         # project, same shapes — wins over global\n<cwd>/.huko/skills/<name>/SKILL.md\n```\n\nFront matter holds a one-line `description` (shown in `huko skills list` and rendered above the body in the system prompt). Any other YAML keys are silently ignored so files written for other agent tools drop in unchanged.\n\n```markdown\n---\ndescription: Pre-deploy checklist + rollback for this service\n---\n\nWhen the user asks to deploy:\n1. Run `pnpm test` and abort on any failure.\n2. Tag the release as `v<semver>`.\n3. ...\n```\n\n### Activating\n\nTwo paths — both stack additively:\n\n```bash\n# Persistent (per project or globally)\nhuko config set skills.deploy.enabled true --project\nhuko config set skills.deploy.enabled true            # global\n\n# One-shot (this invocation only; repeatable)\nhuko --skill=deploy --skill=git-workflow -- \"ship 0.3.0\"\nhuko --chat --skill=deploy\n```\n\nA typo in `--skill=foo` aborts at bootstrap with the list of searched paths. A skill listed as `enabled: true` in config but missing on disk warns and is skipped — config drift can't brick startup.\n\n### Discovery\n\n```bash\nhuko skills list\n# NAME    SOURCE   ACTIVE  DESCRIPTION\n# deploy  project  yes     Pre-deploy checklist + rollback for this service\n# triage  user     no      Bug-triage workflow with reproduction template\n```\n\nProject files shadow global files of the same name (matches the rest of the layered-config story).\n\nWhen any skill is active, the chat banner ends with `skills: deploy, triage`, and one-shot runs print `huko: skills active — deploy, triage` to stderr before the LLM call. No surprise activations.\n\n---\n\n## Web UI (daemon mode)\n\n`huko daemon start` brings up a long-running HTTP + WebSocket server for the current project and prints a `http://localhost:<port>` URL. Open it in a browser, paste the token printed at startup, and you get the same agent loop the CLI drives — message stream, tool calls, ask/decision dialogs — in a React console.\n\n```bash\n# Start the daemon for this project\ncd ~/my-project\nhuko daemon start\n# huko daemon — running\n#   Name:   my-project\n#   URL:    http://127.0.0.1:3000\n#   PID:    12345\n#   Token:  d8e9f0...   (also at ~/.huko/daemon-token.json, chmod 600)\n\n# Set a custom project name (persisted to <.huko/project-name>)\nhuko --name=\"My Project\" daemon start\n# huko daemon — running\n#   Name:   My Project\n#   URL:    http://127.0.0.1:3000\n#   PID:    12346\n#   Token:  d8e9f0...\n\n# The name shows in `daemon list` and the web UI header\nhuko daemon list\n# huko daemon — 2 running\n#   my-project   ~/my-project   http://127.0.0.1:3000  pid 12345  uptime 12m\n#   My Project   ~/other-proj   http://127.0.0.1:3001  pid 12346  uptime 1m\n\n# Multi-project workflow\ncd ~/other-project && huko daemon start    # auto-allocates next free port (e.g. 3001)\nhuko daemon stop --all                      # batch stop\n\n# Stop / restart preserves the URL\nhuko daemon stop && huko daemon start\n# always lands on the same port; the assignment lives at <cwd>/.huko/daemon-port\n```\n\n| Subcommand | What |\n|---|---|\n| `huko daemon start` | Detached background process. Auto port on first start, fails loud if the persisted port is later taken by something else. |\n| `huko daemon stop [--all]` | SIGTERM + 5s grace + SIGKILL. `--all` walks the registry. |\n| `huko daemon status` | URL, PID, uptime, token for this project. |\n| `huko daemon token` | Print the user-scoped token to stdout (exit 1 if none). |\n| `huko daemon list` | All running daemons on this machine, dead-pid filter on read. |\n\n**Threat model**: single Bearer token (256-bit, chmod 600, constant-time compare), localhost-only by default, no TLS. Same-user dev-machine scope. For remote access use an SSH tunnel (`ssh -L 3000:localhost:3000 host`); for LAN exposure set `daemon.host = 0.0.0.0` and put Caddy / nginx in front for TLS. See [docs/modules/daemon.md](docs/modules/daemon.md) for the full design.\n\n---\n\n## Scheduled tasks\n\nWhen the daemon is running, you can hand it a cron expression + a prompt and let it drive the agent on a schedule. Each schedule lives in **one Markdown file** under `<cwd>/.huko/schedules/`, gets its own long-lived session, and every fire becomes a new task in that session — the full history is browsable in the web UI's **Schedules** tab.\n\n```bash\nmkdir -p .huko/schedules\ncat > .huko/schedules/morning-brief.md << 'EOF'\n---\ncron: \"0 8 * * *\"\ntimezone: \"Asia/Shanghai\"\n---\n\nEach morning: run `git log --since=\"24 hours ago\" develop`, group the\ncommits into feat / fix / chore, and deliver the markdown digest via\nmessage(type=result).\nEOF\n\nhuko daemon restart                  # picks up new / edited schedules\n\nhuko schedule list                   # what's loaded + next-fire times\nhuko schedule run morning-brief      # fire it once now (via the daemon)\nhuko schedule disable morning-brief  # frontmatter flip; restart to land\n```\n\nThe body of the file is the agent's *standing duty* — it lands in a cache-stable `<scheduled_task>` system-prompt block, while the wall-clock trigger time and the **previous run's `finalResult`** go in the trigger user message for cross-fire continuity. Scheduled tasks always run non-interactive (no `message(type=ask)`); concurrency is **skip-if-running** per schedule.\n\nFull design + frontmatter reference + a step-by-step tutorial: [`docs/modules/scheduler.md`](docs/modules/scheduler.md).\n\n---\n\n## Configuration\n\nLayered, just like `git config`:\n\n```\nbuilt-in defaults  →  ~/.huko/{providers,config,keys}.json  →  <cwd>/.huko/{...}.json\n```\n\nInspect:\n```bash\nhuko info             # everything that's resolved + which layer set what\nhuko config show      # the runtime config side\n```\n\nEdit through the CLI:\n```bash\nhuko config set mode lean --project          # this project only\nhuko config set mode lean --global           # all projects\nhuko safety init                             # scaffold per-tool safety rules (project)\nhuko safety disable web_fetch                # see Safety section above\n```\n\nOr just edit the JSON files directly — huko reads them on every run, no caching.\n\n---\n\n## Local LLMs\n\nhuko speaks OpenAI-compatible HTTP, so any local server that does — **Ollama**, **LM Studio**, **vLLM**, **llama.cpp's `llama-server`**, **LocalAI**, **text-generation-webui** — registers the same way as a hosted provider. Below uses Ollama; the others differ only in `--base-url`.\n\n```bash\n# 1. Start the local server + pull a model.\nollama serve &\nollama pull qwen2.5-coder:7b\n\n# 2. Register a key reference. Most local servers ignore the value but\n#    expect SOME string in the Authorization header — pick any placeholder.\nhuko keys set ollama          # interactive (hidden prompt) — type 'EMPTY' or anything\n\n# 3. Register the provider. Protocol is `openai` (= OpenAI-compatible API).\nhuko provider add \\\n  --name=ollama \\\n  --protocol=openai \\\n  --base-url=http://127.0.0.1:11434/v1 \\\n  --api-key-ref=ollama\n\n# 4. Register the model under that provider; make it current.\nhuko model add \\\n  --provider=ollama \\\n  --model-id=qwen2.5-coder:7b \\\n  --context-window=32768 \\\n  --tool-call-mode=native \\\n  --current\n\n# 5. Use it.\nhuko -- \"read main.ts and explain the architecture\"\n```\n\n**Notes:**\n\n- `--context-window=` is required for local models — huko sizes compaction thresholds against it. Grab the right number from the model card or `ollama show <model>` (look for `context length`).\n- `--tool-call-mode=native` works when the model + server both implement OpenAI function calling (Qwen 2.5, Llama 3.1, DeepSeek family, recent Ollama). If you see empty / ignored tool calls in responses, switch to `--tool-call-mode=xml` — huko will encode tool calls inside the prompt and parse them from the model's text reply. Slower and a bit less reliable, but works with any model that can follow instructions.\n- Other servers' default ports: **LM Studio** `http://127.0.0.1:1234/v1`, **vLLM** `http://127.0.0.1:8000/v1`, **llama.cpp `llama-server`** `http://127.0.0.1:8080/v1`. All keep `--protocol=openai`.\n- Custom headers (internal gateway, corporate proxy, etc.) — `--header=X-Foo=bar` on `provider add`, repeatable.\n- Project-scoped registration: pass `--project` on `provider add` / `model add` to write to `<cwd>/.huko/providers.json` instead of the global `~/.huko/providers.json`. Useful when a single project pins to a specific local model the rest of your machine doesn't use.\n\nSmall models (7B-and-below) typically struggle to keep a multi-step agent loop coherent — they hallucinate file paths, forget which tool they just called, or repeat themselves. **Lean mode** (`huko --lean -- \"...\"`) is the right pairing: minimal system prompt, just `bash` as the tool, far less for the model to juggle. For the full agent surface, you'll generally want a 32B+ model or a hosted frontier model.\n\n---\n\n## Documentation\n\n| Topic | File |\n|---|---|\n| CLI surface, argv parsing, all flags | [`docs/modules/cli.md`](docs/modules/cli.md) |\n| Architecture overview | [`docs/architecture.md`](docs/architecture.md) |\n| Configuration model | [`docs/modules/config.md`](docs/modules/config.md) |\n| Per-tool safety policy | run `huko safety init` for the template |\n| Docker convention + key resolution | [`docs/docker.md`](docs/docker.md) |\n| CI/CD pipeline + release process | [`docs/cicd.md`](docs/cicd.md) |\n| Working agreements (for contributors) | [`CLAUDE.md`](CLAUDE.md) |\n\n---\n\n## Development\n\n```bash\ngit clone https://github.com/alexzhaosheng/huko.git\ncd huko\nnpm install\nnpm test                  # full suite, cross-platform (Linux / macOS / Windows × Node 24)\nnpx tsc --noEmit          # strict type check\nnpm run build:cli         # esbuild bundle → dist/cli.js (embeds commit + date)\n\nnpm link                  # install your local checkout as `huko`\n```\n\nOr use the unbuilt source directly via tsx:\n```bash\nnpx tsx server/cli/index.ts -- \"your prompt\"\n```\n\nCI runs the same `tsc + test + build` matrix on Linux/macOS/Windows × Node 24 for every PR. The Dockerfile gets a sanity build on every PR too. See [`docs/cicd.md`](docs/cicd.md) for the full pipeline.\n\n---\n\n## To be implemented\n\nSketches of the next surface, in rough priority order. None of these are committed scope or timeline — the list exists to signal direction, and so the kernel design stays compatible with them.\n\n- **Daemon mode.** A long-lived background process owns one or more sessions; multiple CLI invocations / IDE plugins / web UI consumers all talk to it. Solves \"warm tool state across calls\", multi-client coordination, and idle compaction.\n- **Remote CLI UI.** `huko --host=user@remote-box -- \"...\"` — your local terminal driving a daemon running on a remote machine, so the work happens close to the project (file system, network, secrets) and you don't ship gigabytes of repo over your laptop tether.\n- **Web UI.** Browser front-end for the daemon — for cases where a long context, side-by-side diff, image attachments, or non-terminal users need more than what a CLI gives. Same kernel underneath.\n- **More tools.** Expanding the tool surface — language-server integrations (rename, type-aware refactor), git-operation safety (branch / stash / cherry-pick gated), structured browsing (sitemap-aware crawl, login-required pages), database query introspection.\n\nWant any of these sooner? Open an issue / discussion — priority follows demand.\n\n---\n\n## License\n\nMIT. See [`LICENSE`](LICENSE).\n","readmeFilename":"README.md"}