{"_id":"@backloghq/agentdb","_rev":"14-4fc0d45ebb846b70836c4c07206937f8","name":"@backloghq/agentdb","dist-tags":{"latest":"2.3.0"},"versions":{"1.0.0":{"name":"@backloghq/agentdb","version":"1.0.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.0.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"ea81b3417946458d2b4776e2bc25c2e691ed9d24","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.0.0.tgz","fileCount":63,"integrity":"sha512-gFOdSzLLV3A1UN2h6pRS6GPXf46asrwDfnsSRgjpzN41J0mHFFXYIDZC9LVD/0h0dBQlUY8KQggXjagvPQXw8Q==","signatures":[{"sig":"MEQCIDKiGZPLu3E6pyz8KnrT1iKcqCjxfn2cKn3EyjbthHxvAiASmD0Leyv1RfDqC1DEqAFPjaR33OXIDkep77moBuyB+A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":264275},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"e07e1a69b8c1e98f63c896ab3f9875c1069cb9b8","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.12.1","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","@backloghq/opslog":"^0.5.1","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.1.1"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.0.0_1775828647589_0.9147361969492835","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@backloghq/agentdb","version":"1.1.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.1.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"27b69cb03bd367eef7dd916ed846520bac61f8bf","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.1.0.tgz","fileCount":65,"integrity":"sha512-HyrjR8R7bo/ug0L7p5D/Ufwlmw+uc7koZ6lg/IA4KvdaSZ+wGKxQYzIBXI2mzZgubIRhmqcas3NM7NWteDOvMA==","signatures":[{"sig":"MEQCIDCgnz36M6qsOC1SglcngYAdwB5PhcapSL3cqX+FiFMCAiByQj25cTcJAlBGsl663XDKJ/EjyIpCpvMWFfXXd6iH2Q==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":292593},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"d55a47eaa000c3503106b5badc86c4a9ec2dd7d5","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.12.1","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","@backloghq/opslog":"^0.6.0","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.2.0"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.1.0_1775850229230_0.593918619223553","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@backloghq/agentdb","version":"1.1.1","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.1.1","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"7035891f7f57bfceb957466838323145f4986a12","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.1.1.tgz","fileCount":65,"integrity":"sha512-YUp2g+Jpdrm4lkVwjAjcG++KuRxCORKFPUWnfcPCnWbHYJN0YIlOHFGgbkx1uNPmorr1y2FYmEOt637TLybaUQ==","signatures":[{"sig":"MEQCIAk8ajZD1GxxDDaPsyCy7hsKn51eKDqudGBTAR/cQ/yUAiA8vUxtjs1GOrN2ZZ07IhjiC6l7KE6DnmoFKNq2oX2QIg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":293616},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"08b637c34718a302acf12e81e0fceb7862ebedc7","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.12.1","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","@backloghq/opslog":"^0.6.0","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.2.0"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.1.1_1775905284953_0.7405072482231623","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@backloghq/agentdb","version":"1.2.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.2.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"a7ebca50e5e5bdb46d6a7fd7d53f426d8cd0b75b","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.2.0.tgz","fileCount":75,"integrity":"sha512-/1iFG6f2GHWsMRdCdsH7KRJvDQdxd8nLlLpt02WPjMYEcmg5ypoR1/G16VRrp1R9m9aww75wqCxWOmPGHLEgRA==","signatures":[{"sig":"MEUCIAwqfWQvVrca3Hy/FgLTOnvfjKKyD06DAprjdZfZ4Gy3AiEAwKEMD01OVsaB8uNCn1NDqItIO1wOqpbOBoiCbNnzSnU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":390926},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"fb45022badac6c6a7ca25bc499ccc3fe2d781860","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.12.1","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.0","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.2.0_1775929488132_0.7452200941953475","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@backloghq/agentdb","version":"1.2.1","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.2.1","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"f4d1426bd1f6db4646666da5a676706dea34e2df","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.2.1.tgz","fileCount":75,"integrity":"sha512-PLY9o8B+S+lfTubS3SaHkiJgcfJV85hoSm0Af5YrZ3xUmUF36Vzfb7A3dYdD15KYHYN0zhlL2heOBo97B3wwyg==","signatures":[{"sig":"MEQCIEOjz+7L9wXbwfXYMxKYeB2k2LnSbEpJMdiFn4StcP50AiAT4SocT4vIyN1AARqGHtujVpzoQhTzidaNWFznOwSrjA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":390926},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"29ed57ade2d1b99eef364e825b700e9568671e9c","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.12.1","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.2.1_1775930335006_0.219839680974516","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@backloghq/agentdb","version":"1.3.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.3.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"3c39d4aba4954131c67f97ae0d8d419d4065cd67","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.3.0.tgz","fileCount":93,"integrity":"sha512-TNESFJZ5EvAg68vpvgzglz01lj6bnIKFZwSiiIDPb1htBxy7X/Z58AoY3wDTNMuSyvMvl9FGEV1Sp3UWTL/A4g==","signatures":[{"sig":"MEUCIQDNJ5HzNqHxBNNfcIL39O4qSBnJOfNRDYFDJqVAesz3WQIgeIjjfC5BfL9nhEMTsvWyosCU0lecl9nq45bx6pYrhXU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":497364},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"62cc84f7cfa46e1779ede97afb9971fbe3e06b28","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.12.1","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.3.0_1776542852850_0.509759856371746","host":"s3://npm-registry-packages-npm-production"}},"1.3.1":{"name":"@backloghq/agentdb","version":"1.3.1","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.3.1","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"a93704fd6c20fdf9509ee0528f9eca36b5399650","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.3.1.tgz","fileCount":95,"integrity":"sha512-zeEkx2K2xr3ye8elTPtmNa5pVBzUGj9Ohh4nfeRsY1U/ZrI5TItF2BQhGmHbOjjJaDbSNLlXOSmxOgVIvoQO7A==","signatures":[{"sig":"MEQCID/1ZxjvFORu2aTnhluPObB1h8V/MDM4KbBSKwRi50aqAiA5eKphbLPFQDMLjCd5FSxDrWKfXKpnwCT6MRpdnSlvfg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":515024},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"1e5daa9259f6ee3e43b3dc30f8aa2f14becc18fa","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.13.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.3.1_1777756218784_0.1277775012153206","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@backloghq/agentdb","version":"1.4.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@1.4.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"33847b48b2bb178b97e7c0b1f54709b958e11391","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-1.4.0.tgz","fileCount":97,"integrity":"sha512-NpnqUvyqJqb5508aoZU+i3A8OpvA2mA17Lv+UtyKaDkunStmXrtEWL4eHydKpae4jILw7KEbn5tshsy3DT5bng==","signatures":[{"sig":"MEUCIED7xUCAPKYSqUXjW3uAT3W/o02EFmuh/g6r2FHE7cZbAiEAgag2fCgCsjTR3CJwB8d/cdg5uzokgr9IilIr3DD17Ag=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":575946},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"454a124e83f1d7abb4215600d3e2e44bcc0ecdb0","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"_npmVersion":"11.13.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.0"},"_npmOperationalInternal":{"tmp":"tmp/agentdb_1.4.0_1777885626985_0.37463456970237985","host":"s3://npm-registry-packages-npm-production"}},"2.0.0":{"name":"@backloghq/agentdb","version":"2.0.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@2.0.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"homepage":"https://github.com/backloghq/agentdb#readme","bugs":{"url":"https://github.com/backloghq/agentdb/issues"},"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"8d317a5822e0d2bbd457cd7298e238e8500fef4d","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-2.0.0.tgz","fileCount":185,"integrity":"sha512-yGqzui/lSbuzFw5aZga8o8l1hornyRvgyMQCauKy+sYMVsDzhFRlH+/Xz0JVpwlmZhieNHFI9KLWO9F5eG+uPg==","signatures":[{"sig":"MEUCIQDzBfnKlh2KNyh51PrQ2kiKMbQ+tuL42df2cdYKj2N+BAIgd3s2Hb1OGsB/NIqlm+w/ubT3RDavq/QUsntuCbo/Hnc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1086413},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"98b84e88a40575ed79cad6c7385bc9d25fa4cf35","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"repository":{"url":"git+https://github.com/backloghq/agentdb.git","type":"git"},"_npmVersion":"11.13.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"sideEffects":false,"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@backloghq/termlog":"^0.1.2","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4","@backloghq/termlog-s3":"^0.1.0"},"peerDependencies":{"@backloghq/termlog-s3":"^0.1.0"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.1"},"peerDependenciesMeta":{"@backloghq/termlog-s3":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agentdb_2.0.0_1777989451660_0.4004246238010849","host":"s3://npm-registry-packages-npm-production"}},"2.1.0":{"name":"@backloghq/agentdb","version":"2.1.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@2.1.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"homepage":"https://github.com/backloghq/agentdb#readme","bugs":{"url":"https://github.com/backloghq/agentdb/issues"},"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"f9a4f4bbb2ccfec5a18350f03c9afda8cdc9ab58","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-2.1.0.tgz","fileCount":189,"integrity":"sha512-LdP66impV8DpqibZuE5tjL5bCwV6RgBq1QMKucVZO6pxQvFXn/ox8zlG4/K1b/qcllGJ8KNyaFQOFf2d+kU6ew==","signatures":[{"sig":"MEUCIQCeHbuSltUtGQjq/LqfpFX65ITJQzuvoUJg0Lm+vXuMagIgIBkR2uYwg58T/DyTuoBZfv0rgyzC/wIbUbOqXjkoJ0c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1261111},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"cd32e49f3672518b78144e2d62bd97f19a745b82","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"repository":{"url":"git+https://github.com/backloghq/agentdb.git","type":"git"},"_npmVersion":"11.13.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"sideEffects":false,"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@backloghq/termlog":"^0.1.2","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4","@backloghq/termlog-s3":"^0.1.0"},"peerDependencies":{"@backloghq/termlog-s3":"^0.1.0"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.1"},"peerDependenciesMeta":{"@backloghq/termlog-s3":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agentdb_2.1.0_1778020392687_0.8204424132939498","host":"s3://npm-registry-packages-npm-production"}},"2.1.1":{"name":"@backloghq/agentdb","version":"2.1.1","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@2.1.1","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"homepage":"https://github.com/backloghq/agentdb#readme","bugs":{"url":"https://github.com/backloghq/agentdb/issues"},"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"535e809d2f06a797781b362677ce4319b73d3041","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-2.1.1.tgz","fileCount":189,"integrity":"sha512-5+JMtTmo8XatmsxRGWG1ZT7YecxPYKVk4h9k929O8UF2Ms37uudFVyVUb/jLMW5q+3Ab0kvCPfwCpwCXtyKC/Q==","signatures":[{"sig":"MEQCIHsOQSGLMDP6s8LxmhwY9y6XaNOVCyLp7THaP2LM5jDOAiBTDrWQvK7Qh1WOw3P7KcE7tTpKPCYWmk3X9Bc+RCG7tg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1308190},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"1833902674993a0e73d085e22b8978301635759a","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","bench:leak":"node --expose-gc scripts/bench-leak.mjs","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"repository":{"url":"git+https://github.com/backloghq/agentdb.git","type":"git"},"_npmVersion":"11.13.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"sideEffects":false,"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@backloghq/termlog":"^0.1.2","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4","@backloghq/termlog-s3":"^0.1.0"},"peerDependencies":{"@backloghq/termlog-s3":"^0.1.0"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.1"},"peerDependenciesMeta":{"@backloghq/termlog-s3":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agentdb_2.1.1_1778063291501_0.11906418704935051","host":"s3://npm-registry-packages-npm-production"}},"2.2.0":{"name":"@backloghq/agentdb","version":"2.2.0","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@2.2.0","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"homepage":"https://github.com/backloghq/agentdb#readme","bugs":{"url":"https://github.com/backloghq/agentdb/issues"},"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"ee6f535ae39c37f9864ed620ee150d4092f64490","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-2.2.0.tgz","fileCount":189,"integrity":"sha512-C4puvOK8v0I43d/h1TNPaoZio2ezxgZEL1HyK0rKo8YeLTim2tPYL7G3wut7UZ0k7puV0ZAMcvvUvVje0AEnMA==","signatures":[{"sig":"MEUCIBlebc1DAUsMeqI7H3Sh+w1ALYC1XNepEWl5+flTGRNjAiEAqTPTnh5Ca34EOWwRQDrqLpeN9EnG7rxaeMT931o9JM8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1361217},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"49e1d9e2a9943b53bbdc17027370dd798a554d55","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","bench:leak":"node --expose-gc scripts/bench-leak.mjs","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"repository":{"url":"git+https://github.com/backloghq/agentdb.git","type":"git"},"_npmVersion":"11.13.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"sideEffects":false,"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@backloghq/termlog":"^0.1.2","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4","@backloghq/termlog-s3":"^0.1.0"},"peerDependencies":{"@backloghq/termlog-s3":"^0.1.0"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.1"},"peerDependenciesMeta":{"@backloghq/termlog-s3":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agentdb_2.2.0_1778089263946_0.06912356753637128","host":"s3://npm-registry-packages-npm-production"}},"2.2.1":{"name":"@backloghq/agentdb","version":"2.2.1","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","_id":"@backloghq/agentdb@2.2.1","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"homepage":"https://github.com/backloghq/agentdb#readme","bugs":{"url":"https://github.com/backloghq/agentdb/issues"},"bin":{"agentdb":"dist/mcp/cli.js"},"dist":{"shasum":"89fd75b77d20b2b45cbfeda7028872f94336bf05","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-2.2.1.tgz","fileCount":189,"integrity":"sha512-ADdNAmSO7FxgZq6o34Hs1h5Ry2x9O8pj3spOsBQWwa3LrSH34NjQGO8+INIfH8qQByDhJFk9JCbQfgptNy2q/g==","signatures":[{"sig":"MEUCIBF+S1btxKKUCnT44kvm4gyd3uNwPsUBJFpNRdLjpk8JAiEA0IUxUsPdZInQzAOfy8WPnQ+++aIPsdjjuDSXcC6oM8c=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1373943},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"}},"gitHead":"a5b49fe03921da3157b22bd354459a9516d439cd","scripts":{"lint":"eslint src/ tests/","test":"vitest run","build":"tsc","bench:leak":"node --expose-gc scripts/bench-leak.mjs","test:coverage":"vitest run --coverage","prepublishOnly":"npm run build"},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"repository":{"url":"git+https://github.com/backloghq/agentdb.git","type":"git"},"_npmVersion":"11.13.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","directories":{},"sideEffects":false,"_nodeVersion":"25.9.0","dependencies":{"zod":"^4.3.6","jose":"^6.2.2","express":"^5.2.1","hyparquet":"^1.25.6","hyparquet-writer":"^0.13.0","@backloghq/opslog":"^0.8.1","@backloghq/termlog":"^0.1.2","@modelcontextprotocol/sdk":"^1.29.0"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.2.0","vitest":"^4.1.4","@eslint/js":"^10.0.1","typescript":"~6.0.2","@types/node":"^25.6.0","@types/express":"^5.0.6","typescript-eslint":"^8.58.1","@aws-sdk/client-s3":"^3.1028.0","@vitest/coverage-v8":"^4.1.4","@backloghq/termlog-s3":"^0.1.0"},"peerDependencies":{"@backloghq/termlog-s3":"^0.1.0"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.1"},"peerDependenciesMeta":{"@backloghq/termlog-s3":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/agentdb_2.2.1_1778153436258_0.27549089590390907","host":"s3://npm-registry-packages-npm-production"}},"2.3.0":{"name":"@backloghq/agentdb","version":"2.3.0","description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./tools":{"types":"./dist/tools/index.d.ts","import":"./dist/tools/index.js"},"./mcp":{"types":"./dist/mcp/index.d.ts","import":"./dist/mcp/index.js"}},"bin":{"agentdb":"dist/mcp/cli.js"},"scripts":{"build":"tsc","lint":"eslint src/ tests/","test":"vitest run","test:coverage":"vitest run --coverage","bench:leak":"node --expose-gc scripts/bench-leak.mjs","prepublishOnly":"npm run build"},"keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"author":{"name":"mbocevski"},"license":"MIT","engines":{"node":">=22"},"repository":{"type":"git","url":"git+https://github.com/backloghq/agentdb.git"},"sideEffects":false,"dependencies":{"@backloghq/opslog":"^0.8.1","@backloghq/termlog":"^0.2.0","@modelcontextprotocol/sdk":"^1.29.0","express":"^5.2.1","hyparquet":"^1.26.0","hyparquet-writer":"^0.15.6","jose":"^6.2.3","zod":"^4.4.3"},"optionalDependencies":{"@backloghq/opslog-s3":"^0.4.1"},"peerDependencies":{"@backloghq/termlog-s3":"^0.1.0"},"peerDependenciesMeta":{"@backloghq/termlog-s3":{"optional":true}},"devDependencies":{"@aws-sdk/client-s3":"^3.1057.0","@backloghq/termlog-s3":"^0.1.0","@eslint/js":"^10.0.1","@types/express":"^5.0.6","@types/node":"^25.9.1","@vitest/coverage-v8":"^4.1.7","eslint":"^10.4.1","typescript":"^6.0.3","typescript-eslint":"^8.60.0","vitest":"^4.1.7"},"gitHead":"a789f624c3f39bbb8952a4f8634b79c49342c456","_id":"@backloghq/agentdb@2.3.0","bugs":{"url":"https://github.com/backloghq/agentdb/issues"},"homepage":"https://github.com/backloghq/agentdb#readme","_nodeVersion":"26.1.0","_npmVersion":"11.14.1","dist":{"integrity":"sha512-OGtMKLX2i0PyjoSFTKJmhZUYp1lsCV6HUDY6NDPAY6BlJq0DFI7XxwwlHGNyuKWkCdrBW0Loq+crIWTjcLt6Ug==","shasum":"d24b13c653cd6b46d493d911a398d5418659cc18","tarball":"https://registry.npmjs.org/@backloghq/agentdb/-/agentdb-2.3.0.tgz","fileCount":189,"unpackedSize":1383252,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD0CZ1cEPzh6u4TskYT4nhuJvxnFpFjaFREoBYLN5oSxwIhAObxXxKFXlUscP8IoOu8T001o6SjwVaYBcmgGL7WPc6e"}]},"_npmUser":{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"},"directories":{},"maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/agentdb_2.3.0_1780145307338_0.12625491032039915"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-10T13:44:07.505Z","modified":"2026-05-30T12:48:27.625Z","1.0.0":"2026-04-10T13:44:07.824Z","1.1.0":"2026-04-10T19:43:49.375Z","1.1.1":"2026-04-11T11:01:25.123Z","1.2.0":"2026-04-11T17:44:48.298Z","1.2.1":"2026-04-11T17:58:55.147Z","1.3.0":"2026-04-18T20:07:32.999Z","1.3.1":"2026-05-02T21:10:18.952Z","1.4.0":"2026-05-04T09:07:07.149Z","2.0.0":"2026-05-05T13:57:31.861Z","2.1.0":"2026-05-05T22:33:12.953Z","2.1.1":"2026-05-06T10:28:11.740Z","2.2.0":"2026-05-06T17:41:04.146Z","2.2.1":"2026-05-07T11:30:36.455Z","2.3.0":"2026-05-30T12:48:27.493Z"},"bugs":{"url":"https://github.com/backloghq/agentdb/issues"},"author":{"name":"mbocevski"},"license":"MIT","homepage":"https://github.com/backloghq/agentdb#readme","keywords":["agent","database","embedded","llm","mcp","document-store","ai"],"repository":{"type":"git","url":"git+https://github.com/backloghq/agentdb.git"},"description":"AI-first embedded database for LLM agents. Library-first architecture with framework-agnostic tool definitions and MCP adapter.","maintainers":[{"name":"fenrirbaest","email":"marko.bocevski@gmail.com"}],"readme":"# AgentDB\n\n[![CI](https://github.com/backloghq/agentdb/actions/workflows/ci.yml/badge.svg)](https://github.com/backloghq/agentdb/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nAI-first embedded database for LLM agents. Zero native dependencies, pure TypeScript.\n\n## Install\n\n```bash\nnpm install @backloghq/agentdb\n```\n\n## Quick Start\n\n```typescript\nimport { AgentDB } from \"@backloghq/agentdb\";\n\n// Recommended: one-call factory that constructs and initializes\nconst db = await AgentDB.open(\"./data\");\n\nconst tasks = await db.collection(\"tasks\");\n\n// Insert\nconst id = await tasks.insert(\n  { title: \"Ship v1\", status: \"active\", priority: 1 },\n  { agent: \"planner\", reason: \"Sprint kickoff\" },\n);\n\n// Find\nconst result = await tasks.find({ filter: { status: \"active\" } });\n// → { records: [...], total: 1, truncated: false }\n\n// Update\nawait tasks.update(\n  { _id: id },\n  { $set: { status: \"done\" } },\n  { agent: \"planner\", reason: \"Completed\" },\n);\n\n// Clean up\nawait db.close();\n```\n\n## Declarative Schemas\n\nDefine typed, validated collections in one place:\n\n```typescript\nimport { AgentDB, defineSchema } from \"@backloghq/agentdb\";\n\nconst db = await AgentDB.open(\"./data\");\n\nconst tasks = await db.collection(defineSchema({\n  name: \"tasks\",\n  version: 1,\n  description: \"Project tasks tracked by the team\",\n  instructions: \"Set priority based on urgency. Close done tasks after review.\",\n  fields: {\n    title: { type: \"string\", required: true, maxLength: 200, description: \"Short task summary\" },\n    status: { type: \"enum\", values: [\"pending\", \"done\"], default: \"pending\", description: \"Current state\" },\n    priority: { type: \"enum\", values: [\"H\", \"M\", \"L\"], default: \"M\", description: \"H=urgent, M=normal, L=backlog\" },\n    score: { type: \"number\", min: 0, max: 100 },\n    tags: { type: \"string[]\" },\n  },\n  indexes: [\"status\", \"priority\"],\n  arrayIndexes: [\"tags\"],           // O(1) $contains lookups\n  computed: {\n    isUrgent: (r) => r.priority === \"H\" && r.status === \"pending\",\n  },\n  virtualFilters: {\n    \"+URGENT\": (r) => r.priority === \"H\" && r.status === \"pending\",\n  },\n  hooks: {\n    beforeInsert: (record) => ({ ...record, createdAt: new Date().toISOString() }),\n  },\n}));\n// Schema auto-persisted to meta/tasks.schema.json — any agent can discover it\n\nawait tasks.insert({ title: \"Fix critical bug\", priority: \"H\" });\n// → status defaults to \"pending\", priority validated, createdAt auto-set\n\nconst urgent = await tasks.find({ filter: { \"+URGENT\": true } });\n```\n\nFields support: `string`, `number`, `boolean`, `date`, `enum`, `string[]`, `number[]`, `object`, `autoIncrement`. Constraints: `required`, `maxLength`, `min`, `max`, `pattern`, `default`, `resolve`.\n\n**Field resolve** — transform values before validation (e.g. parse natural language dates):\n\n```typescript\nfields: {\n  due: { type: \"date\", resolve: (v) => v === \"tomorrow\" ? nextDay() : v },\n  score: { type: \"number\", resolve: (v) => typeof v === \"string\" ? parseInt(v) : v },\n}\n```\n\n**Custom tag field** — `+tag`/`-tag` syntax queries \"tags\" by default, configurable via `tagField`:\n\n```typescript\ndefineSchema({ tagField: \"labels\", fields: { labels: { type: \"string[]\" } } })\n// +bug → { labels: { $contains: \"bug\" } }\n```\n\n## Three Ways to Use It\n\n### 1. Direct Import\n\n```typescript\nimport { AgentDB } from \"@backloghq/agentdb\";\n```\n\nFull programmatic access. Use `AgentDB` to manage collections, `Collection` for CRUD.\n\n### 2. Tool Definitions\n\n```typescript\nimport { AgentDB } from \"@backloghq/agentdb\";\nimport { getTools } from \"@backloghq/agentdb/tools\";\n\nconst db = await AgentDB.open(\"./data\");\n\nconst tools = getTools(db);\n// → Array of { name, description, schema, annotations, execute }\n```\n\nFramework-agnostic. Each tool has a zod schema and an `execute` function that returns `{ content: [...] }`. Works with Vercel AI SDK, LangChain, or any framework that accepts tool definitions.\n\n### 3. MCP Server\n\n```bash\nnpx @backloghq/agentdb --path ./data              # stdio (single client)\nnpx @backloghq/agentdb --path ./data --http       # HTTP (multiple clients)\n```\n\n**Schema bootstrap — two ways to ship schemas with your data.**\n\nA schema file is a single JSON document describing one collection — the same shape as `meta/{name}.schema.json` after `defineSchema` auto-persists:\n\n```json\n{\n  \"name\": \"tickets\",\n  \"version\": 1,\n  \"description\": \"Customer support tickets — queue for the on-call team\",\n  \"instructions\": \"Set priority from customer tier (enterprise=high). Resolve before closing.\",\n  \"fields\": {\n    \"title\":    { \"type\": \"string\", \"required\": true, \"maxLength\": 200, \"description\": \"Short summary; first line of the issue\" },\n    \"status\":   { \"type\": \"enum\", \"values\": [\"open\", \"in_progress\", \"resolved\", \"closed\"], \"default\": \"open\" },\n    \"priority\": { \"type\": \"enum\", \"values\": [\"low\", \"medium\", \"high\"], \"description\": \"Set from customer tier\" },\n    \"openedAt\": { \"type\": \"date\", \"required\": true }\n  },\n  \"indexes\": [\"status\", \"priority\"]\n}\n```\n\n**Option 1 — auto-discovery.** Drop files into `<dataDir>/schemas/` and every `*.json` there is loaded on `db.init()`:\n\n```bash\nmkdir -p ./data/schemas\ncp tickets.json ./data/schemas/\nnpx @backloghq/agentdb --path ./data\n# → [agentdb] schemas/*.json: loaded 1\n```\n\nBad files are logged and skipped; missing directory is silently ignored. The schemas travel with the data directory on backup/move.\n\n**Option 2 — `--schemas` flag.** Point at any path or glob; multiple flags are unioned:\n\n```bash\nnpx @backloghq/agentdb --path ./data --schemas ./schemas/*.json\nnpx @backloghq/agentdb --path ./data --schemas ./teams/users.json --schemas ./teams/tasks.json\n```\n\nUseful when schemas live in a separate repo or are generated by a build step.\n\n**Load order**: auto-discover from `<dataDir>/schemas/` runs first during `db.init()`, then `--schemas` paths load on top as overlays. File properties win per-property; untouched persisted properties are preserved.\n\n**Option 3 — at runtime via MCP tools.** Agents with admin permission can create collections and attach schemas without a restart (see [Tool Definitions](#tool-definitions) for the full tool reference):\n\n```\ndb_set_schema {\n  collection: \"tickets\",\n  schema: {\n    description: \"Customer support tickets\",\n    instructions: \"Set priority from customer tier.\",\n    fields: {\n      title:  { type: \"string\", required: true, maxLength: 200 },\n      status: { type: \"enum\", values: [\"open\", \"closed\"], default: \"open\" }\n    },\n    indexes: [\"status\"]\n  }\n}\n```\n\nThe schema file is written to `meta/tickets.schema.json` immediately. If the collection doesn't exist yet, it materializes on the first insert — no separate `db_create` call needed. Re-calling `db_set_schema` merges with the existing schema (overlay semantics, same as `--schemas`). `db_diff_schema` previews changes first; `db_delete_schema` removes the file.\n\nAll tools exposed as MCP tools (with additional `db_subscribe`/`db_unsubscribe` on HTTP transport). Claude Code config (`~/.claude/settings.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"agentdb\": {\n      \"command\": \"npx\",\n      \"args\": [\"agentdb\", \"--path\", \"/absolute/path/to/data\"]\n    }\n  }\n}\n```\n\n## Disk-Backed Storage\n\nFor large collections that exceed available RAM, enable disk-backed mode. Collections are compacted to Parquet files with persistent indexes.\n\n```typescript\n// Global: all collections use disk mode\nconst db = new AgentDB(\"./data\", {\n  storageMode: \"disk\",   // \"memory\" (default) | \"disk\" | \"auto\"\n  cacheSize: 10_000,     // LRU cache size (records)\n  rowGroupSize: 5000,    // Parquet row group size\n});\n\n// Per-collection via schema\nconst events = await db.collection(defineSchema({\n  name: \"events\",\n  storageMode: \"disk\",\n  fields: { ... },\n  indexes: [\"type\", \"timestamp\"],\n  arrayIndexes: [\"tags\"],\n}));\n\n// Auto mode: switches to disk when collection exceeds threshold\nconst db = new AgentDB(\"./data\", {\n  storageMode: \"auto\",\n  diskThreshold: 10_000,  // default\n});\n```\n\nDisk mode opens with `skipLoad` — records are NOT loaded into memory. On close, compaction writes two artifacts:\n\n- **Parquet** — `_id` + extracted columns only. For `count()`, column scans, and skip-scanning. No full records stored.\n- **JSONL record store** — full records, one per line. For `findOne()` and `find(limit:N)` via byte-range seeks.\n\nPoint lookups use `readBlobRange` to seek directly to a record's byte offset in the JSONL file — O(1) per record on filesystem, single HTTP Range request on S3. No row group parsing, no full-file reads.\n\nCompaction is incremental — close writes only new records, not the full dataset. Auto-merges after 10 incremental files. Indexes are lazy-loaded on first query.\n\nAll disk I/O goes through `StorageBackend` — works identically on filesystem and S3. Zero native dependencies.\n\n## S3 Backend\n\nStore data in Amazon S3 instead of the local filesystem. Zero code changes — just configure via CLI flags or environment variables.\n\n### CLI flags\n\n```bash\nnpx @backloghq/agentdb --backend s3 --bucket my-bucket --region us-east-1\nnpx @backloghq/agentdb --backend s3 --bucket my-bucket --prefix prod/agentdb --http --port 3000\nnpx @backloghq/agentdb --backend s3 --bucket my-bucket --agent-id agent-1  # multi-writer\n```\n\n### Environment variables\n\n```bash\nAGENTDB_BACKEND=s3\nAGENTDB_S3_BUCKET=my-bucket\nAGENTDB_S3_PREFIX=agentdb        # optional key prefix\nAWS_REGION=us-east-1\nAGENTDB_AGENT_ID=agent-1         # optional multi-writer\nnpx @backloghq/agentdb\n```\n\n### Library usage\n\n```typescript\nimport { AgentDB, loadS3Backend } from \"@backloghq/agentdb\";\n\nconst { S3Backend } = await loadS3Backend(); // optional — requires @backloghq/opslog-s3\nconst db = new AgentDB(\"mydb\", {\n  backend: new S3Backend({\n    bucket: \"my-bucket\",\n    prefix: \"agentdb\",\n    region: \"us-east-1\",\n  }),\n  agentId: \"agent-1\",  // optional: enables multi-writer\n});\nawait db.init();\n```\n\nAWS credentials use the standard SDK chain (env vars, IAM role, `~/.aws/config`). The AWS SDK is only loaded when S3 is configured — filesystem users never pay the cost.\n\n### Text search on S3\n\nWhen agentdb detects an S3 opslog backend, text indexes automatically use `@backloghq/termlog-s3` instead of the local filesystem. No configuration needed — the same bucket and prefix are used, with a per-collection subpath (`<prefix>/<collection>/text/`). Install the optional peer dependency to enable it:\n\n```bash\nnpm install @backloghq/termlog-s3\n```\n\n### Single-writer constraint\n\nBoth `@backloghq/opslog-s3` and `@backloghq/termlog-s3` require that only **one agentdb process** writes to a given `(bucket, prefix)` at a time. Multiple concurrent writers will corrupt the WAL. For multi-process setups, use the HTTP MCP server as a single-writer proxy.\n\n### S3 lifecycle recommendation\n\nConfigure an `AbortIncompleteMultipartUpload` lifecycle rule (1-day expiry) on the bucket. This cleans up orphaned multipart uploads from crashed writers. See the [termlog-s3 README](https://github.com/backloghq/termlog-s3#readme) for bucket setup details.\n\n## Filter Syntax\n\nTwo syntaxes. JSON is primary, compact string is secondary.\n\n### JSON Filters\n\n```typescript\n// Equality (implicit)\ntasks.find({ filter: { status: \"active\" } });\n\n// Comparison operators\ntasks.find({ filter: { priority: { $gt: 3 } } });\n\n// Dot-notation for nested fields\ntasks.find({ filter: { \"metadata.tags\": { $contains: \"urgent\" } } });\n\n// Logical operators\ntasks.find({\n  filter: {\n    $or: [{ status: \"active\" }, { priority: { $gte: 5 } }],\n  },\n});\n```\n\n**Operators:** `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`, `$in`, `$nin`, `$contains`, `$startsWith`, `$endsWith`, `$exists`, `$regex`, `$not`, `$strLen`\n\nTop-level keys are implicitly ANDed.\n\n### Compact String Filters\n\nShorthand for tool calls and quick queries:\n\n```\nstatus:active                          → { status: \"active\" }\nstatus:active priority.gt:3           → { $and: [{ status: \"active\" }, { priority: { $gt: 3 } }] }\nname.contains:alice                    → { name: { $contains: \"alice\" } }\n(role:admin or role:mod)               → { $or: [{ role: \"admin\" }, { role: \"mod\" }] }\ntags.in:bug,feature                    → { tags: { $in: [\"bug\", \"feature\"] } }\ntitle.strLen:20                        → { title: { $strLen: 20 } }\ntitle.strLen.gt:10                     → { title: { $strLen: { $gt: 10 } } }\n+bug                                   → { tags: { $contains: \"bug\" } }\n-old                                   → { tags: { $not: { $contains: \"old\" } } }\nauth error                             → { $text: \"auth error\" }\nstatus:active auth                     → { $and: [{ status: \"active\" }, { $text: \"auth\" }] }\n```\n\nModifier aliases: `gt`, `gte`, `lt`, `lte`, `ne`, `contains`, `has`, `startsWith`, `starts`, `endsWith`, `ends`, `in`, `nin`, `exists`, `regex`, `match`, `eq`, `is`, `not`, `after`, `before`, `above`, `below`, `over`, `under`, `strLen`\n\n## Collection API\n\n> **v1.2 breaking change:** `findOne`, `find`, `findAll`, `count`, `search`, `queryView` are now async and return Promises.\n\n```typescript\nconst col = await db.collection(\"tasks\");\n\n// Insert\nconst id = await col.insert(doc, opts?);\nconst ids = await col.insertMany(docs, opts?);\n\n// Read (async)\nconst record = await col.findOne(id);\nconst result = await col.find({ filter?, limit?, offset?, summary?, sort?, maxTokens? });\nconst n = await col.count(filter?);\n\n// Update\nconst modified = await col.update(filter, { $set?, $unset?, $inc?, $push? }, opts?);\nconst { id, action } = await col.upsert(id, doc, opts?);\nconst results = await col.upsertMany([{ _id, ...doc }, ...], opts?);\n\n// Delete\nconst deleted = await col.remove(filter, opts?);\n\n// History\nconst undone = await col.undo();\nconst ops = col.history(id);\n\n// Inspect\nconst shape = col.schema(sampleSize?);\nconst uniq = col.distinct(field);\n```\n\nAll mutation methods accept `opts?: { agent?: string; reason?: string }`.\n\n## Schema Lifecycle for Agents\n\n> **Terminology** — three distinct \"schema\" concepts:\n> - **`defineSchema()`** — code-level API; includes hooks, validators, computed fields. Lives in memory only; never serialized.\n> - **`PersistedSchema`** — JSON-serializable subset (description, instructions, field types, constraints, indexes). Stored in `meta/{name}.schema.json`. This is what agents read and write.\n> - **`db_schema`** — tool that *samples actual records* to infer field shapes dynamically. Does not read the `PersistedSchema` file; works even with no schema defined.\n\nAgentDB treats schemas as first-class runtime objects that agents can inspect, evolve, and reason about — not just static type definitions. Here's the full six-step lifecycle:\n\n### 1. Define — declare your schema in code\n\n```typescript\nconst tasks = await db.collection(defineSchema({\n  name: \"tasks\",\n  version: 1,\n  description: \"Project tasks tracked by the team\",\n  instructions: \"Set priority based on urgency.\",\n  fields: {\n    title: { type: \"string\", required: true, maxLength: 200 },\n    status: { type: \"enum\", values: [\"pending\", \"done\"], default: \"pending\" },\n  },\n  indexes: [\"status\"],\n}));\n```\n\n### 2. Persist — schema auto-saved to disk\n\n`defineSchema` collections automatically persist to `{dataDir}/meta/{name}.schema.json` on first open. The file contains the agent-facing context (description, instructions, field descriptions) but not runtime-only config (hooks, computed fields). The file can be committed to source control, loaded at startup, or shipped as a seed.\n\n### 3. Discover — agents find and read schemas at runtime\n\n```\ndb_collections          → lists all collections with record count + schema summary\ndb_get_schema tasks     → returns full persisted schema: description, instructions,\n                          field types, constraints, indexes, version\n```\n\nAny agent can call these without knowing the codebase. They answer \"what data exists and how should I use it?\"\n\n### 4. Diff — preview schema changes before committing\n\n```\ndb_diff_schema tasks { fields: { priority: { type: \"enum\", values: [\"H\",\"M\",\"L\"] } } }\n→ { added: [\"priority\"], changed: [], removed: [], warnings: [], impact: { ... } }\n```\n\n`db_diff_schema` uses `mergePersistedSchemas` internally (same semantics as `db_set_schema`), so it accurately shows what would change — including record-impact counts for constraint tightening (e.g. how many strings exceed a new `maxLength`).\n\n### 5. Migrate — apply bulk data changes\n\n```\ndb_migrate tasks { ops: [{ op: \"default\", field: \"priority\", value: \"M\" }] }\n→ { scanned: 1200, updated: 843, unchanged: 357, failed: 0 }\n```\n\n`db_migrate` supports `set`, `unset`, `rename`, `default`, and `copy` ops. Use `dryRun: true` to preview counts. Records that fail validation or are deleted mid-run land in `errors[]` with per-record context.\n\n### 6. Infer — bootstrap a schema from existing data (cold start)\n\nWhen you have data but no schema, `db_infer_schema` samples the collection and proposes a `PersistedSchema`:\n\n```\ndb_infer_schema tasks { sampleSize: 200 }\n→ { proposed: { fields: { title: { type: \"string\", maxLength: 180 }, ... } }, notes: [...] }\n```\n\nThe proposed schema passes `validatePersistedSchema` and can be forwarded directly to `db_set_schema`.\n\n### Forward compatibility\n\nSchema JSON files are forward-compatible by design. Unknown top-level and field-level properties are silently ignored by `validatePersistedSchema` — a file written by a newer version of AgentDB can be loaded by an older version without error. Unknown properties also round-trip cleanly: loading a schema with extra fields and persisting it back preserves those fields unmodified.\n\nThis means you can safely commit schema files generated by a newer version of the library and roll back without data loss or startup errors.\n\n### Library API: programmatic schema management\n\n```typescript\n// Load JSON schema files at startup (overlay semantics, per-file isolation)\nconst result = await db.loadSchemasFromFiles([\"./schemas/tasks.json\"]);\n// → { loaded: 1, skipped: 0, failed: [] }\n\n// Merge two persisted schemas with overlay (used internally by db_set_schema)\nimport { mergePersistedSchemas } from \"@backloghq/agentdb\";\nconst merged = mergePersistedSchemas(existing, incoming);\n// Overlay wins per-property, not per-field — updating { type } preserves { description }\n\n// Reconcile code-level schema with persisted schema at collection open time\nimport { mergeSchemas } from \"@backloghq/agentdb\";\nconst { persisted, warnings } = mergeSchemas(codeSchema, persistedSchema);\n// Code wins for validation, persisted wins for agent context\n```\n\n## Tool Definitions\n\n`getTools(db)` returns tools covering:\n\n| Tool | Description |\n|------|-------------|\n| `db_collections` | List all collections with record counts and schema summaries |\n| `db_create` | Create a collection (idempotent) |\n| `db_drop` | Soft-delete a collection |\n| `db_purge` | Permanently delete a dropped collection |\n| `db_insert` | Insert one or more records |\n| `db_find` | Query with filter, pagination, summary mode, token budget |\n| `db_find_one` | Get a single record by ID |\n| `db_update` | Update matching records ($set, $unset, $inc, $push) |\n| `db_upsert` | Insert or update by ID |\n| `db_delete` | Delete matching records |\n| `db_count` | Count matching records |\n| `db_batch` | Execute multiple mutations atomically |\n| `db_undo` | Undo last mutation |\n| `db_history` | Mutation history for a record |\n| `db_schema` | Sample records to infer field shapes dynamically — no stored schema required |\n| `db_get_schema` | Read the PersistedSchema (description, instructions, field types, indexes) from `meta/` |\n| `db_set_schema` | Create/update persisted schema (admin-only, partial merge) |\n| `db_delete_schema` | Delete persisted schema for a collection (admin-only, idempotent) |\n| `db_diff_schema` | Preview what db_set_schema would change — structured diff with warnings and record impact counts |\n| `db_infer_schema` | Sample existing records and propose a PersistedSchema — cold-start schema bootstrap |\n| `db_migrate` | Declarative bulk record update via set/unset/rename/default/copy ops with dryRun and per-record error tracking |\n| `db_distinct` | Unique values for a field |\n| `db_stats` | Database-level statistics |\n| `db_archive` | Move records to cold storage |\n| `db_archive_list` | List archive segments |\n| `db_archive_load` | View archived records |\n| `db_semantic_search` | Search by meaning (requires embedding provider) |\n| `db_embed` | Manually trigger embedding |\n| `db_vector_upsert` | Store a pre-computed vector with metadata |\n| `db_vector_search` | Search by raw vector (no embedding provider needed) |\n| `db_bm25_search` | Pure BM25 lexical search (no embedding provider needed) |\n| `db_hybrid_search` | Hybrid BM25 + semantic search fused via RRF (degrades gracefully) |\n| `db_reembed_all` | Force-reembed all records in a collection — use when upgrading from v1.3 (admin-only, DESTRUCTIVE) |\n| `db_rebuild_text_index` | Rebuild the BM25 text index from scratch — use after upgrading from v1.4 (admin-only) |\n| `db_blob_write` | Attach a file (base64) to a record |\n| `db_blob_read` | Read an attached file |\n| `db_blob_list` | List files attached to a record |\n| `db_blob_delete` | Delete an attached file |\n| `db_export` | Export collections as JSON backup |\n| `db_import` | Import from a JSON backup |\n\nEach tool returns `{ content: [{ type: \"text\", text: \"...\" }] }`. Tools with an `outputSchema` also include `structuredContent` for typed programmatic access — clients that know the shape can use it directly instead of parsing the text. Errors return `{ isError: true, content: [...] }` — they never throw across the tool boundary.\n\n## Agent Identity\n\nEvery mutation accepts `agent` and `reason`. These are stored internally and visible in history, but stripped from query results.\n\n```typescript\nawait col.insert(\n  { title: \"Fix login bug\" },\n  { agent: \"triage-bot\", reason: \"Auto-filed from error spike\" },\n);\n\n// History shows who did what and why\ncol.history(id);\n// → [{ type: \"set\", key: \"...\", value: { ..., _agent: \"triage-bot\", _reason: \"...\" }, ... }]\n```\n\n## Authentication\n\n### Bearer token (simplest)\n\n```bash\nnpx @backloghq/agentdb --http --auth-token my-secret-token\n\n# Agents send: Authorization: Bearer my-secret-token\n```\n\nOr via environment variable:\n\n```bash\nAGENTDB_AUTH_TOKEN=my-secret-token npx @backloghq/agentdb --http\n```\n\nNo token configured = open access (backward compatible). Health check at `/health` always works.\n\n### Multi-agent tokens\n\nMap different tokens to different agent identities and permissions:\n\n```typescript\nstartHttp(dir, {\n  authTokens: {\n    \"token-reader\": { agentId: \"reader\", permissions: { read: true, write: false, admin: false } },\n    \"token-writer\": { agentId: \"writer\", permissions: { read: true, write: true, admin: false } },\n  },\n});\n```\n\n### Agent identity and the `agent` parameter\n\nAll mutation tools accept an `agent` parameter to stamp who made a change. **Over an authenticated HTTP transport, this parameter is silently overridden with the authenticated identity — the value you supply is ignored.** The authenticated identity (from bearer token or JWT) always wins.\n\nLibrary callers without auth context (in-process `new AgentDB(...)` use) still control the field directly.\n\n| Context | Behavior |\n|---|---|\n| HTTP + auth configured | Authenticated identity wins; `agent` arg ignored |\n| HTTP + no auth | `agent` arg used as-is |\n| Library (in-process) | `agent` arg used as-is |\n\n### JWT (production)\n\nValidate JWTs from any OAuth provider (Auth0, WorkOS, etc.):\n\n```typescript\nimport { startHttp, createJwtAuth } from \"@backloghq/agentdb/mcp\";\n\nstartHttp(dir, {\n  authFn: createJwtAuth({\n    jwksUrl: \"https://your-domain.auth0.com/.well-known/jwks.json\",\n    audience: \"agentdb\",\n    issuer: \"https://your-domain.auth0.com\",\n  }),\n});\n```\n\n### Auth priority when multiple mechanisms are configured\n\nIf more than one mechanism is set in the same config, the CLI enforces a fixed priority and emits a warning at startup:\n\n```\njwt > multi-token > bearer\n```\n\n| What you configured | What is enforced |\n|---|---|\n| `AGENTDB_HTTP_JWT_SECRET` only | JWT |\n| `AGENTDB_HTTP_MULTI_TOKEN` only | multi-token |\n| `AGENTDB_AUTH_TOKEN` only | bearer |\n| JWT + multi-token (or bearer) | JWT wins; others are silently ignored after warning |\n| multi-token + bearer | multi-token wins; bearer is silently ignored after warning |\n\nThe warning is emitted to stderr and names the active mechanisms, the winner, and the priority order.\n\n**JWT secret minimum length:** use at least 32 characters (256 bits) for HMAC-SHA256 secrets. Shorter keys are cryptographically weak and may be rejected by strict JWT libraries. A good default: `openssl rand -hex 32`.\n\n### Group commit (faster writes)\n\nBuffer writes in memory and flush as a single disk write. ~12x faster for sustained writes. Single-writer only — auto-disabled when `agentId` is set.\n\n```bash\nnpx @backloghq/agentdb --http --group-commit\n\n# Or via env var\nAGENTDB_WRITE_MODE=group npx @backloghq/agentdb --http\n```\n\n```typescript\nconst db = new AgentDB(\"./data\", { writeMode: \"group\" });\n```\n\n**Tradeoff:** A crash can lose buffered ops (up to 100ms of data). Default `\"immediate\"` mode is safe — every write survives a crash.\n\n### Read-only mode\n\nOpen a read-only instance alongside a running writer — no write locks, safe for dashboards and monitoring:\n\n```typescript\nconst reader = new AgentDB(\"./data\", { readOnly: true });\nawait reader.init();\nconst col = await reader.collection(\"tasks\");\nawait col.tail(); // pick up latest writes\n```\n\n### Blob storage\n\nAttach files to records — images, PDFs, code, any binary. Stored outside the WAL via the StorageBackend (works on filesystem and S3).\n\n```typescript\nconst col = await db.collection(\"tasks\");\nawait col.insert({ _id: \"task-1\", title: \"Fix auth\" });\n\n// Attach files\nawait col.writeBlob(\"task-1\", \"spec.md\", \"# Spec\\n\\nDetails...\");\nawait col.writeBlob(\"task-1\", \"screenshot.png\", imageBuffer);\n\n// Read back\nconst spec = await col.readBlob(\"task-1\", \"spec.md\");\nconst blobs = await col.listBlobs(\"task-1\"); // → [\"spec.md\", \"screenshot.png\"]\n\n// Delete\nawait col.deleteBlob(\"task-1\", \"spec.md\");\n```\n\nBlobs are automatically cleaned up when their parent record is deleted.\n\n### Embeddings and vector search\n\nAgentDB supports semantic search via embedding providers and explicit vector storage.\n\n**Embedding providers** (for automatic text embedding):\n\n```bash\n# Local via Ollama (no API key)\nnpx @backloghq/agentdb --http --embeddings ollama\n\n# OpenAI\nOPENAI_API_KEY=sk-... npx @backloghq/agentdb --http --embeddings openai:text-embedding-3-small\n\n# Gemini (free tier available)\nGEMINI_API_KEY=... npx @backloghq/agentdb --http --embeddings gemini\n\n# Voyage AI / Cohere\nAGENTDB_EMBEDDINGS_API_KEY=... npx @backloghq/agentdb --http --embeddings voyage\nAGENTDB_EMBEDDINGS_API_KEY=... npx @backloghq/agentdb --http --embeddings cohere\n```\n\n**Explicit vector API** (no provider needed):\n\n```typescript\nconst col = await db.collection(\"docs\");\n\n// Store pre-computed vectors\nawait col.insertVector(\"doc1\", [0.1, 0.2, ...], { title: \"My Document\" });\n\n// Search by vector\nconst results = await col.searchByVector([0.1, 0.2, ...], { limit: 10, filter: { status: \"active\" } });\n// → { records: [...], scores: [0.98, 0.91, ...] }\n```\n\nMCP tools: `db_vector_upsert`, `db_vector_search`, `db_semantic_search`, `db_embed`.\n\n**What text gets embedded?**\n\nWhen AgentDB embeds a record automatically (via `embedUnembedded` or on insert), it concatenates the string values of all user-defined fields. Internal metadata fields — `_id`, `_version`, `_agent`, `_reason`, `_expires`, `_embedding` — are excluded.\n\nThis matters if you compute query embeddings client-side: embed only the user-field content, not any `_`-prefixed keys. Using the same field set for both indexing and querying is what makes retrieval work correctly.\n\n```typescript\n// Correct: embed only user fields\nconst queryText = `${record.title} ${record.body}`;\nconst [queryVec] = await provider.embed([queryText]);\nconst results = await col.searchByVector(queryVec, { limit: 10 });\n\n// Wrong: including _id shifts the embedding away from query embeddings\nconst queryText = `${record._id} ${record.title} ${record.body}`; // don't do this\n```\n\n**v1.3 → v1.4 migration:** v1.3 incorrectly included `_id` in the embedding text. If you have a disk-mode collection indexed by v1.3, call `col.reembedAll()` once after upgrading to fix the stored embeddings. The `db_reembed_all` MCP tool does the same thing (requires admin permission).\n\n**Memory note:** `embedUnembedded` (lazy path) holds all unembedded record references in memory before batching — roughly 1 KB/record, so ~1 GB at 1M unembedded. For large collections, call `col.reembedAll()` instead: it streams and flushes mid-run with bounded memory. `reembedAll` triggers an internal `compactInPlace()` every 8 batches, which itself fully materializes the on-disk dataset (~1 KB/record peak per compaction); cost is amortized across the run.\n\n### Hybrid search (BM25 + semantic)\n\nCombines BM25 lexical scoring with vector similarity, fused via Reciprocal Rank Fusion. Catches exact-term matches that semantic search misses, and semantic matches that keyword search misses.\n\n**Schema — mark fields as searchable:**\n\n```typescript\nconst notes = await db.collection(defineSchema({\n  name: \"notes\",\n  textSearch: true,\n  fields: {\n    title: { type: \"string\", searchable: true },  // BM25-indexed\n    body:  { type: \"string\", searchable: true },  // BM25-indexed\n    tags:  { type: \"string[]\" },                  // not indexed for BM25\n  },\n}));\n```\n\n`searchable: true` is opt-in. Collections without any `searchable` fields fall back to indexing all string fields (v1.3 behaviour preserved).\n\n**Library API:**\n\n```typescript\n// BM25-only (no embedding provider needed)\nconst { records, scores } = await notes.bm25Search(\"typescript generics\", {\n  limit: 10,\n  filter: { status: \"published\" },\n});\n\n// Hybrid: BM25 + semantic, fused via RRF\nconst { records, scores } = await notes.hybridSearch(\"typescript generics\", {\n  limit: 10,\n  k: 60,          // RRF k parameter — higher = less rank-position sensitive\n  filter: { status: \"published\" },\n});\n```\n\n**Degraded modes** — hybrid degrades gracefully:\n- No embedding provider configured → BM25-only ranking\n- No `textSearch: true` → vector-only ranking\n- Neither available → throws\n\n**MCP tool:**\n\n```json\n{ \"name\": \"db_hybrid_search\", \"arguments\": { \"collection\": \"notes\", \"query\": \"typescript generics\", \"limit\": 10 } }\n```\n\n**BM25 defaults:** `k1=1.2`, `b=0.75` (Okapi BM25 standard). Configurable via `Collection` constructor options. **RRF default:** `k=60` (Cormack et al. 2009).\n\n**Upgrading from v1.4:** v1.4 stored BM25 indexes as a single JSON blob (`indexes/text-index.json`). v2.0 uses `@backloghq/termlog` (segment-based LSM). On first open with `textSearch: true`, AgentDB detects the old blob and throws `LegacyTextIndexError`. See [Migration from v1.4](#migration-from-v14) below.\n\n**Unicode normalisation:** AgentDB does not normalise Unicode before tokenizing. Precomposed (`é`, U+00E9) and decomposed (`e` + U+0301) forms of the same character are treated as distinct tokens. Ensure your application uses consistent Unicode normalisation (e.g. NFC) on both indexed text and queries; otherwise the same word in different normal forms will not match.\n\n#### Limits\n\nv2.0+ uses `@backloghq/termlog` (segment-based LSM) for BM25 — there is no per-collection document cap. The old 256 MB `IndexFileTooLargeError` ceiling is gone.\n\n### Embedding and disk performance knobs\n\nTwo options control embedding throughput and disk-mode concurrency. Both follow the same placement rule: set a db-wide default in `AgentDBOptions`; override per-collection in `CollectionOptions`.\n\n**`embeddingBatchSize`** — number of records sent to the embedding provider in a single `embed()` call during `embedUnembedded`. Default: `256`.\n\n```typescript\n// db-wide default\nconst db = new AgentDB(\"./data\", { embeddingBatchSize: 128 });\n\n// per-collection override (wins over db-wide)\nconst col = await db.collection(\"articles\", { embeddingBatchSize: 64 });\n```\n\nSmaller batches reduce peak memory and provider timeout risk; larger batches reduce round-trips. Most hosted providers cap at 512–2048 texts per call — stay below their limit. All embedding providers (OpenAI, Voyage, Cohere, Gemini, Ollama, HTTP) automatically chunk each `embed()` call into provider-safe batches, so `embeddingBatchSize` can be set independently of API limits.\n\n**`diskConcurrency`** — maximum number of concurrent `DiskStore.get()` calls when materializing BM25/vector candidates in disk mode. Default: `20` for non-local-filesystem backends (e.g. S3); local filesystem is unbounded.\n\n```typescript\n// db-wide default (applied to every disk-mode collection)\nconst db = new AgentDB(\"./data\", { diskConcurrency: 32 });\n\n// per-collection override\nconst col = await db.collection(\"embeddings\", { diskConcurrency: 8 });\n```\n\nS3 sizing guidance: the default of `20` prevents per-prefix request throttling at typical QPS. If you are running at very high query concurrency (dozens of simultaneous `hybridSearch` calls) and observe `SlowDown` errors, raise to `32`. If you share an S3 prefix with other workloads, lower to `8` to leave headroom.\n\n### Rate limiting and CORS\n\n```bash\nnpx @backloghq/agentdb --http --auth-token secret --rate-limit 100 --cors https://app.example.com\n```\n\n### Real-time notifications\n\nSubscribe to collection changes via `db_subscribe` / `db_unsubscribe` on the HTTP MCP transport. Agents receive push notifications via SSE when records are inserted, updated, or deleted — no polling needed. See [examples/multi-agent/](./examples/multi-agent/) for a working demo.\n\n## Docker\n\n```bash\ndocker build -t agentdb .\ndocker run -p 3000:3000 -v ./data:/data agentdb --path /data --http --host 0.0.0.0\n\n# With auth:\ndocker run -p 3000:3000 -e AGENTDB_AUTH_TOKEN=secret -v ./data:/data agentdb --path /data --http --host 0.0.0.0\n\n# With a config file (mount the file and point --config at it):\ndocker run -p 3000:3000 \\\n  -v ./data:/data \\\n  -v ./agentdb.config.json:/etc/agentdb/config.json:ro \\\n  agentdb --path /data --http --host 0.0.0.0 --config /etc/agentdb/config.json\n\n# With S3:\ndocker run -p 3000:3000 \\\n  -e AGENTDB_BACKEND=s3 \\\n  -e AGENTDB_S3_BUCKET=my-bucket \\\n  -e AWS_REGION=us-east-1 \\\n  agentdb --http --host 0.0.0.0\n```\n\n## Sorting\n\n```typescript\ncol.find({ filter: { status: \"active\" }, sort: \"name\" });     // ascending\ncol.find({ filter: { status: \"active\" }, sort: \"-score\" });    // descending\ncol.find({ sort: \"-metadata.priority\" });                       // nested field\n```\n\n## Progressive Disclosure\n\nUse `summary: true` on find to get compact results. Omits long text fields (>200 chars), nested objects, and large arrays (>10 items). Useful for agents scanning many records before drilling into one.\n\n```typescript\ncol.find({ filter: { status: \"active\" }, summary: true });\n```\n\n## Deployment Patterns\n\n| Scenario | Pattern | Storage Mode | Latency |\n|----------|---------|-------------|---------|\n| Small datasets (<10K records) | Direct import / stdio MCP | memory (default) | <1ms |\n| Large datasets (10K-1M+) | Direct import / HTTP MCP | disk | <1ms findOne, ~10ms find |\n| Auto-scaling | Any | auto (switches at threshold) | varies |\n| Multiple agents, same machine | HTTP MCP server | memory or disk | ~1-5ms |\n| Multiple agents, distributed | HTTP MCP + S3 backend | disk | ~50ms |\n| Decentralized, no server | Multi-writer S3 | memory | ~50ms |\n\n**Storage mode guide:**\n- `memory` — all records in RAM. Fastest queries. Use for <10K records.\n- `disk` — records in JSONL + Parquet on disk/S3. Handles 1M+ records. Lazy index loading for fast cold open.\n- `auto` — starts in memory, switches to disk when collection exceeds `diskThreshold`.\n\n**Default recommendation:** Use `memory` for small datasets, `disk` or `auto` for anything that might grow.\n\n## Configuration\n\nThe MCP CLI accepts configuration from three sources. Precedence (highest first):\n\n1. **CLI flags** — passed directly to `npx @backloghq/agentdb`\n2. **Environment variables** — `AGENTDB_*` prefixed vars\n3. **Config file** — `agentdb.config.json` in the working directory, or the path from `--config` / `AGENTDB_CONFIG`\n\n### 1. CLI flags\n\nEvery option has a flag. Flags win over env vars and the config file:\n\n```bash\nnpx @backloghq/agentdb \\\n  --path ./data \\\n  --http --port 3000 \\\n  --backend s3 --bucket my-bucket \\\n  --write-mode group \\\n  --embeddings openai \\\n  --schemas \"schemas/*.json\" \\\n  --auth-token secret \\\n  --tenant-id org-123\n```\n\nRun `npx @backloghq/agentdb --help` for the full flag list.\n\n### 2. Environment variables\n\nAll flags have an `AGENTDB_` equivalent. Useful for container deployments and secrets managers:\n\n```bash\nAGENTDB_PATH=./data\nAGENTDB_WRITE_MODE=group\nAGENTDB_BACKEND=s3\nAGENTDB_S3_BUCKET=my-bucket\nAGENTDB_S3_REGION=us-east-1\nAGENTDB_HTTP_AUTH=secret\nAGENTDB_TENANT_ID=org-123\nAGENTDB_EMBEDDINGS_PROVIDER=openai\nAGENTDB_EMBEDDINGS_API_KEY=sk-...\n```\n\nFull reference:\n\n| Variable | Type | Description |\n|---|---|---|\n| `AGENTDB_CONFIG` | string | Path to config file (overrides auto-discovery) |\n| `AGENTDB_PATH` | string | Data directory |\n| `AGENTDB_WRITE_MODE` | `immediate`\\|`group`\\|`async` | Write durability mode |\n| `AGENTDB_GROUP_COMMIT_SIZE` | number | Batch size for group/async mode |\n| `AGENTDB_GROUP_COMMIT_MS` | number | Max latency (ms) for group commit |\n| `AGENTDB_MAX_FIND_LIMIT` | number | Cap on records returned by `find()` |\n| `AGENTDB_MAX_INDEX_CARDINALITY` | number | B-tree index cardinality threshold |\n| `AGENTDB_CACHE_SIZE` | number | Disk LRU record cache size |\n| `AGENTDB_DISK_CONCURRENCY` | number | Parallel JSONL reads |\n| `AGENTDB_EMBEDDING_BATCH_SIZE` | number | Records per embedding batch |\n| `AGENTDB_FILTER_CACHE_SIZE` | number | Compiled-filter LRU cache size |\n| `AGENTDB_MERGE_PARQUET_THRESHOLD` | number | Parquet file compaction trigger |\n| `AGENTDB_MERGE_JSONL_THRESHOLD` | number | JSONL file compaction trigger |\n| `AGENTDB_MEMORY_BUDGET` | number | Memory budget in bytes (0 = unlimited) |\n| `AGENTDB_ROW_GROUP_SIZE` | number | Parquet row group size |\n| `AGENTDB_HNSW_M` | number | HNSW M parameter |\n| `AGENTDB_HNSW_EF_CONSTRUCTION` | number | HNSW efConstruction |\n| `AGENTDB_HNSW_EF_SEARCH` | number | HNSW efSearch |\n| `AGENTDB_HNSW_MAX_LEVEL` | number | HNSW max level cap |\n| `AGENTDB_EMBEDDINGS_PROVIDER` | string | Embedding provider: `ollama`, `openai`, `voyage`, `cohere`, `gemini`, `http` |\n| `AGENTDB_EMBEDDINGS_API_KEY` | string | API key for the embedding provider |\n| `AGENTDB_EMBEDDINGS_MODEL` | string | Model name |\n| `AGENTDB_EMBEDDINGS_BATCH_LIMIT` | number | Max texts per API call (HTTP provider) |\n| `AGENTDB_EMBEDDINGS_URL` | string | HTTP embedding provider URL |\n| `AGENTDB_EMBEDDINGS_BASE_URL` | string | Ollama base URL (same as `AGENTDB_OLLAMA_URL`) |\n| `AGENTDB_EMBEDDINGS_DIMENSIONS` | number | Embedding vector dimensions (HTTP provider) |\n| `AGENTDB_OLLAMA_URL` | string | Ollama base URL (alias for `AGENTDB_EMBEDDINGS_BASE_URL`) |\n| `AGENTDB_DISK_THRESHOLD` | number | Record count at which `auto` mode switches to disk |\n| `AGENTDB_BACKEND` | `fs`\\|`s3` | Storage backend |\n| `AGENTDB_S3_BUCKET` | string | S3 bucket name |\n| `AGENTDB_S3_REGION` | string | AWS region |\n| `AGENTDB_S3_PREFIX` | string | S3 key prefix |\n| `AGENTDB_AGENT_ID` | string | Agent ID for multi-writer mode |\n| `AGENTDB_TENANT_ID` | string | Tenant binding |\n| `AGENTDB_SCHEMA_PATHS` | comma-list | Schema JSON files to load on startup |\n| `AGENTDB_STORAGE_MODE` | `memory`\\|`disk`\\|`auto` | Storage mode |\n| `AGENTDB_READ_ONLY` | boolean | Open collections read-only |\n| `AGENTDB_HTTP_PORT` | number | HTTP port |\n| `AGENTDB_HTTP_HOST` | string | HTTP bind address |\n| `AGENTDB_HTTP_AUTH` | string | Bearer token |\n| `AGENTDB_HTTP_MULTI_TOKEN` | JSON array | Multiple bearer tokens (JSON) |\n| `AGENTDB_HTTP_JWT_SECRET` | string | JWT signing secret |\n| `AGENTDB_HTTP_JWT_AUDIENCE` | string | JWT audience |\n| `AGENTDB_HTTP_JWT_ISSUER` | string | JWT issuer |\n| `AGENTDB_HTTP_MAX_SESSIONS` | number | Max concurrent MCP sessions |\n| `AGENTDB_HTTP_SESSION_IDLE_MS` | number | Session idle timeout (ms) |\n| `AGENTDB_HTTP_AUDIT_BUFFER_SIZE` | number | Audit log ring-buffer size |\n| `AGENTDB_HTTP_AUDIT_MAX_LIMIT` | number | Audit query max page size |\n| `AGENTDB_HTTP_AUDIT_DEFAULT_LIMIT` | number | Audit query default page size |\n| `AGENTDB_HTTP_RATE_LIMIT` | number | Max requests/minute per IP |\n| `AGENTDB_HTTP_RATE_LIMIT_WINDOW` | number | Rate limit window (ms) |\n| `AGENTDB_HTTP_CORS` | comma-list | Allowed CORS origins |\n| `AWS_REGION` | string | AWS region fallback (standard SDK var) |\n\n> **Security note:** environment variables set in a process are readable from `/proc/<pid>/environ` on Linux by any user with access to that file (root, or the process owner). For long-lived server processes, prefer injecting secrets via a secrets manager, a read-protected config file (`chmod 600 agentdb.config.json`), or systemd `EnvironmentFile=` with appropriate permissions — rather than exporting tokens directly in shell startup scripts.\n\n### 3. Config file\n\n`agentdb.config.json` in the working directory is loaded automatically when present. Use `--config <path>` or `AGENTDB_CONFIG=<path>` to point at a different file.\n\n**Note:** if you pass `--config` explicitly and the file does not exist, the CLI exits 1. The auto-discovered `./agentdb.config.json` silently produces an empty config when absent (no error), so you can safely omit it in development.\n\n```json\n{\n  \"db\": {\n    \"path\": \"./data\",\n    \"writeMode\": \"group\",\n    \"maxFindLimit\": 5000,\n    \"memoryBudget\": 1073741824,\n    \"hnsw\": { \"M\": 32, \"efSearch\": 100 },\n    \"embeddings\": {\n      \"provider\": \"openai\",\n      \"model\": \"text-embedding-3-small\"\n    }\n  },\n  \"http\": {\n    \"port\": 3000,\n    \"host\": \"0.0.0.0\",\n    \"auth\": \"change-me\",\n    \"maxSessions\": 200,\n    \"sessionIdleMs\": 600000,\n    \"cors\": [\"https://myapp.example.com\"]\n  },\n  \"collections\": {\n    \"notes\": {\n      \"maxFindLimit\": 500,\n      \"mergeParquetThreshold\": 5,\n      \"hnsw\": { \"efSearch\": 200 }\n    }\n  }\n}\n```\n\nThe `collections` key supports per-collection overrides for most storage and search knobs. Any key omitted falls back to the db-wide value.\n\n### Library API\n\nThe config pipeline is also available as a library function. The CLI uses it internally; library users are not affected by any of the above:\n\n```typescript\nimport { loadAgentDBConfig, ConfigValidationError } from \"@backloghq/agentdb\";\n\ntry {\n  const config = loadAgentDBConfig({\n    configPath: \"./my-config.json\", // optional; auto-discovers agentdb.config.json by default\n    requireConfigFile: true,        // error if configPath is missing (default: false)\n    env: process.env,               // injectable for testing\n    cli: { db: { path: \"./data\" } }, // highest precedence\n  });\n  console.log(config.db?.path);\n} catch (e) {\n  if (e instanceof ConfigValidationError) {\n    console.error(`Config error (${e.source}): ${e.message}`);\n  }\n}\n```\n\n`ConfigValidationError` carries `.source` (`\"file\"` | `\"env\"` | `\"cli\"`), `.path[]` (the field path that failed), and `.message`.\n\n### Restart required\n\nConfiguration is read once at startup. Changing env vars, the config file, or CLI flags takes effect only after restarting the process. There is no hot-reload.\n\n## Production Tuning\n\nEvery configurable knob, its location, default, and the workload signal that should prompt you to change it.\n\n`AgentDB` options propagate as defaults to every collection; per-collection `CollectionOptions` override them.\n\n### Storage and query knobs\n\n| Option | Location | Default | Tune when… | Recommended range |\n|--------|----------|---------|-----------|-------------------|\n| `maxFindLimit` | `AgentDB` / `Collection` | `10_000` | batch exports need >10K records per page, or you want to enforce a lower cap | 1K – unlimited |\n| `maxIndexCardinality` | `AgentDB` / `Collection` | `1_000` | `console.warn` fires at collection open naming a field that exceeds the threshold; queries on that field fall back to full Parquet scan | 100 – 100K |\n| `filterCacheSize` | `AgentDB` / `Collection` | `64` | a collection has many distinct query shapes (>64 unique filters in a session) | 32 – 256 |\n| `cacheSize` | `AgentDB` / `Collection` | `1_000` | `metrics().recordCacheHits / recordCacheFetches` hit rate is low (<50%) on a hot collection | 100 – 100K |\n| `rowGroupSize` | `AgentDB` / `Collection` | `5_000` | column scan performance is slow (lower = smaller seek range, higher = fewer S3 requests) | 1K – 20K |\n| `mergeParquetThreshold` | `AgentDB` / `Collection` | `10` | S3 per-request cost is high (raise), or local read amplification is high (lower) | 4 – 50 |\n| `mergeJsonlThreshold` | `AgentDB` / `Collection` | `8` | same as `mergeParquetThreshold` — controls JSONL delta file accumulation before full merge | 4 – 40 |\n| `diskConcurrency` | `AgentDB` / `Collection` | `20` | S3 point-lookup latency is high (raise to overlap more requests); has no effect on local FS | 4 – 64 |\n| `embeddingBatchSize` | `AgentDB` / `Collection` | `256` | embedding provider rate-limit errors or timeouts on large batch runs | 8 – 512 |\n| `hnsw.M` | `AgentDB` / `Collection` | `16` | recall is low (raise) or index build is slow and you accept lower recall (lower) | 4 – 64 |\n| `hnsw.efConstruction` | `AgentDB` / `Collection` | `200` | index build time is too slow (lower) or initial recall on a fresh dataset is unsatisfactory (raise) | 50 – 500 |\n| `hnsw.efSearch` | `AgentDB` / `Collection` | `50` | `semanticSearch` / `hybridSearch` recall is insufficient (raise) or query latency is high (lower) | 10 – 500 |\n\n### Write mode and commit knobs\n\n| Option | Location | Default | Tune when… | Notes |\n|--------|----------|---------|-----------|-------|\n| `writeMode` | `AgentDB` | `\"immediate\"` | write throughput is the bottleneck (switch to `\"group\"` for ~12x, `\"async\"` for ~50x) | `\"group\"` / `\"async\"` require single-writer; `\"async\"` loses unflushed ops on crash |\n| `groupCommitSize` | `AgentDB` | `50` | group-commit batches are too small (raise) or latency per op is too high (lower) | Only effective when `writeMode: \"group\"` |\n| `groupCommitMs` | `AgentDB` | `100` | you need lower write latency at the cost of smaller batches (lower) or higher throughput at higher latency (raise) | Only effective when `writeMode: \"group\"` |\n\n### Memory and budget knobs\n\n| Option | Location | Default | Tune when… | Notes |\n|--------|----------|---------|-----------|-------|\n| `memoryBudget` | `AgentDB` | `0` (unlimited) | you want a `console.warn` when total collection memory exceeds a threshold | Set in bytes; `0` disables the check; check fires at mutation time via the memory monitor |\n\n### HTTP / MCP server knobs\n\n| Option | Location | Default | Tune when… | Recommended range |\n|--------|----------|---------|-----------|-------------------|\n| `maxSessions` | `HttpOptions` | `100` | multi-agent orchestrators fan out more than 100 concurrent connections | 10 – 1000 |\n| `sessionIdleMs` | `HttpOptions` | `1_800_000` (30 min) | agents hold long-lived idle connections (raise) or session memory is expensive (lower) | 60K – 86_400_000 |\n| `auditBufferSize` | `HttpOptions` | `10_000` | audit entries are silently dropped (observable via log volume drops) | 1K – 100K |\n\n### Observability\n\nUse `col.metrics()` to read live counters without any instrumentation cost:\n\n```typescript\nconst m = col.metrics();\n// Filter cache hit rate — low values mean filterCacheSize should be raised\nconsole.log(m.filterCacheHits / (m.filterCacheHits + m.filterCompilations));\n// Disk LRU hit rate — low values mean cacheSize should be raised\nconsole.log(m.recordCacheHits / m.recordCacheFetches);\n// findTruncations — non-zero means some queries hit the maxFindLimit cap\nconsole.log(m.findTruncations);\n// Index sizes\nconsole.log(m.bm25SegmentCount, m.hnswNodeCount, m.walRecordCount, m.parquetRowGroups);\n// BM25 detail — doc count (flushed) and whether a merge pass would reduce segment count\nconsole.log(m.bm25DocCount, m.bm25NeedsMerge);\n// Write mode this collection is running under\nconsole.log(m.writeMode);\n```\n\n**Verifying configuration changes:** after adjusting a knob (e.g. raising `cacheSize` or `filterCacheSize`), call `col.metrics()` after a warm-up period of representative traffic. Compare `recordCacheHits / recordCacheFetches` or `filterCacheHits / (filterCacheHits + filterCompilations)` before and after to confirm the new limit is having the intended effect. All counters are lifetime values since the collection was opened.\n\n## Limits and Ceilings\n\nEvery hard cap in the system, what triggers it, and how to change it.\n\n| Cap | Default | What triggers it | Effect | How to change |\n|-----|---------|-----------------|--------|---------------|\n| `maxFindLimit` | `10_000` | `find()` called with `limit` exceeding the cap | Result is truncated (`truncated: true`); `console.warn` printed; `metrics().findTruncations` incremented | `CollectionOptions.maxFindLimit` or `AgentDBOptions.maxFindLimit` |\n| `maxIndexCardinality` | `1_000` | Field cardinality exceeds threshold at index load | B-tree index for that field is skipped; queries fall back to full Parquet scan; `console.warn` printed once per field | `CollectionOptions.maxIndexCardinality` or `AgentDBOptions.maxIndexCardinality` |\n| `maxSessions` | `100` | 101st concurrent MCP HTTP session arrives | HTTP 503 returned | `HttpOptions.maxSessions` |\n| `auditBufferSize` | `10_000` | 10,001st audit log entry recorded | Oldest entry silently dropped (ring buffer) | `HttpOptions.auditBufferSize` |\n| `auditMaxLimit` | `10_000` | `/audit?limit=N` with N exceeding cap | `limit` silently capped at maximum | `HttpOptions.auditMaxLimit` |\n| `mergeParquetThreshold` | `10` | 10 incremental Parquet files accumulate before compaction | Full merge triggered on next close | `AgentDB/CollectionOptions.mergeParquetThreshold` |\n| `mergeJsonlThreshold` | `8` | 8 incremental JSONL delta files accumulate | Full merge triggered on next close | `AgentDB/CollectionOptions.mergeJsonlThreshold` |\n\n**Removed in v2.0:** the 256 MB per-collection text index cap (~25–30K document ceiling) is gone. termlog uses a segment-based LSM with no in-memory size limit.\n\n## Migration from v1.4\n\nv2.0 replaces the in-house `TextIndex` JSON blob with `@backloghq/termlog` (segment-based LSM). The change is automatic for new collections. Existing collections that have a v1.4 BM25 index on disk require a one-time rebuild.\n\n**Detection:** on the first open with `textSearch: true`, AgentDB checks for `indexes/text-index.json` (v1.4 format) without a termlog manifest. If found, it throws `LegacyTextIndexError` (exported from core) with a `legacyPath` field pointing at the old file.\n\n**Rebuild via library API:**\n\n```typescript\nimport { AgentDB, LegacyTextIndexError, defineSchema } from \"@backloghq/agentdb\";\n\nconst schema = defineSchema({ name: \"notes\", textSearch: true, fields: { ... } });\nconst db = await AgentDB.open(\"./data\");\n\ntry {\n  await db.collection(schema);\n} catch (e) {\n  if (e instanceof LegacyTextIndexError) {\n    await db.rebuildTextIndex(\"notes\");  // re-indexes all records into a fresh TermLog\n    await db.collection(schema);         // succeeds now\n  }\n}\n```\n\n**Disk space:** in FS mode, `rebuildTextIndex` builds the new index in `text.new/` while the original `text/` remains intact and queryable. Both directories coexist until the atomic rename swap completes — plan for ~2× your current text-index size in free disk space during the rebuild. In S3 mode, the old index is wiped before rebuilding (no rename is possible for blob stores).\n\n**Write safety:** records inserted, updated, or deleted during an in-flight rebuild are captured in the new index. Concurrent `bm25Search` calls during a rebuild are safe — they read from the old index until the swap completes.\n\n**Rebuild via MCP tool** (no code change required):\n\n```json\n{ \"name\": \"db_rebuild_text_index\", \"arguments\": { \"collection\": \"notes\" } }\n```\n\nReturns `{ rebuiltDocCount: N }`. Requires admin permission.\n\n**What's new in v2.2.1:**\n- **MCP HTTP CORS** allows the spec-required `MCP-Protocol-Version` request header and exposes `Mcp-Session-Id` to browser fetch clients (origin policy unchanged — still configurable via `--cors` / `AGENTDB_HTTP_CORS` / `http.cors`).\n- **`db_archive_list` returns `Array<{ name, recordCount }>`** for admin/operator views. Pass `details:false` to skip per-segment loads (`recordCount: -1` sentinel) for fast names-only listing. New `Collection.listArchiveSegmentsDetailed()` library method; existing `listArchiveSegments(): string[]` unchanged.\n- **`db.import()` / `db_import` returns structured `ImportResult`** — `{ collections, records, inserted, overwritten, skipped, errors[] }` instead of `{ collections, records }`. Records without `_id` are now counted under `skipped` (previously dropped silently); per-record insert/upsert throws are captured in `errors[]` instead of aborting. New `ImportResult` type exported.\n- **`db_import` MCP tool emits `notifications/progress`** when the client supplies `progressToken` in `_meta`. The library `db.import()` already supported `onProgress`; the MCP tool now forwards each event as a JSON-RPC progress notification with `{ progressToken, progress, total }`.\n\n**What's new in v2.2:**\n- **Bloom filter query planner integration** — equality predicates (`{ field: value }`, `$eq`, `$in`) auto-consult `mightHave` and short-circuit definite-misses to empty result before scan. Bloom filters now bound to the field's index; the planner picks structural indexes (B-tree, composite, array) first and only falls to bloom when no structural match. False positives fall through to scan correctly.\n- **`HnswOptions.persistEvery`** — configurable periodic flush of the HNSW graph sidecar for bounded crash exposure on long-running ingest. Default `undefined` (close-only, v2.1.1 behavior). Pair with `persistTimeoutMs` to bound non-close-time waits on slow backends.\n- **Composite + bloom durable persistence** — `<dir>/indexes/composite-{fields}.json` and `<dir>/indexes/bloom-{field}.json` mirror the existing B-tree/array persistence pattern. Lazy load on first use; v2.1.1 disk-iter populate retained as fallback. Field-set validation guards against filename collisions.\n- **HNSW determinism via `seed`** propagated correctly through `CollectionOptions.hnsw.seed` and `AgentDBOptions.hnsw.seed` (latent omission in v2.1.1 fixed).\n- **Bloom maintenance fixes** in `IndexManager.updateIndexes`/`rebuildAll`/`incrementalUpdate` — bloom filters now correctly track post-creation inserts/updates/deletes (was silent stale state pre-v2.2).\n- **Diagnostic warnings** on corrupt JSON / non-ENOENT errors when loading persisted indexes (was silent fall-back).\n- **Targeted leak bench scenario N** for bloom `mightHave()` latency, plus scenario O for HNSW `persistEvery` write-amplification ratio.\n\nKnown issue: HNSW `graph.bin` sidecar persists to local FS regardless of backend; in S3 deployments with ephemeral container FS, the sidecar is lost on restart and HNSW rebuilds from quantized embeddings (no data loss, just slower cold start). S3-native sidecar deferred to v2.3.\n\n**What's new in v2.1.1 (patch):**\n- HNSW graph persistence — disk-mode collections now persist the graph to `<dir>/hnsw/graph.bin` on close and load it on reopen, eliminating the O(N) rebuild for embedded collections\n- HNSW determinism — new `HnswOptions.seed` for reproducible layer assignments across processes\n- `bm25DocCount` no longer inflates 2× after the first BM25 search in a session\n- Composite and bloom indexes now populate from disk on reopen (were silently empty in disk mode)\n- Five memory-leak fixes (HNSW orphans on delete, MemoryMonitor LRU cleanup, close() listener teardown, subscription pin-while-subscribed, S3 rebuild close interlock)\n- Targeted leak regression bench (`npm run bench:leak`) gated by CI\n\n**What's new in v2.1:**\n- `AgentDB.open(dir, opts)` static factory — async one-call entry point; replaces the `new AgentDB(...); await db.init()` two-step\n- Lazy auto-init — calling `db.collection(...)` without explicit `init()` now Just Works\n- Configuration: optional `agentdb.config.json` + 47 `AGENTDB_*` env vars for the MCP CLI (precedence CLI > env > file > defaults)\n- Per-collection overrides via `collectionOverrides` (db-wide) or the config file's `collections` block\n- Production-readiness knobs: `maxFindLimit`, `maxIndexCardinality`, `mergeParquetThreshold`, `mergeJsonlThreshold`, `filterCacheSize`, HNSW `M`/`efConstruction`/`efSearch`/`maxLevel`, `maxSessions`/`sessionIdleMs`, audit buffer/limits\n- Ergonomics: `onProgress` callbacks for `reembedAll`/`rebuildTextIndex`/`db_import`; `AbortSignal` for `find`, `reembedAll`, `rebuildTextIndex`; `col.metrics()` for cache hit-rate / index usage / BM25 segment count / write mode\n- Auth hardening: JWT secret minimum 32 bytes (HS256 RFC 7518); auth precedence (JWT > multi-token > bearer) with conflict warn\n- `rebuildTextIndex` now uses snapshot-then-swap with concurrent-write capture and crash recovery — runs safely against live collections (FS mode)\n\nSee [MIGRATION-2.0.md](./MIGRATION-2.0.md#new-in-v21) for the full v2.1 list and [CHANGELOG.md](./CHANGELOG.md) for the detailed entry.\n\n**What's new in v2.0:**\n- No per-collection document cap (256 MB / ~25–30K doc ceiling is gone)\n- S3-backed text indexes via `@backloghq/termlog-s3` (auto-wired when opslog uses S3)\n- Segment-based LSM — writes never block reads; compaction happens in the background\n- BM25 scores are deterministic across close/reopen (WAL replay double-count bug fixed)\n\n**S3 text search** — install the optional peer dependency:\n\n```bash\nnpm install @backloghq/termlog-s3\n```\n\nText indexes are then automatically stored in S3 alongside opslog data. No configuration needed beyond the existing S3 backend setup.\n\n## Examples\n\nSee [examples/](./examples/) for runnable demos powered by Ollama:\n\n- **[Multi-Agent Task Board](./examples/multi-agent/)** — Agents collaborate on a shared task board. Event-driven via NOTIFY/LISTEN.\n- **[RAG Knowledge Base](./examples/rag-knowledge-base/)** — Ingest docs, embed with Ollama, answer questions via hybrid search (BM25 + semantic, fused via RRF). Updated for v2.0.\n- **[Research Pipeline](./examples/research-pipeline/)** — 3-stage AI pipeline: Researcher → Analyst → Writer. Each stage triggers the next.\n- **[Multi-Model Code Review](./examples/code-review/)** — Gemini generates code, Ollama reviews locally, Gemini writes tests. Multi-provider orchestration. Updated for v2.0: shows schema lifecycle (`defineSchema` with description/instructions/field descriptions, auto-persistence, `db_get_schema` discovery).\n- **[Live Dashboard](./examples/live-dashboard/)** — Real-time CLI view of any running demo's collections.\n\n## Development\n\n```bash\nnpm run build          # tsc\nnpm run lint           # eslint src/ tests/\nnpm test               # vitest run\nnpm run test:coverage  # vitest coverage\n```\n\nBuilt on [@backloghq/opslog](https://github.com/backloghq/opslog) -- every mutation is an operation in an append-only log. You get crash safety, undo, and audit trails for free.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}