Compare commits
626 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cbe492dde3 | |||
| 0fb6f3cf4e | |||
| 5cd68f4a96 | |||
| 10a8598aac | |||
| 19af455c57 | |||
| b5807aed2e | |||
| c6fd984cc1 | |||
| 490ba182d5 | |||
| 4baed97bd0 | |||
| f41824fa59 | |||
| 80ba7633e5 | |||
| d14266d70a | |||
| 1cd545c36c | |||
| 901af0b7f7 | |||
| 6815cc55b8 | |||
| 12603a1a5c | |||
| 15d05b5ac7 | |||
| bf4a20223a | |||
| a549d9fe47 | |||
| e896cfa0c5 | |||
| 5d4e71d2ff | |||
| f923c0cdd5 | |||
| 1491123706 | |||
| 9f1745bdec | |||
| d25b1d7394 | |||
| f6351434ae | |||
| ef9716eb5c | |||
| 6ebb678306 | |||
| 25684ea8f7 | |||
| 147b2c5aa5 | |||
| f154e32145 | |||
| 013fe9423e | |||
| f50a005cef | |||
| d24d5dda04 | |||
| 50c7603a37 | |||
| 807d1d6100 | |||
| ded9671a82 | |||
| b8a9f366e7 | |||
| 83b0f9551b | |||
| 8bf22b3dc5 | |||
| f8108047c4 | |||
| e4bd0ae461 | |||
| b39cf84730 | |||
| 772e235e92 | |||
| 0986301e7a | |||
| 822cf796e1 | |||
| 53314d9c38 | |||
| 3a1ed0d299 | |||
| 8c589b6265 | |||
| 8bdec6abc0 | |||
| 41fbb87aa0 | |||
| fb9cccd350 | |||
| 9387418707 | |||
| eaba21329c | |||
| 84c4d62812 | |||
| 9e9ff20cba | |||
| bc28891bca | |||
| bafc86832c | |||
| b985579959 | |||
| 5f36d2bf9a | |||
| 65e5411c21 | |||
| 7a22144069 | |||
| 1360195390 | |||
| 6b38be29fb | |||
| f992251c32 | |||
| c2015c4dfc | |||
| 005a80c540 | |||
| c3761a2204 | |||
| d957bff495 | |||
| c5ee27f001 | |||
| d9f3798c90 | |||
| 1fb8df42b6 | |||
| e09e64ade5 | |||
| 7cab32151e | |||
| a2f7a4dc5a | |||
| fc5c2d5e07 | |||
| b22adcca05 | |||
| 2adc830c71 | |||
| e2c8f6b99e | |||
| 280608574b | |||
| 291f43d2c7 | |||
| d7dc29498c | |||
| 1f2e5f1a9c | |||
| 679a077f9b | |||
| f7a80e6abc | |||
| 4321add69c | |||
| 105b4ca70d | |||
| 06ba1cd92c | |||
| b003a43e73 | |||
| 5210bc74c7 | |||
| a00ca2b3ec | |||
| ba2c098ec1 | |||
| 5550ecf623 | |||
| 9a27f380c3 | |||
| 577cac8831 | |||
| 8da92c6569 | |||
| a18b43744c | |||
| 7c4979eba1 | |||
| ffe1e1622d | |||
| 8cfa04f93d | |||
| deef86380f | |||
| aa1e65cbb6 | |||
| 9192bb6f21 | |||
| 512486bd85 | |||
| b9814e87f4 | |||
| 54c53fda04 | |||
| f494d3b168 | |||
| 9cb4b9d02a | |||
| 922f04e66a | |||
| b1fb135d9c | |||
| 476f81ceca | |||
| 34ba526fa8 | |||
| efcc557e4f | |||
| 0a34786df9 | |||
| 7175b527a6 | |||
| c415ff5120 | |||
| 83b4806718 | |||
| cb1d939750 | |||
| 9855ccf66d | |||
| 85f30126aa | |||
| 225424a19e | |||
| 2e67821445 | |||
| bbed39c71b | |||
| 3aaee6f13a | |||
| 795a430f1a | |||
| 0a667afc0f | |||
| 8e0b1ee4e1 | |||
| d3aaef926b | |||
| 42fde819a3 | |||
| 4eeb8391c6 | |||
| 213557dd6e | |||
| e1d2ffeb02 | |||
| 9e66a4843e | |||
| 0a3b50c875 | |||
| a8d31d465f | |||
| 186f54b3fd | |||
| be28c095e2 | |||
| 28305f73bb | |||
| c6708b3684 | |||
| 375dd1c3d6 | |||
| c78500cac2 | |||
| 2b683f99bb | |||
| 00e2b0c55f | |||
| fbd4df4285 | |||
| ca24048e15 | |||
| f9fd85fa4d | |||
| bc7e0ba3e0 | |||
| cbfc94bc26 | |||
| c768a80bf0 | |||
| 6dc648f07c | |||
| b116681529 | |||
| d1876cb6e0 | |||
| e1017b483b | |||
| 8d5b886f63 | |||
| 6e8d823139 | |||
| e1212d2dd9 | |||
| d3ae18434f | |||
| 8bdf228a92 | |||
| 2b223b7cd9 | |||
| 7cad4f0114 | |||
| 41835954be | |||
| 2431a1bd9e | |||
| 7fd0f28343 | |||
| 50535499d9 | |||
| 4eb6557fbb | |||
| a22098d661 | |||
| 69b17e15a2 | |||
| de279ef6bf | |||
| c6fed386ef | |||
| ffcd7d21b3 | |||
| efb7507a8f | |||
| 01b3103567 | |||
| 4739b9e413 | |||
| 45acdf84c1 | |||
| 03b85d2af2 | |||
| 03fefca884 | |||
| 01be3156fb | |||
| a48a67ca76 | |||
| 155465f52a | |||
| 0a70bcecc5 | |||
| 4e5913611a | |||
| 73982dc709 | |||
| 93de6d97f5 | |||
| 29e6e026b6 | |||
| 1b394cdf4e | |||
| 6ffa4cfde5 | |||
| 8caf159d99 | |||
| 2a2206d886 | |||
| e3a63c0294 | |||
| 634033b730 | |||
| 54ef1496d2 | |||
| 5d23c60b76 | |||
| 9314ede6e9 | |||
| 58f4053a61 | |||
| a08e5068c8 | |||
| 9f1b653f2f | |||
| c5d89142b9 | |||
| b44d4702b1 | |||
| 4988b4b317 | |||
| c5e68a17c8 | |||
| f35764aa14 | |||
| 601bded789 | |||
| c231e8d076 | |||
| b62e93577c | |||
| 0787e47b1a | |||
| f9843fe593 | |||
| 5b772ee768 | |||
| baabf14bfa | |||
| c126a7083f | |||
| f1170512d6 | |||
| 6c9a8d1dca | |||
| d64939c379 | |||
| 97d8bd3e62 | |||
| 6cd904a81c | |||
| 74c8afd0e0 | |||
| 02444392da | |||
| d175f1759c | |||
| d55db524f0 | |||
| 7d44fdb289 | |||
| 812de2940d | |||
| 95edf31c14 | |||
| a9ae89a198 | |||
| 047914d087 | |||
| bdf79a439b | |||
| 99b6b85d67 | |||
| 798dec972e | |||
| 286343fef6 | |||
| 9285826547 | |||
| ce3b3733fa | |||
| cf1c966409 | |||
| 02fef487e7 | |||
| 20d45006c0 | |||
| 4f1cd309fd | |||
| c46e4a341a | |||
| 60d5f8fbf1 | |||
| c0778bef00 | |||
| 3cbc041c8b | |||
| 0f96476987 | |||
| cd6f883020 | |||
| 9fb7383ab3 | |||
| e8e7fc81af | |||
| e3283c2a1d | |||
| 581e940659 | |||
| 915dbc1aa9 | |||
| 5a84198529 | |||
| f5b25e8fc4 | |||
| 7d1e6af5c5 | |||
| 8b4cc4f6bf | |||
| 68290a9121 | |||
| ab5d78717f | |||
| cb4aea57a8 | |||
| 7bdf6dbfe1 | |||
| 1c9da73d5f | |||
| 5f7aa0710e | |||
| 39fedfc5fc | |||
| ecb8b39f6d | |||
| fe0902b48f | |||
| 4ab9739e4c | |||
| 6ddef1093a | |||
| 97d565e3cd | |||
| eafdd6a7be | |||
| 3529f9274b | |||
| 30ebe92a53 | |||
| 1bb203cbb5 | |||
| 9f8499fe54 | |||
| 40d105d7de | |||
| cda12d95c9 | |||
| bbd6113f69 | |||
| 51d1315562 | |||
| 85763d575d | |||
| c76ddc2f83 | |||
| 348cc7f7ac | |||
| ed19e92f75 | |||
| 2a96214456 | |||
| eaa2268bf9 | |||
| 730c420a13 | |||
| d0bdc6ae9b | |||
| d46fbb7166 | |||
| a60ef6eacb | |||
| 13941a1e72 | |||
| bd809c860e | |||
| b4b90faa1e | |||
| 9e235b5b57 | |||
| 5fdf25d60f | |||
| a367436a78 | |||
| 5d64df2ba5 | |||
| 22a04ac461 | |||
| 170b66f623 | |||
| ca4f046777 | |||
| 0475a57fb1 | |||
| fda069bb07 | |||
| 4c1f7b4ff1 | |||
| 35b98c53f0 | |||
| e029903a66 | |||
| 5666f7dd1c | |||
| 57f0c9fd92 | |||
| 5482052c16 | |||
| ccb7001ff0 | |||
| edc20a12a1 | |||
| 45c35c6bdd | |||
| 47ee0838e3 | |||
| 809c9e6639 | |||
| 9646527d66 | |||
| f27c73b469 | |||
| 7f9959fdb7 | |||
| 012774b83c | |||
| e22edaddf4 | |||
| 6204fe9b9d | |||
| 30a42036aa | |||
| d6f1237283 | |||
| 700e3253fa | |||
| 740d65b5a5 | |||
| 4bc467f7ed | |||
| 7fdfdd5d5e | |||
| e872c2da38 | |||
| 13643a5b18 | |||
| 980151a50e | |||
| 9eddc51979 | |||
| 7c3477b7e1 | |||
| f45c782c07 | |||
| 3bdf0b41bc | |||
| 3030f518b5 | |||
| 0b476e971a | |||
| f7b51a963e | |||
| f8dc7f940f | |||
| b68ea38bcc | |||
| 12459eab3b | |||
| 5e6ef4aeb1 | |||
| f46b5b452f | |||
| 2af8db6b82 | |||
| 6a4fa85c10 | |||
| 22f4655a8c | |||
| 79ff1849f0 | |||
| ff28db9d76 | |||
| 268b78083e | |||
| a1f76af902 | |||
| d5e392ea69 | |||
| 66ee9395cb | |||
| 7e75c0b22f | |||
| c506390007 | |||
| f8695516a4 | |||
| 0127c7639a | |||
| 6e66d78825 | |||
| 0b4cfcbe56 | |||
| c8a9486832 | |||
| 9fb43d8b06 | |||
| 1b9cec2a95 | |||
| ddec9835d2 | |||
| 2d97ffc9a8 | |||
| d8886619b8 | |||
| 280cb2fe54 | |||
| c8a206b682 | |||
| c03457d2d4 | |||
| a46a028ddb | |||
| 37f836b719 | |||
| bc8bc10b0b | |||
| 5169cfa46d | |||
| 03ba89b703 | |||
| 263a8d4c18 | |||
| b25b312bf3 | |||
| 633f89a5fb | |||
| c6bf72ca72 | |||
| bda39733e0 | |||
| 80935fbc66 | |||
| bcfd036dfe | |||
| ebf53e9fb0 | |||
| 7133108f15 | |||
| f20bb5bced | |||
| e238a81b34 | |||
| 9215c7e1f5 | |||
| b694f233db | |||
| 02130c49d1 | |||
| c9e0301e3e | |||
| 65c89ea2f0 | |||
| 9a9b00c6d8 | |||
| 309e8a7139 | |||
| 867226c19d | |||
| 192adf5cbc | |||
| 140a5f3469 | |||
| 5c4b44d4c7 | |||
| 3bbacb8fa4 | |||
| d69a95bd29 | |||
| 90b209081c | |||
| 6d145c035c | |||
| bd5ad6e5c2 | |||
| 28005b75af | |||
| 322f81e515 | |||
| ea54a03fae | |||
| 15c55a57a3 | |||
| 056cd12558 | |||
| b0fae0cfd4 | |||
| 44b69b737b | |||
| 56213ef84a | |||
| 64dfc0467d | |||
| c75563a89b | |||
| fb00b517c0 | |||
| df44bd8fd3 | |||
| e9c0ec45db | |||
| d363dfd668 | |||
| c06abbc6f2 | |||
| f499810c7a | |||
| 609d8f5c88 | |||
| 5ebf6c8aec | |||
| d94a11e2e1 | |||
| d4d6185bb4 | |||
| 2df50bcaa0 | |||
| 19ecc7845f | |||
| 142d6ae56f | |||
| 7db39bb482 | |||
| e600a0f702 | |||
| b87654d452 | |||
| a3b0b70a98 | |||
| 81f8aa7eef | |||
| 8f8649c2a8 | |||
| ab0938633a | |||
| d8d4d2464f | |||
| 9d32629f9d | |||
| 6a007a26fe | |||
| 6131f9694a | |||
| 22777bdcfe | |||
| d7946522e9 | |||
| 43262d7b53 | |||
| 80fc1588d3 | |||
| 70ba785364 | |||
| 7fb990f845 | |||
| 9f3bf55c76 | |||
| 83d9747627 | |||
| ae2c789781 | |||
| 81d7ab59ac | |||
| e82d9e075b | |||
| 99af5fdf13 | |||
| b88ce840fa | |||
| 516e136966 | |||
| 051bc8dd67 | |||
| 05ddf3540c | |||
| e18f02e2af | |||
| 77885db345 | |||
| 50d504715d | |||
| 28d9c43f85 | |||
| adc5853c73 | |||
| 81fdf28347 | |||
| b3a565c448 | |||
| 5b28c23b20 | |||
| f4217cb2b9 | |||
| e7252c8999 | |||
| 74637705d7 | |||
| 322cb94c43 | |||
| 21c7ab2929 | |||
| 3846d66ccc | |||
| 817a069323 | |||
| d7b9f68d80 | |||
| c48290a156 | |||
| 226a52f8b8 | |||
| 93b5f80168 | |||
| f6cf895847 | |||
| dba29de2a7 | |||
| c16f453017 | |||
| 8b4c962e62 | |||
| 12149470a2 | |||
| fd4cd0444c | |||
| 0adbf38c39 | |||
| 15362d1aed | |||
| c04e5c571c | |||
| 66a69f3044 | |||
| e50c6142bb | |||
| 8d5bfec90e | |||
| ab2c44069b | |||
| babb375955 | |||
| 334fbdd913 | |||
| 4a269183a3 | |||
| 37cd8b8328 | |||
| 33d2422faa | |||
| dad3a104b4 | |||
| bcad4c484d | |||
| 4284b31f42 | |||
| f556546994 | |||
| 6441d9103c | |||
| 2952b7fb8d | |||
| 63f930a433 | |||
| 3cb003f4e4 | |||
| 8b5e5efeb5 | |||
| a57aba82a4 | |||
| 7b7a53ee19 | |||
| e57bfc4187 | |||
| 3cfdd5fd65 | |||
| 1a226b08f0 | |||
| 15b5176fe6 | |||
| 418dc963b2 | |||
| 2314362028 | |||
| f373b682dd | |||
| 1c25c3a7e7 | |||
| 3ca5e33b4a | |||
| 3042de1093 | |||
| f7f62ef3f3 | |||
| 726f167ebf | |||
| a62887a6e0 | |||
| 635cc87462 | |||
| c27f07023c | |||
| e073c0b75f | |||
| 562194612e | |||
| 02bce8a6e6 | |||
| e9bcb7e9db | |||
| 86214b93a9 | |||
| ef572ec032 | |||
| 3cb99ab7f4 | |||
| 20136121d8 | |||
| df0f3fd96c | |||
| fe861a85bd | |||
| 32f45a1100 | |||
| 1ea692e0b0 | |||
| 861cd20adf | |||
| d275715974 | |||
| fd4684dcb3 | |||
| c54e50ec0c | |||
| c42444e06c | |||
| cb2f2a0432 | |||
| 692bb07dfe | |||
| 58e9dcc0fc | |||
| f60ee3b4f5 | |||
| 7ed166323c | |||
| 651989c423 | |||
| 9dd8b180ac | |||
| 9b1d801a46 | |||
| 6fb9570291 | |||
| ae90b26995 | |||
| 3b0cd0b3f6 | |||
| f849a69506 | |||
| daf368e343 | |||
| cbd43240c7 | |||
| 47c1398ce7 | |||
| b44359c136 | |||
| be0ab12789 | |||
| 7ff611feb5 | |||
| cf9d1d4a0b | |||
| 9149acf4d1 | |||
| 002f7a94b8 | |||
| 6d68fd44ca | |||
| bc41e367c0 | |||
| c41c4b21ea | |||
| 5dd663730b | |||
| 56167c47a2 | |||
| 115270c35e | |||
| c27682c799 | |||
| 1fbba55aa3 | |||
| 05f3889deb | |||
| 874815770a | |||
| d452913487 | |||
| 635f456ecf | |||
| 81101ef1a6 | |||
| 938eb9dc0e | |||
| a11199a527 | |||
| 015b38c763 | |||
| be936d8413 | |||
| d4a71c994d | |||
| 372854948c | |||
| d6462919cb | |||
| ec79e085b2 | |||
| cedb635176 | |||
| 6f62a569df | |||
| 7c5e5b1941 | |||
| 8e460a8c2a | |||
| 18d5e0d3bb | |||
| 3e617a8b1e | |||
| 307c87b9f6 | |||
| 2d080b0264 | |||
| 834cf4095e | |||
| 723f1f5374 | |||
| 5f05f991bc | |||
| b44853fb2c | |||
| 29aa945ae0 | |||
| f2551ac366 | |||
| 2ba840aaac | |||
| eddb321489 | |||
| 6e9be84a01 | |||
| 18aa4f2538 | |||
| 4489249ecc | |||
| 2608fb180e | |||
| edeed2ee2c | |||
| 01b477da26 | |||
| 58a9554bb3 | |||
| 29f1cb3b4c | |||
| 7307563cfe | |||
| 047298a183 | |||
| 78fd1368db | |||
| d07a40616d | |||
| e81ea69143 | |||
| 917ab9740c | |||
| b43b7f02ae | |||
| d989ba62f9 | |||
| 87f26d7b0d | |||
| 7fac3e3bb6 | |||
| 2663121d9f | |||
| b5bfc029c3 | |||
| 5886fe7d8f | |||
| 5f15695c3f | |||
| c49533c250 | |||
| 4f49cb1bc9 | |||
| 874726b193 | |||
| 5244a12422 | |||
| 5b30764fa8 | |||
| 85ed7c3d2f | |||
| 4d5b307a74 | |||
| 68566b556c | |||
| b0032c1745 | |||
| 35b7aab174 | |||
| 2601215c91 | |||
| 4ebf0cad6b | |||
| 98d959112c | |||
| d01c2afaa6 | |||
| 8ebcb55b0d | |||
| 97807494fd | |||
| c4eb2e2dc9 | |||
| f0c3bf18b0 | |||
| 3eaae66bc4 | |||
| 27d1cd405f | |||
| 267965a065 | |||
| 181aca0215 | |||
| b6eef0145f | |||
| a1bc421fea | |||
| 502b3894d7 | |||
| 8e9005d9c3 | |||
| 7978f84f6c | |||
| f1f578c6fb | |||
| aae7de8e05 | |||
| 4da61a77c7 | |||
| 4fbb25e385 |
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "thedotmack",
|
||||
"owner": {
|
||||
"name": "Alex Newman"
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Plugins by Alex Newman (thedotmack)",
|
||||
"homepage": "https://github.com/thedotmack/claude-mem"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "7.1.3",
|
||||
"source": "./plugin",
|
||||
"description": "Persistent memory system for Claude Code - context compression across sessions"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"env": {},
|
||||
"permissions": {
|
||||
"deny": [
|
||||
"Read(./package-lock.json)",
|
||||
"Read(./node_modules/**)",
|
||||
"Read(./.DS_Store)"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
# Project-Level Skills
|
||||
|
||||
This directory contains skills **for developing and maintaining the claude-mem project itself**, not skills that are released as part of the plugin.
|
||||
|
||||
## Distinction
|
||||
|
||||
**Project Skills** (`.claude/skills/`):
|
||||
- Used by developers working on claude-mem
|
||||
- Not included in the plugin distribution
|
||||
- Project-specific workflows (version bumps, release management, etc.)
|
||||
- Not synced to `~/.claude/plugins/marketplaces/thedotmack/`
|
||||
|
||||
**Plugin Skills** (`plugin/skills/`):
|
||||
- Released as part of the claude-mem plugin
|
||||
- Available to all users who install the plugin
|
||||
- General-purpose memory search functionality
|
||||
- Synced to user installations via `npm run sync-marketplace`
|
||||
|
||||
## Skills in This Directory
|
||||
|
||||
### version-bump
|
||||
Manages semantic versioning for the claude-mem project itself. Handles updating all four version files (package.json, marketplace.json, plugin.json, CLAUDE.md), creating git tags, and GitHub releases.
|
||||
|
||||
**Usage**: Only for claude-mem maintainers releasing new versions.
|
||||
|
||||
## Adding New Skills
|
||||
|
||||
**For claude-mem development** → Add to `.claude/skills/`
|
||||
**For end users** → Add to `plugin/skills/` (gets distributed with plugin)
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
name: version-bump
|
||||
description: Manage semantic version updates for claude-mem project. Handles patch, minor, and major version increments following semantic versioning. Updates package.json, marketplace.json, plugin.json, and CLAUDE.md version number (NOT version history). Creates git tags and GitHub releases. Auto-generates CHANGELOG.md from releases.
|
||||
---
|
||||
|
||||
# Version Bump Skill
|
||||
|
||||
Manage semantic versioning across the claude-mem project with consistent updates to all version-tracked files.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
**Files requiring updates (ALL FOUR):**
|
||||
1. `package.json` (line 3)
|
||||
2. `.claude-plugin/marketplace.json` (line 13)
|
||||
3. `plugin/.claude-plugin/plugin.json` (line 3)
|
||||
4. `CLAUDE.md` (line 9 ONLY - version number, NOT version history)
|
||||
|
||||
**Semantic versioning:**
|
||||
- **PATCH** (x.y.Z): Bugfixes only
|
||||
- **MINOR** (x.Y.0): New features, backward compatible
|
||||
- **MAJOR** (X.0.0): Breaking changes
|
||||
|
||||
## Quick Decision Guide
|
||||
|
||||
**What changed?**
|
||||
- "Fixed a bug" → PATCH (5.3.0 → 5.3.1)
|
||||
- "Added new feature" → MINOR (5.3.0 → 5.4.0)
|
||||
- "Breaking change" → MAJOR (5.3.0 → 6.0.0)
|
||||
|
||||
**If unclear, ASK THE USER explicitly.**
|
||||
|
||||
## Standard Workflow
|
||||
|
||||
See [operations/workflow.md](operations/workflow.md) for detailed step-by-step process.
|
||||
|
||||
**Quick version:**
|
||||
1. Determine version type (PATCH/MINOR/MAJOR)
|
||||
2. Calculate new version from current
|
||||
3. Preview changes to user
|
||||
4. Update ALL FOUR files
|
||||
5. Verify consistency
|
||||
6. Build and test
|
||||
7. Commit and create git tag
|
||||
8. Push and create GitHub release
|
||||
9. Generate CHANGELOG.md from releases and commit
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
See [operations/scenarios.md](operations/scenarios.md) for examples:
|
||||
- Bug fix releases
|
||||
- New feature releases
|
||||
- Breaking change releases
|
||||
|
||||
## Critical Rules
|
||||
|
||||
**ALWAYS:**
|
||||
- Update ALL FOUR files with matching version numbers
|
||||
- Create git tag with format `vX.Y.Z`
|
||||
- Create GitHub release from the tag
|
||||
- Generate CHANGELOG.md from releases after creating release
|
||||
- Ask user if version type is unclear
|
||||
|
||||
**NEVER:**
|
||||
- Update only one, two, or three files
|
||||
- Skip the verification step
|
||||
- Forget to create git tag or GitHub release
|
||||
- Add version history entries to CLAUDE.md (that's managed separately)
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
Before considering the task complete:
|
||||
- [ ] All FOUR files have matching version numbers
|
||||
- [ ] `npm run build` succeeds
|
||||
- [ ] Git commit created with all version files
|
||||
- [ ] Git tag created (format: vX.Y.Z)
|
||||
- [ ] Commit and tags pushed to remote
|
||||
- [ ] GitHub release created from the tag
|
||||
- [ ] CHANGELOG.md generated and committed
|
||||
- [ ] CLAUDE.md: ONLY line 9 updated (version number), NOT version history
|
||||
|
||||
## Reference Commands
|
||||
|
||||
```bash
|
||||
# View current version
|
||||
grep '"version"' package.json
|
||||
|
||||
# Verify consistency across all version files
|
||||
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
|
||||
|
||||
# View git tags
|
||||
git tag -l -n1
|
||||
|
||||
# Check what will be committed
|
||||
git status
|
||||
git diff package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json CLAUDE.md
|
||||
```
|
||||
|
||||
For more commands, see [operations/reference.md](operations/reference.md).
|
||||
@@ -0,0 +1,275 @@
|
||||
# Version Bump Reference
|
||||
|
||||
Quick reference for version bump commands and file locations.
|
||||
|
||||
## File Locations
|
||||
|
||||
### Version-Tracked Files (ALL FOUR)
|
||||
|
||||
1. **package.json**
|
||||
- Path: `package.json`
|
||||
- Line: 3
|
||||
- Format: `"version": "X.Y.Z",`
|
||||
|
||||
2. **marketplace.json**
|
||||
- Path: `.claude-plugin/marketplace.json`
|
||||
- Line: 13
|
||||
- Format: `"version": "X.Y.Z",`
|
||||
|
||||
3. **plugin.json**
|
||||
- Path: `plugin/.claude-plugin/plugin.json`
|
||||
- Line: 3
|
||||
- Format: `"version": "X.Y.Z",`
|
||||
|
||||
4. **CLAUDE.md**
|
||||
- Path: `CLAUDE.md`
|
||||
- Line: 9
|
||||
- Format: `**Current Version**: X.Y.Z`
|
||||
|
||||
## Essential Commands
|
||||
|
||||
### View Current Version
|
||||
|
||||
```bash
|
||||
# From package.json
|
||||
grep '"version"' package.json
|
||||
|
||||
# Extract just the version number
|
||||
grep '"version"' package.json | head -1 | sed 's/.*"version": "\(.*\)".*/\1/'
|
||||
|
||||
# From all version files
|
||||
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
|
||||
grep "Current Version" CLAUDE.md
|
||||
```
|
||||
|
||||
### Verify Version Consistency
|
||||
|
||||
```bash
|
||||
# Check all JSON files match
|
||||
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
|
||||
|
||||
# Should output identical version in all three:
|
||||
# package.json:3: "version": "5.3.0",
|
||||
# .claude-plugin/marketplace.json:13: "version": "5.3.0",
|
||||
# plugin/.claude-plugin/plugin.json:3: "version": "5.3.0",
|
||||
|
||||
# Check CLAUDE.md
|
||||
grep "Current Version" CLAUDE.md
|
||||
# Should output: **Current Version**: 5.3.0
|
||||
```
|
||||
|
||||
### Git Commands
|
||||
|
||||
```bash
|
||||
# View recent commits
|
||||
git log --oneline -5
|
||||
|
||||
# View changes since last tag
|
||||
LAST_TAG=$(git describe --tags --abbrev=0)
|
||||
git log $LAST_TAG..HEAD --oneline
|
||||
git diff $LAST_TAG..HEAD
|
||||
|
||||
# List all tags
|
||||
git tag -l
|
||||
|
||||
# View tag details
|
||||
git show vX.Y.Z
|
||||
|
||||
# List tags with messages
|
||||
git tag -l -n1
|
||||
```
|
||||
|
||||
### Build and Test
|
||||
|
||||
```bash
|
||||
# Build plugin
|
||||
npm run build
|
||||
|
||||
# Sync to marketplace
|
||||
npm run sync-marketplace
|
||||
|
||||
# Run tests (if available)
|
||||
npm test
|
||||
```
|
||||
|
||||
### Commit and Tag
|
||||
|
||||
```bash
|
||||
# Stage version files
|
||||
git add package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json CLAUDE.md plugin/scripts/
|
||||
|
||||
# Commit
|
||||
git commit -m "Release vX.Y.Z: [Description]"
|
||||
|
||||
# Create tag
|
||||
git tag vX.Y.Z -m "Release vX.Y.Z: [Description]"
|
||||
|
||||
# Push
|
||||
git push && git push --tags
|
||||
```
|
||||
|
||||
### GitHub Release
|
||||
|
||||
```bash
|
||||
# Create release
|
||||
gh release create vX.Y.Z --title "vX.Y.Z" --notes "[Release notes]"
|
||||
|
||||
# Create with auto-generated notes
|
||||
gh release create vX.Y.Z --title "vX.Y.Z" --generate-notes
|
||||
|
||||
# View release
|
||||
gh release view vX.Y.Z
|
||||
|
||||
# List all releases
|
||||
gh release list
|
||||
|
||||
# Delete release (if needed)
|
||||
gh release delete vX.Y.Z
|
||||
```
|
||||
|
||||
## Semantic Versioning Rules
|
||||
|
||||
### Version Format: MAJOR.MINOR.PATCH
|
||||
|
||||
**MAJOR (X.0.0):**
|
||||
- Breaking changes
|
||||
- Incompatible API changes
|
||||
- Schema changes requiring migration
|
||||
- Removes features
|
||||
|
||||
**MINOR (x.Y.0):**
|
||||
- New features (backward compatible)
|
||||
- New functionality
|
||||
- Deprecations (but not removals)
|
||||
- Resets PATCH to 0
|
||||
|
||||
**PATCH (x.y.Z):**
|
||||
- Bug fixes
|
||||
- Performance improvements
|
||||
- Documentation fixes
|
||||
- No new features
|
||||
|
||||
### Incrementing Rules
|
||||
|
||||
```
|
||||
PATCH: 5.3.2 → 5.3.3
|
||||
MINOR: 5.3.2 → 5.4.0 (resets patch)
|
||||
MAJOR: 5.3.2 → 6.0.0 (resets minor and patch)
|
||||
```
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Bug Fix Release
|
||||
|
||||
```bash
|
||||
# Example: 5.3.0 → 5.3.1
|
||||
# 1. Update all four files to 5.3.1
|
||||
# 2. Build and test
|
||||
npm run build
|
||||
# 3. Commit and tag
|
||||
git add package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json CLAUDE.md plugin/scripts/
|
||||
git commit -m "Release v5.3.1: Fixed observer crash"
|
||||
git tag v5.3.1 -m "Release v5.3.1: Fixed observer crash"
|
||||
git push && git push --tags
|
||||
# 4. Create release
|
||||
gh release create v5.3.1 --title "v5.3.1" --notes "Fixed observer crash on empty content"
|
||||
```
|
||||
|
||||
### Feature Release
|
||||
|
||||
```bash
|
||||
# Example: 5.3.0 → 5.4.0
|
||||
# 1. Update all four files to 5.4.0
|
||||
# 2. Build and test
|
||||
npm run build
|
||||
# 3. Commit and tag
|
||||
git add package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json CLAUDE.md plugin/scripts/
|
||||
git commit -m "Release v5.4.0: Added dark mode support"
|
||||
git tag v5.4.0 -m "Release v5.4.0: Added dark mode support"
|
||||
git push && git push --tags
|
||||
# 4. Create release
|
||||
gh release create v5.4.0 --title "v5.4.0" --generate-notes
|
||||
```
|
||||
|
||||
### Breaking Change Release
|
||||
|
||||
```bash
|
||||
# Example: 5.3.0 → 6.0.0
|
||||
# 1. Update all four files to 6.0.0
|
||||
# 2. Build and test
|
||||
npm run build
|
||||
# 3. Commit and tag
|
||||
git add package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json CLAUDE.md plugin/scripts/
|
||||
git commit -m "Release v6.0.0: Storage layer redesign"
|
||||
git tag v6.0.0 -m "Release v6.0.0: Storage layer redesign"
|
||||
git push && git push --tags
|
||||
# 4. Create release with warning
|
||||
gh release create v6.0.0 --title "v6.0.0" --notes "⚠️ Breaking change: Storage layer redesigned. Migration required."
|
||||
```
|
||||
|
||||
## Rollback Commands
|
||||
|
||||
### Delete Tag
|
||||
|
||||
```bash
|
||||
# Delete local tag
|
||||
git tag -d vX.Y.Z
|
||||
|
||||
# Delete remote tag
|
||||
git push origin :refs/tags/vX.Y.Z
|
||||
# Or: git push --delete origin vX.Y.Z
|
||||
```
|
||||
|
||||
### Delete Release
|
||||
|
||||
```bash
|
||||
# Delete GitHub release
|
||||
gh release delete vX.Y.Z
|
||||
|
||||
# Confirm deletion
|
||||
gh release delete vX.Y.Z --yes
|
||||
```
|
||||
|
||||
### Revert Commit
|
||||
|
||||
```bash
|
||||
# Revert last commit (creates new commit)
|
||||
git revert HEAD
|
||||
|
||||
# Reset to previous commit (destructive)
|
||||
git reset --hard HEAD~1
|
||||
git push --force # Dangerous! Only if not shared
|
||||
```
|
||||
|
||||
## Error Prevention
|
||||
|
||||
### Pre-commit Checks
|
||||
|
||||
```bash
|
||||
# Check all versions match before committing
|
||||
V1=$(grep '"version"' package.json | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
|
||||
V2=$(grep '"version"' .claude-plugin/marketplace.json | sed 's/.*"\([^"]*\)".*/\1/')
|
||||
V3=$(grep '"version"' plugin/.claude-plugin/plugin.json | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
|
||||
|
||||
if [ "$V1" = "$V2" ] && [ "$V2" = "$V3" ]; then
|
||||
echo "✓ All versions match: $V1"
|
||||
else
|
||||
echo "✗ Version mismatch!"
|
||||
echo " package.json: $V1"
|
||||
echo " marketplace.json: $V2"
|
||||
echo " plugin.json: $V3"
|
||||
fi
|
||||
```
|
||||
|
||||
### Pre-push Checks
|
||||
|
||||
```bash
|
||||
# Check tag exists
|
||||
git tag -l | grep vX.Y.Z || echo "Warning: Tag not created"
|
||||
|
||||
# Check build succeeds
|
||||
npm run build || echo "Error: Build failed"
|
||||
|
||||
# Check no uncommitted changes
|
||||
git status --porcelain | grep -q . && echo "Warning: Uncommitted changes"
|
||||
```
|
||||
@@ -0,0 +1,218 @@
|
||||
# Common Version Bump Scenarios
|
||||
|
||||
Real-world examples of version bumps with decision rationale.
|
||||
|
||||
## Scenario 1: Bug Fix After Testing
|
||||
|
||||
**User request:**
|
||||
> "Fixed the memory leak in the search function"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: Bug fix
|
||||
- Breaking changes: No
|
||||
- New features: No
|
||||
- **Decision: PATCH**
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
Current: 4.2.8
|
||||
New: 4.2.9 (PATCH)
|
||||
|
||||
Steps:
|
||||
1. Update all four files to 4.2.9
|
||||
2. npm run build
|
||||
3. git commit -m "Release v4.2.9: Fixed memory leak in search"
|
||||
4. git tag v4.2.9 -m "Release v4.2.9: Fixed memory leak in search"
|
||||
5. git push && git push --tags
|
||||
6. gh release create v4.2.9 --title "v4.2.9" --notes "Fixed memory leak in search function"
|
||||
```
|
||||
|
||||
## Scenario 2: New Feature Added
|
||||
|
||||
**User request:**
|
||||
> "Added web search MCP integration"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: New feature (MCP integration)
|
||||
- Breaking changes: No
|
||||
- Backward compatible: Yes
|
||||
- **Decision: MINOR**
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
Current: 4.2.8
|
||||
New: 4.3.0 (MINOR - reset patch to 0)
|
||||
|
||||
Steps:
|
||||
1. Update all four files to 4.3.0
|
||||
2. npm run build
|
||||
3. git commit -m "Release v4.3.0: Added web search MCP integration"
|
||||
4. git tag v4.3.0 -m "Release v4.3.0: Added web search MCP integration"
|
||||
5. git push && git push --tags
|
||||
6. gh release create v4.3.0 --title "v4.3.0" --generate-notes
|
||||
```
|
||||
|
||||
## Scenario 3: Database Schema Redesign
|
||||
|
||||
**User request:**
|
||||
> "Rewrote storage layer, old data needs migration"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: Storage layer rewrite
|
||||
- Breaking changes: Yes (requires migration)
|
||||
- Backward compatible: No
|
||||
- **Decision: MAJOR**
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
Current: 4.2.8
|
||||
New: 5.0.0 (MAJOR - reset minor and patch to 0)
|
||||
|
||||
Steps:
|
||||
1. Update all four files to 5.0.0
|
||||
2. npm run build
|
||||
3. git commit -m "Release v5.0.0: Storage layer redesign with migration required"
|
||||
4. git tag v5.0.0 -m "Release v5.0.0: Storage layer redesign"
|
||||
5. git push && git push --tags
|
||||
6. gh release create v5.0.0 --title "v5.0.0" --notes "⚠️ Breaking change: Storage layer redesigned. Migration required."
|
||||
```
|
||||
|
||||
## Scenario 4: Multiple Small Bug Fixes
|
||||
|
||||
**User request:**
|
||||
> "Fixed three bugs: observer crash, viewer pagination, and date formatting"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: Multiple bug fixes
|
||||
- Breaking changes: No
|
||||
- New features: No
|
||||
- **Decision: PATCH** (one patch covers all fixes)
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
Current: 4.2.8
|
||||
New: 4.2.9 (PATCH)
|
||||
|
||||
Steps:
|
||||
1. Update all four files to 4.2.9
|
||||
2. npm run build
|
||||
3. git commit -m "Release v4.2.9: Multiple bug fixes
|
||||
|
||||
- Fixed observer crash on empty content
|
||||
- Fixed viewer pagination edge case
|
||||
- Fixed date formatting in timeline"
|
||||
4. git tag v4.2.9 -m "Release v4.2.9: Multiple bug fixes"
|
||||
5. git push && git push --tags
|
||||
6. gh release create v4.2.9 --title "v4.2.9" --generate-notes
|
||||
```
|
||||
|
||||
## Scenario 5: Feature + Bug Fix
|
||||
|
||||
**User request:**
|
||||
> "Added dark mode support and fixed the viewer crash bug"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: New feature + bug fix
|
||||
- Breaking changes: No
|
||||
- **Decision: MINOR** (feature trumps bug fix)
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
Current: 5.1.0
|
||||
New: 5.2.0 (MINOR)
|
||||
|
||||
Steps:
|
||||
1. Update all four files to 5.2.0
|
||||
2. npm run build
|
||||
3. git commit -m "Release v5.2.0: Dark mode support + bug fixes
|
||||
|
||||
Features:
|
||||
- Added dark mode toggle to viewer UI
|
||||
|
||||
Bug fixes:
|
||||
- Fixed viewer crash on empty database"
|
||||
4. git tag v5.2.0 -m "Release v5.2.0: Dark mode support"
|
||||
5. git push && git push --tags
|
||||
6. gh release create v5.2.0 --title "v5.2.0" --generate-notes
|
||||
```
|
||||
|
||||
## Scenario 6: Documentation Only
|
||||
|
||||
**User request:**
|
||||
> "Updated README with new installation instructions"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: Documentation only
|
||||
- Breaking changes: No
|
||||
- Code changes: No
|
||||
- **Decision: PATCH** (or skip version bump if no code changes)
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
Option 1: PATCH (if you want to tag doc improvements)
|
||||
Current: 4.2.8
|
||||
New: 4.2.9
|
||||
|
||||
Option 2: No version bump (documentation-only changes don't require versioning)
|
||||
Just commit without bumping version
|
||||
```
|
||||
|
||||
**Recommendation:** Skip version bump for documentation-only changes unless it's a significant documentation overhaul.
|
||||
|
||||
## Scenario 7: Configuration Change
|
||||
|
||||
**User request:**
|
||||
> "Changed default observation count from 50 to 30"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: Default configuration
|
||||
- Breaking changes: Yes (behavior changes)
|
||||
- Users might notice different context size
|
||||
- **Decision: MINOR or MAJOR** (ask user)
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
Ask user:
|
||||
"This changes default behavior (context size). Users will see different results.
|
||||
Is this:
|
||||
- MINOR (acceptable behavior change): 4.2.8 → 4.3.0
|
||||
- MAJOR (breaking change): 4.2.8 → 5.0.0
|
||||
|
||||
Which should I use?"
|
||||
```
|
||||
|
||||
## Scenario 8: Dependency Update
|
||||
|
||||
**User request:**
|
||||
> "Updated Claude SDK from 1.2.0 to 1.3.0"
|
||||
|
||||
**Analysis:**
|
||||
- What changed: Dependency version
|
||||
- Breaking changes: Depends on SDK changes
|
||||
- **Decision: Ask user or check SDK changelog**
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
1. Check SDK changelog for breaking changes
|
||||
2. If SDK has breaking changes → MAJOR
|
||||
3. If SDK adds features → MINOR
|
||||
4. If SDK only fixes bugs → PATCH
|
||||
|
||||
Typical: PATCH (unless SDK breaks compatibility)
|
||||
```
|
||||
|
||||
## Decision Tree
|
||||
|
||||
```
|
||||
Is there a breaking change?
|
||||
├─ Yes → MAJOR (X.0.0)
|
||||
└─ No
|
||||
├─ Is there a new feature?
|
||||
│ ├─ Yes → MINOR (x.Y.0)
|
||||
│ └─ No
|
||||
│ ├─ Is there a bug fix?
|
||||
│ │ ├─ Yes → PATCH (x.y.Z)
|
||||
│ │ └─ No → Don't bump version (docs only, etc.)
|
||||
│ └─ Configuration change? → Ask user (MINOR or MAJOR)
|
||||
└─ Multiple changes? → Use highest level (MAJOR > MINOR > PATCH)
|
||||
```
|
||||
@@ -0,0 +1,251 @@
|
||||
# Detailed Version Bump Workflow
|
||||
|
||||
Step-by-step process for bumping versions in the claude-mem project.
|
||||
|
||||
## Step 1: Analyze Changes
|
||||
|
||||
First, understand what changed:
|
||||
|
||||
```bash
|
||||
# View recent commits
|
||||
git log --oneline -5
|
||||
|
||||
# See what changed in last commit
|
||||
git diff HEAD~1
|
||||
|
||||
# Or see all changes since last tag
|
||||
LAST_TAG=$(git describe --tags --abbrev=0)
|
||||
git log $LAST_TAG..HEAD --oneline
|
||||
git diff $LAST_TAG..HEAD
|
||||
```
|
||||
|
||||
## Step 2: Determine Version Type
|
||||
|
||||
Ask yourself:
|
||||
- **Breaking changes?** → MAJOR
|
||||
- **New features?** → MINOR
|
||||
- **Bugfixes only?** → PATCH
|
||||
|
||||
**If unclear, ASK THE USER explicitly.**
|
||||
|
||||
### Decision Matrix
|
||||
|
||||
| Change Type | Version Bump | Example |
|
||||
|------------|--------------|---------|
|
||||
| Bug fix | PATCH | 4.2.8 → 4.2.9 |
|
||||
| New feature (backward compatible) | MINOR | 4.2.8 → 4.3.0 |
|
||||
| Breaking change | MAJOR | 4.2.8 → 5.0.0 |
|
||||
| Multiple features | MINOR | 4.2.8 → 4.3.0 |
|
||||
| Feature + breaking change | MAJOR | 4.2.8 → 5.0.0 |
|
||||
|
||||
## Step 3: Calculate New Version
|
||||
|
||||
From current version in `package.json`:
|
||||
|
||||
```bash
|
||||
grep '"version"' package.json
|
||||
```
|
||||
|
||||
Apply semantic versioning rules:
|
||||
- **Patch:** increment Z (4.2.8 → 4.2.9)
|
||||
- **Minor:** increment Y, reset Z (4.2.8 → 4.3.0)
|
||||
- **Major:** increment X, reset Y and Z (4.2.8 → 5.0.0)
|
||||
|
||||
## Step 4: Preview Changes
|
||||
|
||||
**BEFORE making changes, show the user:**
|
||||
|
||||
```
|
||||
Current version: 4.2.8
|
||||
New version: 4.2.9 (PATCH)
|
||||
Reason: Fixed database query bug
|
||||
|
||||
Files to update:
|
||||
- package.json: "version": "4.2.9"
|
||||
- marketplace.json: "version": "4.2.9"
|
||||
- plugin.json: "version": "4.2.9"
|
||||
- CLAUDE.md line 9: "**Current Version**: 4.2.9" (version number ONLY)
|
||||
- Git tag: v4.2.9
|
||||
|
||||
Proceed? (yes/no)
|
||||
```
|
||||
|
||||
Wait for user confirmation before proceeding.
|
||||
|
||||
## Step 5: Update Files
|
||||
|
||||
### Update package.json
|
||||
|
||||
File: `package.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "4.2.9",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Update line 3 with new version.
|
||||
|
||||
### Update marketplace.json
|
||||
|
||||
File: `.claude-plugin/marketplace.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "4.2.9",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Update line 13 with new version.
|
||||
|
||||
### Update plugin.json
|
||||
|
||||
File: `plugin/.claude-plugin/plugin.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "4.2.9",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Update line 3 with new version.
|
||||
|
||||
### Update CLAUDE.md
|
||||
|
||||
File: `CLAUDE.md`
|
||||
|
||||
**ONLY update line 9 with the version number:**
|
||||
|
||||
```markdown
|
||||
**Current Version**: 4.2.9
|
||||
```
|
||||
|
||||
**CRITICAL:** DO NOT add version history entries to CLAUDE.md. Version history is managed separately outside this skill.
|
||||
|
||||
## Step 6: Verify Consistency
|
||||
|
||||
```bash
|
||||
# Check all versions match
|
||||
grep -n '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
|
||||
|
||||
# Should show same version in all three files:
|
||||
# package.json:3: "version": "4.2.9",
|
||||
# .claude-plugin/marketplace.json:13: "version": "4.2.9",
|
||||
# plugin/.claude-plugin/plugin.json:3: "version": "4.2.9",
|
||||
```
|
||||
|
||||
All three must match exactly.
|
||||
|
||||
## Step 7: Test
|
||||
|
||||
```bash
|
||||
# Verify the plugin loads correctly
|
||||
npm run build
|
||||
```
|
||||
|
||||
Build must succeed before proceeding.
|
||||
|
||||
## Step 8: Commit and Tag
|
||||
|
||||
```bash
|
||||
# Stage all version files
|
||||
git add package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json CLAUDE.md plugin/scripts/
|
||||
|
||||
# Commit with descriptive message
|
||||
git commit -m "Release vX.Y.Z: [Brief description]
|
||||
|
||||
[Optional detailed description]
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||
|
||||
# Create annotated git tag
|
||||
git tag vX.Y.Z -m "Release vX.Y.Z: [Brief description]"
|
||||
|
||||
# Push commit and tags
|
||||
git push && git push --tags
|
||||
```
|
||||
|
||||
Replace `X.Y.Z` with actual version (e.g., `4.2.9`).
|
||||
|
||||
## Step 9: Create GitHub Release
|
||||
|
||||
```bash
|
||||
# Create GitHub release from the tag
|
||||
gh release create vX.Y.Z --title "vX.Y.Z" --notes "[Brief release notes]"
|
||||
|
||||
# Or generate notes automatically from commits
|
||||
gh release create vX.Y.Z --title "vX.Y.Z" --generate-notes
|
||||
```
|
||||
|
||||
**IMPORTANT:** Always create the GitHub release immediately after pushing the tag. This makes the release discoverable to users and triggers any automated workflows.
|
||||
|
||||
## Step 10: Generate CHANGELOG
|
||||
|
||||
After creating the GitHub release, regenerate CHANGELOG.md from all releases:
|
||||
|
||||
```bash
|
||||
# Generate CHANGELOG.md from all GitHub releases
|
||||
npm run changelog:generate
|
||||
|
||||
# Review the generated changelog
|
||||
git diff CHANGELOG.md
|
||||
|
||||
# Commit and push the updated changelog
|
||||
git add CHANGELOG.md
|
||||
git commit -m "Update CHANGELOG.md for vX.Y.Z release"
|
||||
git push
|
||||
```
|
||||
|
||||
**Why this step:**
|
||||
- CHANGELOG.md is auto-generated from GitHub releases
|
||||
- Keeps the changelog in sync with release notes
|
||||
- No manual editing required
|
||||
- Single source of truth: GitHub releases
|
||||
|
||||
## Verification
|
||||
|
||||
After completing all steps, verify:
|
||||
|
||||
```bash
|
||||
# Check git tag created
|
||||
git tag -l | grep vX.Y.Z
|
||||
|
||||
# Check remote has tag
|
||||
git ls-remote --tags origin | grep vX.Y.Z
|
||||
|
||||
# Check GitHub release exists
|
||||
gh release view vX.Y.Z
|
||||
|
||||
# Verify versions match
|
||||
grep '"version"' package.json .claude-plugin/marketplace.json plugin/.claude-plugin/plugin.json
|
||||
```
|
||||
|
||||
All checks should pass.
|
||||
|
||||
## Rollback (If Needed)
|
||||
|
||||
If you made a mistake:
|
||||
|
||||
```bash
|
||||
# Delete local tag
|
||||
git tag -d vX.Y.Z
|
||||
|
||||
# Delete remote tag (if already pushed)
|
||||
git push origin :refs/tags/vX.Y.Z
|
||||
|
||||
# Delete GitHub release (if created)
|
||||
gh release delete vX.Y.Z
|
||||
|
||||
# Revert commits if needed
|
||||
git revert HEAD
|
||||
```
|
||||
|
||||
Then restart the workflow with correct version.
|
||||
@@ -0,0 +1,57 @@
|
||||
name: Claude Code Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize]
|
||||
# Optional: Only run on specific file changes
|
||||
# paths:
|
||||
# - "src/**/*.ts"
|
||||
# - "src/**/*.tsx"
|
||||
# - "src/**/*.js"
|
||||
# - "src/**/*.jsx"
|
||||
|
||||
jobs:
|
||||
claude-review:
|
||||
# Optional: Filter by PR author
|
||||
# if: |
|
||||
# github.event.pull_request.user.login == 'external-contributor' ||
|
||||
# github.event.pull_request.user.login == 'new-developer' ||
|
||||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code Review
|
||||
id: claude-review
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
prompt: |
|
||||
REPO: ${{ github.repository }}
|
||||
PR NUMBER: ${{ github.event.pull_request.number }}
|
||||
|
||||
Please review this pull request and provide feedback on:
|
||||
- Code quality and best practices
|
||||
- Potential bugs or issues
|
||||
- Performance considerations
|
||||
- Security concerns
|
||||
- Test coverage
|
||||
|
||||
Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback.
|
||||
|
||||
Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR.
|
||||
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
|
||||
claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"'
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
name: Claude Code
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
claude:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
actions: read # Required for Claude to read CI results on PRs
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
|
||||
# This is an optional setting that allows Claude to read CI results on PRs
|
||||
additional_permissions: |
|
||||
actions: read
|
||||
|
||||
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
||||
# prompt: 'Update the pull request description to include a summary of changes.'
|
||||
|
||||
# Optional: Add claude_args to customize behavior and configuration
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://docs.claude.com/en/docs/claude-code/cli-reference for available options
|
||||
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
||||
|
||||
+14
-10
@@ -1,13 +1,17 @@
|
||||
# Binaries (distributed via GitHub releases)
|
||||
*.exe
|
||||
*.app
|
||||
claude-mem
|
||||
claude-mem-*
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
node_modules/
|
||||
dist/
|
||||
*.log
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
*.tmp
|
||||
*.temp
|
||||
.install-version
|
||||
.claude/settings.local.json
|
||||
plugin/data/
|
||||
plugin/data.backup/
|
||||
package-lock.json
|
||||
private/
|
||||
|
||||
# Node modules (if any)
|
||||
node_modules/
|
||||
# Generated UI files (built from viewer-template.html)
|
||||
src/ui/viewer.html
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"old-claude-mem": {
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"chroma-mcp",
|
||||
"--client-type",
|
||||
"persistent",
|
||||
"--data-dir",
|
||||
"/Users/alexnewman/.claude-mem/backups/chroma-backup-20251005-222403"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"sourceHash": "9ab0d799179c66f9",
|
||||
"lastUpdated": "2025-12-12T07:42:03.489Z",
|
||||
"translations": {
|
||||
"zh": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:06:55.026Z",
|
||||
"costUsd": 0.12256679999999998
|
||||
},
|
||||
"ja": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:06:55.026Z",
|
||||
"costUsd": 0.12973164999999998
|
||||
},
|
||||
"pt-br": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:06:55.026Z",
|
||||
"costUsd": 0.11508539999999999
|
||||
},
|
||||
"ko": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:06:55.026Z",
|
||||
"costUsd": 0.13952664999999997
|
||||
},
|
||||
"es": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:06:55.026Z",
|
||||
"costUsd": 0.12530165
|
||||
},
|
||||
"de": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:06:55.026Z",
|
||||
"costUsd": 0.12232164999999998
|
||||
},
|
||||
"fr": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:06:55.026Z",
|
||||
"costUsd": 0.11906665
|
||||
},
|
||||
"he": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.151329
|
||||
},
|
||||
"ar": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.151952
|
||||
},
|
||||
"ru": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.13418499999999997
|
||||
},
|
||||
"pl": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.13196799999999997
|
||||
},
|
||||
"cs": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.12714599999999998
|
||||
},
|
||||
"nl": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.118389
|
||||
},
|
||||
"tr": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.13991199999999998
|
||||
},
|
||||
"uk": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:25:00.076Z",
|
||||
"costUsd": 0.13786
|
||||
},
|
||||
"vi": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:42:03.489Z",
|
||||
"costUsd": 0.15467299999999998
|
||||
},
|
||||
"id": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:42:03.489Z",
|
||||
"costUsd": 0.185581
|
||||
},
|
||||
"th": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:42:03.489Z",
|
||||
"costUsd": 0.177859
|
||||
},
|
||||
"hi": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:42:03.489Z",
|
||||
"costUsd": 0.17412700000000003
|
||||
},
|
||||
"bn": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:42:03.489Z",
|
||||
"costUsd": 0.202735
|
||||
},
|
||||
"ro": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:42:03.489Z",
|
||||
"costUsd": 0.12212875
|
||||
},
|
||||
"sv": {
|
||||
"hash": "9ab0d799179c66f9",
|
||||
"translatedAt": "2025-12-12T07:42:03.489Z",
|
||||
"costUsd": 0.12143675000000001
|
||||
}
|
||||
}
|
||||
}
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
# Action Plan: Issues & PRs Cleanup
|
||||
Generated: 2025-12-12
|
||||
|
||||
## Phase 1: Immediate Cleanup (Today)
|
||||
|
||||
### Close Obsolete PRs
|
||||
|
||||
- [ ] **#255** - Close PR "Fix PM2 worker MODULE_NOT_FOUND"
|
||||
- Reason: v7.1.0 removed PM2 entirely, this fix is no longer relevant
|
||||
- Comment: Explain that v7.1.0 migration to Bun eliminated PM2 dependency
|
||||
|
||||
- [ ] **#206** - Close or request update on "Harden worker startup"
|
||||
- Reason: Contains PM2-specific code that no longer exists
|
||||
- Comment: Ask author if they want to update for Bun architecture, otherwise close as obsolete
|
||||
|
||||
### Close/Update Fixed Issues
|
||||
|
||||
- [ ] **#213** - Comment and close "Windows endless process spawning"
|
||||
- Reason: v7.1.0 Bun migration eliminated PM2 process management
|
||||
- Comment: Ask user to verify fix on v7.1.0, explain PM2 removal resolved issue
|
||||
|
||||
- [ ] **#229** - Close as duplicate
|
||||
- Reason: Duplicate of #227 (upstream Claude Code bug)
|
||||
- Comment: Direct to #227 for full details and workaround
|
||||
|
||||
- [ ] **#211** - Answer and close "Cursor IDE support question"
|
||||
- Reason: Product question, not a bug report
|
||||
- Comment: Explain focus is Claude Code, but plugin architecture may allow future expansion
|
||||
|
||||
### Critical Bug Follow-Up
|
||||
|
||||
- [ ] **#254** - Follow up on "Worker API fetch failed"
|
||||
- Current status: Asked about PM2 logs (pre-v7.1.0 comment)
|
||||
- Action: Update comment asking:
|
||||
- What version of claude-mem are you running?
|
||||
- If pre-v7.1.0: Please upgrade to v7.1.0 which fixes PM2 issues
|
||||
- If v7.1.0+: Run troubleshoot skill and share logs
|
||||
|
||||
## Phase 2: High-Priority Merges (This Week)
|
||||
|
||||
### Security & Critical Fixes
|
||||
|
||||
- [ ] **#236** - Review and merge "Localhost-only binding" 🔒 PRIORITY
|
||||
- Impact: Security improvement (fixes network exposure)
|
||||
- Status: 156 additions, all tests pass (42/42)
|
||||
- Action: Final review, merge, update CHANGELOG
|
||||
|
||||
- [ ] **#212** - Review and merge "Windows path quoting fix"
|
||||
- Impact: Fixes Windows usernames with spaces
|
||||
- Status: 6 lines changed, minimal risk
|
||||
- Action: Quick cross-platform test, merge
|
||||
|
||||
### Major Features (Maintainer-Authored)
|
||||
|
||||
- [ ] **#225** - Review and merge "Export/Import scripts"
|
||||
- Impact: Enables backup/restore, partially addresses #233
|
||||
- Status: 927 additions, extensively tested by maintainer
|
||||
- Action: Final review, merge, update docs
|
||||
|
||||
- [ ] **#250** - Review and merge "README translations"
|
||||
- Impact: International user onboarding (22 languages)
|
||||
- Status: 10,209 additions (massive but low-risk)
|
||||
- Action: Spot-check a few translations, merge
|
||||
|
||||
### User-Requested Features
|
||||
|
||||
- [ ] **#252** - Test and merge "Execution traces" (addresses #194)
|
||||
- Impact: Shows tools/skills/MCPs in UI bubbles
|
||||
- Status: 383 additions, comprehensive implementation
|
||||
- Action: Test database migration, API endpoints, UI display
|
||||
|
||||
- [ ] **#251** - Test and merge "Plan file context" (addresses #180)
|
||||
- Impact: Injects last plan file into context
|
||||
- Status: 85 additions, follows existing patterns
|
||||
- Action: Test with real plan files, verify toggle works
|
||||
|
||||
## Phase 3: Review & Consider (Next Week)
|
||||
|
||||
### Quality Enhancements
|
||||
|
||||
- [ ] **#230** - Review "Multi-language support" (addresses #228)
|
||||
- Impact: Observations/summaries in user's language
|
||||
- Status: 157 additions, Korean screenshot provided
|
||||
- Action: Review prompt changes carefully, test with multiple languages
|
||||
|
||||
- [ ] **#226** - Review "CLAUDE_CONFIG_DIR support"
|
||||
- Impact: Supports non-standard Claude installations
|
||||
- Status: 10 additions, minimal change
|
||||
- Action: Test with custom config directory, merge if working
|
||||
|
||||
### Developer Experience
|
||||
|
||||
- [ ] **#216** - Review "Makefile shortcuts"
|
||||
- Impact: DX improvement for contributors
|
||||
- Status: 1,085 additions
|
||||
- Priority: Low (not urgent)
|
||||
- Action: Review when time permits
|
||||
|
||||
## Phase 4: Issue Follow-Ups (Ongoing)
|
||||
|
||||
### Awaiting User Verification
|
||||
|
||||
- [ ] **#209** - Follow up if no response on Windows worker startup
|
||||
- Status: Already commented asking for v7.1.0 verification
|
||||
- Action: Close if verified fixed, or investigate if still broken
|
||||
|
||||
- [ ] **#231** - Follow up if no response on module resolution
|
||||
- Status: Already commented asking for v7.1.0 verification
|
||||
- Action: Close if verified fixed, or investigate if still broken
|
||||
|
||||
### Upstream Bugs (Keep Open)
|
||||
|
||||
- [ ] **#227** - Keep open as documented upstream bug
|
||||
- Reason: Claude Code CLI uses invalid Windows paths
|
||||
- Action: No action needed, workaround documented
|
||||
|
||||
### Active Bugs (Investigate)
|
||||
|
||||
- [ ] **#208** - Investigate "Windows console windows appearing"
|
||||
- Priority: Medium (cosmetic but annoying)
|
||||
- Action: Reproduce on Windows, identify root cause
|
||||
|
||||
## Phase 5: Future Feature Planning
|
||||
|
||||
### Feature Requests Without PRs
|
||||
|
||||
- [ ] **#240** - Plan "Move MCP scaffolding to separate file"
|
||||
- Type: Internal refactoring
|
||||
- Priority: Low
|
||||
- Action: Design approach when time permits
|
||||
|
||||
- [ ] **#239** - Plan "Track git branch as metadata"
|
||||
- Type: Context enhancement
|
||||
- Priority: Medium
|
||||
- Action: Design schema changes, discuss approach
|
||||
|
||||
- [ ] **#215** - Plan "PreCompact event hook"
|
||||
- Type: Power user feature
|
||||
- Priority: Low
|
||||
- Action: Evaluate use cases, design API
|
||||
|
||||
- [ ] **#233** - Plan "Multi-device sync" (partial solution exists)
|
||||
- Type: Major feature
|
||||
- Note: PR #225 provides export/import, full sync is more complex
|
||||
- Action: Determine if export/import is sufficient, or plan cloud sync
|
||||
|
||||
## Summary
|
||||
|
||||
### Quick Wins (Do Today)
|
||||
- Close 2 obsolete PRs (#255, #206)
|
||||
- Close 3 resolved/duplicate issues (#213, #229, #211)
|
||||
- Follow up on critical bug (#254)
|
||||
|
||||
### High-Impact Merges (This Week)
|
||||
- Merge security fix (#236)
|
||||
- Merge 2 simple fixes (#212, #225)
|
||||
- Merge 2 major features (#250, #252, #251)
|
||||
|
||||
### Expected Impact
|
||||
- **Security**: Localhost-only by default
|
||||
- **Functionality**: Export/import, execution traces, plan context
|
||||
- **UX**: Multi-language support, Windows fixes
|
||||
- **Clarity**: Clean backlog, remove PM2 confusion
|
||||
|
||||
---
|
||||
|
||||
**Next Review**: After Phase 2 completion, reassess remaining items
|
||||
+2483
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/* To @claude: be vigilant about only leaving evergreen context in this file, claude-mem handles working context separately. */
|
||||
|
||||
# Claude-Mem: AI Development Instructions
|
||||
|
||||
## What This Project Is
|
||||
|
||||
Claude-mem is a Claude Code plugin providing persistent memory across sessions. It captures tool usage, compresses observations using the Claude Agent SDK, and injects relevant context into future sessions.
|
||||
|
||||
**Current Version**: 7.1.3
|
||||
|
||||
## Architecture
|
||||
|
||||
**5 Lifecycle Hooks**: SessionStart → UserPromptSubmit → PostToolUse → Summary → SessionEnd
|
||||
|
||||
**Hooks** (`src/hooks/*.ts`) - TypeScript → ESM, built to `plugin/scripts/*-hook.js`
|
||||
|
||||
**Worker Service** (`src/services/worker-service.ts`) - Express API on port 37777, Bun-managed, handles AI processing asynchronously
|
||||
|
||||
**Database** (`src/services/sqlite/`) - SQLite3 at `~/.claude-mem/claude-mem.db` with FTS5 full-text search
|
||||
|
||||
**Search Skill** (`plugin/skills/mem-search/SKILL.md`) - HTTP API for searching past work, auto-invoked when users ask about history
|
||||
|
||||
**Chroma** (`src/services/sync/ChromaSync.ts`) - Vector embeddings for semantic search
|
||||
|
||||
**Viewer UI** (`src/ui/viewer/`) - React interface at http://localhost:37777, built to `plugin/ui/viewer.html`
|
||||
|
||||
## Privacy Tags
|
||||
|
||||
**Dual-Tag System** for meta-observation control:
|
||||
- `<private>content</private>` - User-level privacy control (manual, prevents storage)
|
||||
- `<claude-mem-context>content</claude-mem-context>` - System-level tag (auto-injected observations, prevents recursive storage)
|
||||
|
||||
**Implementation**: Tag stripping happens at hook layer (edge processing) before data reaches worker/database. See `src/utils/tag-stripping.ts` for shared utilities.
|
||||
|
||||
## Build Commands
|
||||
|
||||
**Hooks only**: `npm run build && npm run sync-marketplace`
|
||||
|
||||
**Worker changes**: `npm run build && npm run sync-marketplace && npm run worker:restart`
|
||||
|
||||
**Skills only**: `npm run sync-marketplace`
|
||||
|
||||
**Viewer UI**: `npm run build && npm run sync-marketplace && npm run worker:restart`
|
||||
|
||||
## Configuration
|
||||
|
||||
Settings are managed in `~/.claude-mem/settings.json`. The file is auto-created with defaults on first run.
|
||||
|
||||
**Core Settings:**
|
||||
- `CLAUDE_MEM_MODEL` - Model for observations/summaries (default: claude-haiku-4-5)
|
||||
- `CLAUDE_MEM_CONTEXT_OBSERVATIONS` - Observations injected at SessionStart (default: 50)
|
||||
- `CLAUDE_MEM_WORKER_PORT` - Worker service port (default: 37777)
|
||||
- `CLAUDE_MEM_WORKER_HOST` - Worker bind address (default: 127.0.0.1, use 0.0.0.0 for remote access)
|
||||
|
||||
**System Configuration:**
|
||||
- `CLAUDE_MEM_DATA_DIR` - Data directory location (default: ~/.claude-mem)
|
||||
- `CLAUDE_MEM_LOG_LEVEL` - Log verbosity: DEBUG, INFO, WARN, ERROR, SILENT (default: INFO)
|
||||
- `CLAUDE_MEM_PYTHON_VERSION` - Python version for uvx/chroma-mcp (default: 3.13, avoids onnxruntime compatibility issues with Python 3.14+)
|
||||
- `CLAUDE_CODE_PATH` - Path to Claude executable (default: auto-detect via 'which claude')
|
||||
|
||||
**Settings File Format:**
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_MODEL": "claude-haiku-4-5",
|
||||
"CLAUDE_MEM_WORKER_PORT": "37777"
|
||||
}
|
||||
```
|
||||
|
||||
## File Locations
|
||||
|
||||
- **Source**: `<project-root>/src/`
|
||||
- **Built Plugin**: `<project-root>/plugin/`
|
||||
- **Installed Plugin**: `~/.claude/plugins/marketplaces/thedotmack/`
|
||||
- **Database**: `~/.claude-mem/claude-mem.db`
|
||||
- **Chroma**: `~/.claude-mem/chroma/`
|
||||
- **Usage Logs**: `~/.claude-mem/usage-logs/usage-YYYY-MM-DD.jsonl`
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Bun** >= 1.0 (all platforms - auto-installed if missing)
|
||||
- **uv** (all platforms - auto-installed if missing, provides Python for Chroma)
|
||||
- Node.js >= 18 (build tools only)
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
npm run build # Compile TypeScript
|
||||
npm run sync-marketplace # Copy to ~/.claude/plugins
|
||||
npm run worker:restart # Restart worker service
|
||||
npm run worker:status # Check worker status
|
||||
npm run worker:logs # View worker logs
|
||||
```
|
||||
|
||||
**Viewer UI**: http://localhost:37777
|
||||
**Worker Logs**: `~/.claude-mem/logs/worker-YYYY-MM-DD.log`
|
||||
|
||||
## Documentation
|
||||
|
||||
**Public Docs**: https://docs.claude-mem.ai (Mintlify)
|
||||
**Source**: `docs/public/` - MDX files, edit `docs.json` for navigation
|
||||
**Deploy**: Auto-deploys from GitHub on push to main
|
||||
**Local Dev**: `cd docs/public && npx mintlify dev`
|
||||
@@ -1,43 +1,630 @@
|
||||
# Claude Mem License
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (c) 2024 Alex Newman (@thedotmack)
|
||||
Copyright (C) 2025 Alex Newman (@thedotmack). All rights reserved.
|
||||
|
||||
## Binary Distribution License
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
The compiled binaries (claude-mem, claude-mem.exe, etc.) are provided free of charge for personal and commercial use under the following terms:
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
1. **USE**: You may use the binaries for any purpose.
|
||||
2. **DISTRIBUTION**: You may redistribute the unmodified binaries.
|
||||
3. **NO REVERSE ENGINEERING**: You may not decompile, disassemble, or reverse engineer the binaries.
|
||||
4. **NO MODIFICATION**: You may not modify the binary files.
|
||||
5. **NO WARRANTY**: The software is provided "as is" without warranty of any kind.
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
## Hook Files License (MIT)
|
||||
Preamble
|
||||
|
||||
The hook files in the `/hooks` directory are licensed under the MIT License:
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of these hook files and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
## Contributions
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
By submitting pull requests for hook files or documentation, you agree to license your contributions under the MIT License.
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
## Trademark
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
"Claude Mem" is a trademark of Alex Newman. You may use the name when referring to this software, but not in a way that implies endorsement or affiliation.
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
@@ -1,215 +1,443 @@
|
||||
# Claude Memory System (claude-mem)
|
||||
<h1 align="center">
|
||||
<br>
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-dark-mode.webp">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp">
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/claude-mem-logo-for-light-mode.webp" alt="Claude-Mem" width="400">
|
||||
</picture>
|
||||
</a>
|
||||
<br>
|
||||
</h1>
|
||||
|
||||
**Truth + Context = Clarity**
|
||||
<h4 align="center">Persistent memory compression system built for <a href="https://claude.com/claude-code" target="_blank">Claude Code</a>.</h4>
|
||||
|
||||
A revolutionary memory system that transforms your Claude Code conversations into a persistent, intelligent knowledge base. Never lose valuable insights, code patterns, or debugging solutions again. Your AI assistant finally has a memory that spans across all your projects and sessions.
|
||||
<p align="center">
|
||||
<a href="LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-AGPL%203.0-blue.svg" alt="License">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/version-6.5.0-green.svg" alt="Version">
|
||||
</a>
|
||||
<a href="package.json">
|
||||
<img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg" alt="Node">
|
||||
</a>
|
||||
<a href="https://github.com/thedotmack/awesome-claude-code">
|
||||
<img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Claude Code">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🚀 Why Claude-Mem?
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/15496" target="_blank">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/trendshift-badge-dark.svg">
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/trendshift-badge.svg">
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/trendshift-badge.svg" alt="thedotmack/claude-mem | Trendshift" width="250" height="55"/>
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
### The Problem We Solve
|
||||
- **Lost Context**: Starting every Claude Code session from scratch
|
||||
- **Repeated Explanations**: Re-describing your codebase and architecture repeatedly
|
||||
- **Fragmented Knowledge**: Valuable insights scattered across hundreds of conversations
|
||||
- **Context Switching**: Losing progress when switching between projects or devices
|
||||
- **Knowledge Decay**: Brilliant solutions forgotten and re-discovered multiple times
|
||||
<br>
|
||||
|
||||
### The Claude-Mem Solution
|
||||
Transform your Claude Code experience from forgetful to persistent, from isolated sessions to connected knowledge, from starting over to building upon previous insights.
|
||||
<p align="center">
|
||||
<a href="https://github.com/thedotmack/claude-mem">
|
||||
<picture>
|
||||
<img src="https://raw.githubusercontent.com/thedotmack/claude-mem/main/docs/public/cm-preview.gif" alt="Claude-Mem Preview" width="800">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## ✨ Key Features
|
||||
<p align="center">
|
||||
<a href="#quick-start">Quick Start</a> •
|
||||
<a href="#how-it-works">How It Works</a> •
|
||||
<a href="#mcp-search-tools">Search Tools</a> •
|
||||
<a href="#documentation">Documentation</a> •
|
||||
<a href="#configuration">Configuration</a> •
|
||||
<a href="#troubleshooting">Troubleshooting</a> •
|
||||
<a href="#license">License</a>
|
||||
</p>
|
||||
|
||||
### 🧠 **Intelligent Memory Compression**
|
||||
- Automatically extracts key learnings from your Claude Code conversations
|
||||
- Identifies patterns, architectural decisions, and breakthrough moments
|
||||
- Compresses hours of conversation into searchable, actionable knowledge
|
||||
- Uses advanced AI analysis to understand context and significance
|
||||
|
||||
### 🔄 **Seamless Integration**
|
||||
- **One-command setup**: `claude-mem install` and you're ready
|
||||
- **Zero friction**: Works invisibly in the background
|
||||
- **Automatic triggers**: Memory compression on `/compact` and `/clear`
|
||||
- **Instant context loading**: New sessions start with relevant memories
|
||||
|
||||
### 🎯 **Smart Context Loading**
|
||||
- Loads relevant memories when starting new sessions
|
||||
- Project-aware context selection
|
||||
- Semantic search finds related knowledge across all sessions
|
||||
- Prevents re-explaining the same concepts repeatedly
|
||||
|
||||
### 📚 **Comprehensive Knowledge Base**
|
||||
- Stores technical implementations, bug fixes, and solutions
|
||||
- Captures design patterns and architectural decisions
|
||||
- Remembers tool configurations and setup procedures
|
||||
- Archives complete conversation transcripts for detailed reference
|
||||
|
||||
### 🔍 **Powerful Search & Retrieval**
|
||||
- Vector-based semantic search finds related concepts
|
||||
- Keyword search for specific terms and technologies
|
||||
- Project filtering to focus on relevant memories
|
||||
- Time-based filtering to find recent insights
|
||||
|
||||
## 🛠 Installation & Setup
|
||||
|
||||
### Quick Install
|
||||
```bash
|
||||
# Install globally
|
||||
npm install -g claude-mem
|
||||
|
||||
# Set up Claude Code integration
|
||||
claude-mem install
|
||||
|
||||
# Restart Claude Code to activate
|
||||
```
|
||||
|
||||
### Alternative Installation
|
||||
```bash
|
||||
# Use without installing globally
|
||||
npx claude-mem install
|
||||
```
|
||||
|
||||
### Verification
|
||||
```bash
|
||||
# Check installation status
|
||||
claude-mem status
|
||||
```
|
||||
|
||||
## 💻 How It Works
|
||||
|
||||
### The Memory Lifecycle
|
||||
|
||||
1. **🎬 Session Start**: Claude-mem loads relevant context from your knowledge base
|
||||
2. **💬 Active Session**: You work normally in Claude Code - no changes needed
|
||||
3. **🗜️ Memory Compression**: Use `/compact` or `/clear` to trigger intelligent compression
|
||||
4. **🧠 Knowledge Extraction**: AI analysis extracts key learnings and patterns
|
||||
5. **💾 Persistent Storage**: Memories stored in searchable vector database
|
||||
6. **🔄 Context Ready**: Next session starts with relevant memories loaded
|
||||
|
||||
### Technical Architecture
|
||||
|
||||
- **Vector Database**: ChromaDB for semantic search and storage
|
||||
- **MCP Integration**: Model Context Protocol for Claude Code communication
|
||||
- **AI Analysis**: Advanced prompt engineering for knowledge extraction
|
||||
- **Local Storage**: All data stored locally in `~/.claude-mem/`
|
||||
|
||||
## 📋 Commands Reference
|
||||
|
||||
### Core Commands
|
||||
```bash
|
||||
claude-mem install # Set up Claude Code integration
|
||||
claude-mem status # Check system status and configuration
|
||||
claude-mem load-context # View and search stored memories
|
||||
claude-mem logs # View system logs and debug information
|
||||
claude-mem uninstall # Remove Claude Code hooks
|
||||
```
|
||||
|
||||
### Advanced Usage
|
||||
```bash
|
||||
claude-mem compress <file> # Manually compress a transcript file
|
||||
claude-mem restore # Restore from backups
|
||||
claude-mem trash-view # View deleted files (Smart Trash feature)
|
||||
```
|
||||
|
||||
## 📁 Storage Structure
|
||||
|
||||
Your claude-mem data is organized in `~/.claude-mem/`:
|
||||
|
||||
```
|
||||
~/.claude-mem/
|
||||
├── index/ # ChromaDB vector database
|
||||
├── archives/ # Original conversation transcripts
|
||||
├── hooks/ # Claude Code integration scripts
|
||||
├── trash/ # Smart Trash (deleted files)
|
||||
└── logs/ # System logs and debug information
|
||||
```
|
||||
|
||||
## 🌟 Real-World Benefits
|
||||
|
||||
### For Individual Developers
|
||||
- **Faster Problem Solving**: Find solutions you've used before instantly
|
||||
- **Knowledge Accumulation**: Build expertise that persists across projects
|
||||
- **Context Continuity**: Pick up where you left off, even weeks later
|
||||
- **Pattern Recognition**: See how you've solved similar problems before
|
||||
|
||||
### For Teams (Coming Soon)
|
||||
- **Shared Knowledge**: Team-wide memory accessible to all members
|
||||
- **Onboarding Acceleration**: New team members access collective knowledge
|
||||
- **Best Practices**: Capture and share proven solutions
|
||||
- **Institutional Memory**: Prevent knowledge loss when team members leave
|
||||
|
||||
## 🚀 Coming Soon: Cloud Sync
|
||||
|
||||
### Individual Plan ($9.95/month)
|
||||
- **Multi-device sync**: Access your memories on any device
|
||||
- **Cloud backup**: Never lose your knowledge base
|
||||
- **Enhanced search**: Advanced filtering and semantic search
|
||||
- **API access**: Integrate with your own tools and workflows
|
||||
|
||||
### Team Plan ($29.95/month, 3+ seats)
|
||||
- **Shared memories**: Team-wide knowledge base
|
||||
- **Role-based access**: Control what memories are shared
|
||||
- **Admin dashboard**: Manage team members and usage
|
||||
- **Priority support**: Direct access to our engineering team
|
||||
|
||||
[**Join the waitlist**](https://claude-mem.ai) for early access to cloud features.
|
||||
|
||||
## 🛡️ Privacy & Security
|
||||
|
||||
- **Local-first**: All data stored locally by default
|
||||
- **No tracking**: We don't collect or transmit your conversations
|
||||
- **Your data**: You own and control your knowledge base
|
||||
- **Open architecture**: ChromaDB and MCP are open standards
|
||||
|
||||
## 🆘 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Hook not triggering?**
|
||||
```bash
|
||||
claude-mem status # Check installation
|
||||
claude-mem install --force # Reinstall hooks
|
||||
```
|
||||
|
||||
**Context not loading?**
|
||||
```bash
|
||||
claude-mem load-context # Verify memories exist
|
||||
claude-mem logs # Check for errors
|
||||
```
|
||||
|
||||
**Performance issues?**
|
||||
```bash
|
||||
# ChromaDB maintenance (if needed)
|
||||
claude-mem status # Check memory usage
|
||||
```
|
||||
|
||||
## 🔧 Requirements
|
||||
|
||||
- **Node.js**: 18.0 or higher
|
||||
- **Claude Code**: Latest version recommended
|
||||
- **Storage**: ~100MB for typical usage
|
||||
- **Memory**: 2GB RAM minimum for large knowledge bases
|
||||
|
||||
## 📞 Support & Community
|
||||
|
||||
- **Documentation**: Complete guides at [claude-mem.ai/docs](https://claude-mem.ai/docs)
|
||||
- **Issues**: Report bugs at [GitHub Issues](https://github.com/thedotmack/claude-mem/issues)
|
||||
- **Feature Requests**: [GitHub Discussions](https://github.com/thedotmack/claude-mem/discussions)
|
||||
- **Community**: Join our [Discord](https://discord.gg/claude-mem) for tips and discussions
|
||||
|
||||
## 📄 License
|
||||
|
||||
This software is free to use but is NOT open source. See [LICENSE](LICENSE) file for complete terms.
|
||||
<p align="center">
|
||||
Claude-Mem seamlessly preserves context across sessions by automatically capturing tool usage observations, generating semantic summaries, and making them available to future sessions. This enables Claude to maintain continuity of knowledge about projects even after sessions end or reconnect.
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Ready to Transform Your Claude Code Experience?
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
npm install -g claude-mem
|
||||
claude-mem install
|
||||
Start a new Claude Code session in the terminal and enter the following commands:
|
||||
|
||||
```
|
||||
> /plugin marketplace add thedotmack/claude-mem
|
||||
|
||||
> /plugin install claude-mem
|
||||
```
|
||||
|
||||
**Your AI assistant is about to get a lot smarter.** 🧠✨
|
||||
Restart Claude Code. Context from previous sessions will automatically appear in new sessions.
|
||||
|
||||
**Key Features:**
|
||||
|
||||
- 🧠 **Persistent Memory** - Context survives across sessions
|
||||
- 📊 **Progressive Disclosure** - Layered memory retrieval with token cost visibility
|
||||
- 🔍 **Skill-Based Search** - Query your project history with mem-search skill (~2,250 token savings)
|
||||
- 🖥️ **Web Viewer UI** - Real-time memory stream at http://localhost:37777
|
||||
- 💻 **Claude Desktop Skill** - Search memory from Claude Desktop conversations
|
||||
- 🔒 **Privacy Control** - Use `<private>` tags to exclude sensitive content from storage
|
||||
- ⚙️ **Context Configuration** - Fine-grained control over what context gets injected
|
||||
- 🤖 **Automatic Operation** - No manual intervention required
|
||||
- 🔗 **Citations** - Reference past decisions with `claude-mem://` URIs
|
||||
- 🧪 **Beta Channel** - Try experimental features like Endless Mode via version switching
|
||||
|
||||
---
|
||||
|
||||
*Built with ❤️ for developers who believe AI assistants should remember and learn from every conversation.*
|
||||
## Documentation
|
||||
|
||||
📚 **[View Full Documentation](docs/)** - Browse markdown docs on GitHub
|
||||
|
||||
💻 **Local Preview**: Run Mintlify docs locally:
|
||||
|
||||
```bash
|
||||
cd docs
|
||||
npx mintlify dev
|
||||
```
|
||||
|
||||
### Getting Started
|
||||
|
||||
- **[Installation Guide](https://docs.claude-mem.ai/installation)** - Quick start & advanced installation
|
||||
- **[Usage Guide](https://docs.claude-mem.ai/usage/getting-started)** - How Claude-Mem works automatically
|
||||
- **[Search Tools](https://docs.claude-mem.ai/usage/search-tools)** - Query your project history with natural language
|
||||
- **[Beta Features](https://docs.claude-mem.ai/beta-features)** - Try experimental features like Endless Mode
|
||||
|
||||
### Best Practices
|
||||
|
||||
- **[Context Engineering](https://docs.claude-mem.ai/context-engineering)** - AI agent context optimization principles
|
||||
- **[Progressive Disclosure](https://docs.claude-mem.ai/progressive-disclosure)** - Philosophy behind Claude-Mem's context priming strategy
|
||||
|
||||
### Architecture
|
||||
|
||||
- **[Overview](https://docs.claude-mem.ai/architecture/overview)** - System components & data flow
|
||||
- **[Architecture Evolution](https://docs.claude-mem.ai/architecture-evolution)** - The journey from v3 to v5
|
||||
- **[Hooks Architecture](https://docs.claude-mem.ai/hooks-architecture)** - How Claude-Mem uses lifecycle hooks
|
||||
- **[Hooks Reference](https://docs.claude-mem.ai/architecture/hooks)** - 7 hook scripts explained
|
||||
- **[Worker Service](https://docs.claude-mem.ai/architecture/worker-service)** - HTTP API & Bun management
|
||||
- **[Database](https://docs.claude-mem.ai/architecture/database)** - SQLite schema & FTS5 search
|
||||
- **[Search Architecture](https://docs.claude-mem.ai/architecture/search-architecture)** - Hybrid search with Chroma vector database
|
||||
|
||||
### Configuration & Development
|
||||
|
||||
- **[Configuration](https://docs.claude-mem.ai/configuration)** - Environment variables & settings
|
||||
- **[Development](https://docs.claude-mem.ai/development)** - Building, testing, contributing
|
||||
- **[Troubleshooting](https://docs.claude-mem.ai/troubleshooting)** - Common issues & solutions
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Session Start → Inject recent observations as context │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ User Prompts → Create session, save user prompts │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Tool Executions → Capture observations (Read, Write, etc.) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Worker Processes → Extract learnings via Claude Agent SDK │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Session Ends → Generate summary, ready for next session │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Core Components:**
|
||||
|
||||
1. **5 Lifecycle Hooks** - SessionStart, UserPromptSubmit, PostToolUse, Stop, SessionEnd (6 hook scripts)
|
||||
2. **Smart Install** - Cached dependency checker (pre-hook script, not a lifecycle hook)
|
||||
3. **Worker Service** - HTTP API on port 37777 with web viewer UI and 10 search endpoints, managed by Bun
|
||||
4. **SQLite Database** - Stores sessions, observations, summaries with FTS5 full-text search
|
||||
5. **mem-search Skill** - Natural language queries with progressive disclosure (~2,250 token savings vs MCP)
|
||||
6. **Chroma Vector Database** - Hybrid semantic + keyword search for intelligent context retrieval
|
||||
|
||||
See [Architecture Overview](https://docs.claude-mem.ai/architecture/overview) for details.
|
||||
|
||||
---
|
||||
|
||||
## mem-search Skill
|
||||
|
||||
Claude-Mem provides intelligent search through the mem-search skill that auto-invokes when you ask about past work:
|
||||
|
||||
**How It Works:**
|
||||
- Just ask naturally: *"What did we do last session?"* or *"Did we fix this bug before?"*
|
||||
- Claude automatically invokes the mem-search skill to find relevant context
|
||||
- ~2,250 token savings per session start vs MCP approach
|
||||
|
||||
**Available Search Operations:**
|
||||
|
||||
1. **Search Observations** - Full-text search across observations
|
||||
2. **Search Sessions** - Full-text search across session summaries
|
||||
3. **Search Prompts** - Search raw user requests
|
||||
4. **By Concept** - Find by concept tags (discovery, problem-solution, pattern, etc.)
|
||||
5. **By File** - Find observations referencing specific files
|
||||
6. **By Type** - Find by type (decision, bugfix, feature, refactor, discovery, change)
|
||||
7. **Recent Context** - Get recent session context for a project
|
||||
8. **Timeline** - Get unified timeline of context around a specific point in time
|
||||
9. **Timeline by Query** - Search for observations and get timeline context around best match
|
||||
10. **API Help** - Get search API documentation
|
||||
|
||||
**Example Natural Language Queries:**
|
||||
|
||||
```
|
||||
"What bugs did we fix last session?"
|
||||
"How did we implement authentication?"
|
||||
"What changes were made to worker-service.ts?"
|
||||
"Show me recent work on this project"
|
||||
"What was happening when we added the viewer UI?"
|
||||
```
|
||||
|
||||
See [Search Tools Guide](https://docs.claude-mem.ai/usage/search-tools) for detailed examples.
|
||||
|
||||
---
|
||||
|
||||
## Beta Features & Endless Mode
|
||||
|
||||
Claude-Mem offers a **beta channel** with experimental features. Switch between stable and beta versions directly from the web viewer UI.
|
||||
|
||||
### How to Try Beta
|
||||
|
||||
1. Open http://localhost:37777
|
||||
2. Click Settings (gear icon)
|
||||
3. In **Version Channel**, click "Try Beta (Endless Mode)"
|
||||
4. Wait for the worker to restart
|
||||
|
||||
Your memory data is preserved when switching versions.
|
||||
|
||||
### Endless Mode (Beta)
|
||||
|
||||
The flagship beta feature is **Endless Mode** - a biomimetic memory architecture that dramatically extends session length:
|
||||
|
||||
**The Problem**: Standard Claude Code sessions hit context limits after ~50 tool uses. Each tool adds 1-10k+ tokens, and Claude re-synthesizes all previous outputs on every response (O(N²) complexity).
|
||||
|
||||
**The Solution**: Endless Mode compresses tool outputs into ~500-token observations and transforms the transcript in real-time:
|
||||
|
||||
```
|
||||
Working Memory (Context): Compressed observations (~500 tokens each)
|
||||
Archive Memory (Disk): Full tool outputs preserved for recall
|
||||
```
|
||||
|
||||
**Expected Results**:
|
||||
- ~95% token reduction in context window
|
||||
- ~20x more tool uses before context exhaustion
|
||||
- Linear O(N) scaling instead of quadratic O(N²)
|
||||
- Full transcripts preserved for perfect recall
|
||||
|
||||
**Caveats**: Adds latency (60-90s per tool for observation generation), still experimental.
|
||||
|
||||
See [Beta Features Documentation](https://docs.claude-mem.ai/beta-features) for details.
|
||||
|
||||
---
|
||||
|
||||
## What's New
|
||||
|
||||
**v6.4.9 - Context Configuration Settings:**
|
||||
- 11 new settings for fine-grained control over context injection
|
||||
- Configure token economics display, observation filtering by type/concept
|
||||
- Control number of observations and which fields to display
|
||||
|
||||
**v6.4.0 - Dual-Tag Privacy System:**
|
||||
- `<private>` tags for user-controlled privacy - wrap sensitive content to exclude from storage
|
||||
- System-level `<claude-mem-context>` tags prevent recursive observation storage
|
||||
- Edge processing ensures private content never reaches database
|
||||
|
||||
**v6.3.0 - Version Channel:**
|
||||
- Switch between stable and beta versions from the web viewer UI
|
||||
- Try experimental features like Endless Mode without manual git operations
|
||||
|
||||
**Previous Highlights:**
|
||||
- **v6.0.0**: Major session management & transcript processing improvements
|
||||
- **v5.5.0**: mem-search skill enhancement with 100% effectiveness rate
|
||||
- **v5.4.0**: Skill-based search architecture (~2,250 tokens saved per session)
|
||||
- **v5.1.0**: Web-based viewer UI with real-time updates
|
||||
- **v5.0.0**: Hybrid search with Chroma vector database
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for complete version history.
|
||||
|
||||
---
|
||||
|
||||
## System Requirements
|
||||
|
||||
- **Node.js**: 18.0.0 or higher
|
||||
- **Claude Code**: Latest version with plugin support
|
||||
- **Bun**: JavaScript runtime and process manager (auto-installed if missing)
|
||||
- **uv**: Python package manager for vector search (auto-installed if missing)
|
||||
- **SQLite 3**: For persistent storage (bundled)
|
||||
|
||||
---
|
||||
|
||||
## Key Benefits
|
||||
|
||||
### Progressive Disclosure Context
|
||||
|
||||
- **Layered memory retrieval** mirrors human memory patterns
|
||||
- **Layer 1 (Index)**: See what observations exist with token costs at session start
|
||||
- **Layer 2 (Details)**: Fetch full narratives on-demand via MCP search
|
||||
- **Layer 3 (Perfect Recall)**: Access source code and original transcripts
|
||||
- **Smart decision-making**: Token counts help Claude choose between fetching details or reading code
|
||||
- **Type indicators**: Visual cues (🔴 critical, 🟤 decision, 🔵 informational) highlight observation importance
|
||||
|
||||
### Automatic Memory
|
||||
|
||||
- Context automatically injected when Claude starts
|
||||
- No manual commands or configuration needed
|
||||
- Works transparently in the background
|
||||
|
||||
### Full History Search
|
||||
|
||||
- Search across all sessions and observations
|
||||
- FTS5 full-text search for fast queries
|
||||
- Citations link back to specific observations
|
||||
|
||||
### Structured Observations
|
||||
|
||||
- AI-powered extraction of learnings
|
||||
- Categorized by type (decision, bugfix, feature, etc.)
|
||||
- Tagged with concepts and file references
|
||||
|
||||
### Multi-Prompt Sessions
|
||||
|
||||
- Sessions span multiple user prompts
|
||||
- Context preserved across `/clear` commands
|
||||
- Track entire conversation threads
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
Settings are managed in `~/.claude-mem/settings.json`. The file is auto-created with defaults on first run.
|
||||
|
||||
**Available Settings:**
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| `CLAUDE_MEM_MODEL` | `claude-haiku-4-5` | AI model for observations |
|
||||
| `CLAUDE_MEM_WORKER_PORT` | `37777` | Worker service port |
|
||||
| `CLAUDE_MEM_WORKER_HOST` | `127.0.0.1` | Worker bind address (use `0.0.0.0` for remote access) |
|
||||
| `CLAUDE_MEM_DATA_DIR` | `~/.claude-mem` | Data directory location |
|
||||
| `CLAUDE_MEM_LOG_LEVEL` | `INFO` | Log verbosity (DEBUG, INFO, WARN, ERROR, SILENT) |
|
||||
| `CLAUDE_MEM_PYTHON_VERSION` | `3.13` | Python version for chroma-mcp |
|
||||
| `CLAUDE_CODE_PATH` | _(auto-detect)_ | Path to Claude executable |
|
||||
| `CLAUDE_MEM_CONTEXT_OBSERVATIONS` | `50` | Number of observations to inject at SessionStart |
|
||||
|
||||
**Settings Management:**
|
||||
|
||||
```bash
|
||||
# Edit settings via CLI helper
|
||||
./claude-mem-settings.sh
|
||||
|
||||
# Or edit directly
|
||||
nano ~/.claude-mem/settings.json
|
||||
|
||||
# View current settings
|
||||
curl http://localhost:37777/api/settings
|
||||
```
|
||||
|
||||
**Settings File Format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_MODEL": "claude-haiku-4-5",
|
||||
"CLAUDE_MEM_WORKER_PORT": "37777",
|
||||
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "50"
|
||||
}
|
||||
```
|
||||
|
||||
See [Configuration Guide](https://docs.claude-mem.ai/configuration) for details.
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Clone and build
|
||||
git clone https://github.com/thedotmack/claude-mem.git
|
||||
cd claude-mem
|
||||
npm install
|
||||
npm run build
|
||||
|
||||
# Run tests
|
||||
npm test
|
||||
|
||||
# Start worker
|
||||
npm run worker:start
|
||||
|
||||
# View logs
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
See [Development Guide](https://docs.claude-mem.ai/development) for detailed instructions.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Quick Diagnostic:**
|
||||
|
||||
If you're experiencing issues, describe the problem to Claude and the troubleshoot skill will automatically activate to diagnose and provide fixes.
|
||||
|
||||
**Common Issues:**
|
||||
|
||||
- Worker not starting → `npm run worker:restart`
|
||||
- No context appearing → `npm run test:context`
|
||||
- Database issues → `sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"`
|
||||
- Search not working → Check FTS5 tables exist
|
||||
|
||||
See [Troubleshooting Guide](https://docs.claude-mem.ai/troubleshooting) for complete solutions.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please:
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes with tests
|
||||
4. Update documentation
|
||||
5. Submit a Pull Request
|
||||
|
||||
See [Development Guide](https://docs.claude-mem.ai/development) for contribution workflow.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the **GNU Affero General Public License v3.0** (AGPL-3.0).
|
||||
|
||||
Copyright (C) 2025 Alex Newman (@thedotmack). All rights reserved.
|
||||
|
||||
See the [LICENSE](LICENSE) file for full details.
|
||||
|
||||
**What This Means:**
|
||||
|
||||
- You can use, modify, and distribute this software freely
|
||||
- If you modify and deploy on a network server, you must make your source code available
|
||||
- Derivative works must also be licensed under AGPL-3.0
|
||||
- There is NO WARRANTY for this software
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
- **Documentation**: [docs/](docs/)
|
||||
- **Issues**: [GitHub Issues](https://github.com/thedotmack/claude-mem/issues)
|
||||
- **Repository**: [github.com/thedotmack/claude-mem](https://github.com/thedotmack/claude-mem)
|
||||
- **Author**: Alex Newman ([@thedotmack](https://github.com/thedotmack))
|
||||
|
||||
---
|
||||
|
||||
**Built with Claude Agent SDK** | **Powered by Claude Code** | **Made with TypeScript**
|
||||
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
# Claude Mem v3.3.8
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
### Quick Install (Recommended)
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/thedotmack/claude-mem/main/install.sh | bash
|
||||
```
|
||||
|
||||
### Manual Download
|
||||
Download the appropriate binary for your platform from the [releases page](https://github.com/thedotmack/claude-mem/releases/latest):
|
||||
|
||||
- **Windows x64**: `claude-mem.exe`
|
||||
- **Linux x64**: `claude-mem-linux`
|
||||
- **Linux ARM64**: `claude-mem-linux-arm64`
|
||||
- **macOS ARM64** (Apple Silicon): `claude-mem-macos-arm64`
|
||||
- **macOS x64** (Intel): `claude-mem-macos-x64`
|
||||
|
||||
## 📦 What's Included
|
||||
|
||||
- Multi-platform binaries for Windows, Linux, and macOS
|
||||
- Hook system for customization
|
||||
- Full documentation
|
||||
- MCP server integration for Claude Code
|
||||
|
||||
## 🔧 Supported Platforms
|
||||
|
||||
| Platform | Architecture | Binary Name |
|
||||
|----------|--------------|-------------|
|
||||
| Windows | x64 | claude-mem.exe |
|
||||
| Linux | x64 | claude-mem-linux |
|
||||
| Linux | ARM64 | claude-mem-linux-arm64 |
|
||||
| macOS | ARM64 (Apple Silicon) | claude-mem-macos-arm64 |
|
||||
| macOS | x64 (Intel) | claude-mem-macos-x64 |
|
||||
|
||||
## 📝 License
|
||||
|
||||
Binary distribution under proprietary license (free to use).
|
||||
Hook files under MIT license (open source).
|
||||
See LICENSE file for details.
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
name: mem-search
|
||||
description: Search your persistent memory database from previous coding sessions. Use when asked about past work, decisions, bugs fixed, or development history.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
Search your local memory database for past sessions, decisions, code changes, and development history. This skill uses the `mem-search` MCP server tools.
|
||||
|
||||
## Available MCP tools
|
||||
|
||||
Use these tools from the `mem-search` MCP server:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `search` | Unified search across all memory types |
|
||||
| `decisions` | Find architectural/design decisions |
|
||||
| `changes` | Find code changes and refactorings |
|
||||
| `timeline` | Get observations around a specific point in time |
|
||||
| `find_by_file` | Find observations for specific files |
|
||||
| `find_by_type` | Filter by type (decision, bugfix, feature, refactor, discovery, change) |
|
||||
| `find_by_concept` | Find by concept tags |
|
||||
| `how_it_works` | Understand system architecture and design patterns |
|
||||
|
||||
## Common parameters
|
||||
|
||||
- `query` - Natural language search query
|
||||
- `limit` - Max results (1-100, default 20)
|
||||
- `format` - `index` for titles only (recommended), `full` for complete content
|
||||
- `type` - Filter: observations, sessions, or prompts
|
||||
- `obs_type` - Filter observation type: decision, bugfix, feature, refactor, discovery, change
|
||||
|
||||
## When to use
|
||||
|
||||
- "Did we already solve this?"
|
||||
- "How did we do X last time?"
|
||||
- "Find the bug fix for..."
|
||||
- "What decisions did we make about..."
|
||||
- "Show me changes to [file]"
|
||||
- "What work did we do on [project]?"
|
||||
|
||||
## Setup requirement
|
||||
|
||||
The `mem-search` MCP server must be configured in Claude Desktop settings. See MCP configuration docs.
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,113 @@
|
||||
# Branch Switching Test Plan: feature/bun-executable
|
||||
|
||||
## Overview
|
||||
This document validates that switching to the `feature/bun-executable` branch will be seamless for users.
|
||||
|
||||
## Branch Switching Mechanism
|
||||
|
||||
When a user switches branches via the Settings UI:
|
||||
|
||||
1. **Branch Switch Request**: User selects `feature/bun-executable` from Settings UI
|
||||
2. **Validation**: SettingsRoutes validates branch name against allowed list
|
||||
3. **Git Operations**: BranchManager performs:
|
||||
- Discard local changes (`git checkout -- .` and `git clean -fd`)
|
||||
- Fetch from origin (`git fetch origin`)
|
||||
- Checkout target branch (`git checkout feature/bun-executable`)
|
||||
- Pull latest (`git pull origin feature/bun-executable`)
|
||||
4. **Install Dependencies**:
|
||||
- Clear install marker (`.install-version`)
|
||||
- Run `npm install` (2 minute timeout)
|
||||
5. **Worker Restart**: Worker process exits and PM2/supervisor restarts it
|
||||
|
||||
## Feature Branch Changes
|
||||
|
||||
The `feature/bun-executable` branch makes these key changes:
|
||||
|
||||
### Dependencies Removed
|
||||
- `better-sqlite3` → Uses Bun's built-in SQLite
|
||||
- `pm2` → Custom worker CLI with process management
|
||||
- `@types/better-sqlite3`
|
||||
|
||||
### New Features
|
||||
- Auto-installation of Bun runtime in smart-install.js
|
||||
- Simplified worker management via worker-cli.js
|
||||
- No native module compilation required (better-sqlite3 removed)
|
||||
|
||||
## Installation Validation
|
||||
|
||||
### Current Branch → feature/bun-executable
|
||||
|
||||
**Step 1: Branch Switch (BranchManager)**
|
||||
```bash
|
||||
git checkout feature/bun-executable
|
||||
git pull origin feature/bun-executable
|
||||
rm .install-version
|
||||
npm install # ✅ Works - package.json is npm-compatible
|
||||
```
|
||||
|
||||
**Step 2: First Hook Execution**
|
||||
```bash
|
||||
node plugin/scripts/context-hook.js
|
||||
↓
|
||||
Calls smart-install.js
|
||||
↓
|
||||
Checks if Bun installed → Auto-installs if missing
|
||||
↓
|
||||
Runs: bun install (if needed)
|
||||
```
|
||||
|
||||
**Step 3: Worker Management**
|
||||
- Old: PM2 manages worker-service.cjs
|
||||
- New: worker-cli.js manages worker as background process
|
||||
- Transition: Automatic on first worker start command
|
||||
|
||||
## Seamless Installation Checklist
|
||||
|
||||
- [x] **Branch Validation**: `feature/bun-executable` added to allowedBranches list
|
||||
- [x] **npm install Compatible**: Feature branch package.json works with npm
|
||||
- [x] **No Breaking Changes**: No hooks that would fail on first run
|
||||
- [x] **Auto-Install**: smart-install.js automatically installs Bun if missing
|
||||
- [x] **Graceful Degradation**: Scripts fall back to node if Bun unavailable
|
||||
- [x] **No Manual Steps**: User just clicks "Switch Branch" in UI
|
||||
|
||||
## Potential Issues & Mitigations
|
||||
|
||||
### Issue 1: Bun Not in PATH After Install
|
||||
**Mitigation**: smart-install.js checks common Bun installation paths and provides clear instructions to user
|
||||
|
||||
### Issue 2: PM2 vs Worker CLI Transition
|
||||
**Mitigation**: Old PM2 worker continues running, new worker CLI starts separately. User can manually stop old PM2 worker if needed.
|
||||
|
||||
### Issue 3: Windows Compatibility
|
||||
**Mitigation**: Feature branch uses PowerShell installer for Windows, curl for Unix/macOS
|
||||
|
||||
## Test Results
|
||||
|
||||
### Unit Tests
|
||||
```bash
|
||||
✓ tests/branch-selector.test.ts (5 tests)
|
||||
✓ should allow main branch
|
||||
✓ should allow beta/7.0 branch
|
||||
✓ should allow feature/bun-executable branch
|
||||
✓ should reject invalid branch names
|
||||
✓ should have exactly 3 allowed branches
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
```bash
|
||||
✓ All existing tests pass (42 tests)
|
||||
✓ No regressions introduced
|
||||
✓ TypeScript compilation successful
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
✅ **SEAMLESS INSTALLATION VALIDATED**
|
||||
|
||||
The installation process is seamless because:
|
||||
1. Branch switching uses standard git operations
|
||||
2. `npm install` works on feature branch
|
||||
3. Bun auto-installs on first hook execution
|
||||
4. No manual intervention required
|
||||
5. Clear error messages if issues occur
|
||||
6. Backward compatible with existing installations
|
||||
@@ -0,0 +1,561 @@
|
||||
# Claude-Mem Smart Install & Plugin Hooks - Comprehensive Analysis
|
||||
|
||||
**Generated:** 2025-12-09
|
||||
**Scope:** Smart install system, all plugin hooks, cross-platform compatibility, error handling, edge cases
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
This report provides a comprehensive analysis of claude-mem's smart install system and plugin hook infrastructure. The analysis focuses on cross-platform compatibility, error handling patterns, artificial blockers, and edge case handling.
|
||||
|
||||
**Key Findings:**
|
||||
- ✅ Overall architecture is well-designed with clear separation of concerns
|
||||
- ⚠️ Multiple cross-platform compatibility issues identified
|
||||
- ⚠️ Several silent failure patterns that hinder debugging
|
||||
- ⚠️ Artificial blockers that could prevent legitimate use cases
|
||||
- ⚠️ Inconsistent timeout values across different components
|
||||
- ✅ No nested try-catch anti-patterns found
|
||||
|
||||
---
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### Smart Install System Flow
|
||||
|
||||
```
|
||||
User Invokes Hook
|
||||
↓
|
||||
ensureWorkerRunning() [worker-utils.ts]
|
||||
↓
|
||||
isWorkerHealthy() → fetch /health endpoint
|
||||
↓
|
||||
├─ [HEALTHY] → Continue
|
||||
└─ [UNHEALTHY] → startWorker()
|
||||
↓
|
||||
├─ [Windows] → PowerShell Start-Process (hidden window)
|
||||
└─ [Unix] → Bun start ecosystem.config.cjs
|
||||
↓
|
||||
Wait for health check (15 retries × 1000ms)
|
||||
↓
|
||||
├─ [SUCCESS] → Continue
|
||||
└─ [FAILURE] → Throw error with manual recovery instructions
|
||||
```
|
||||
|
||||
### Plugin Hook Lifecycle
|
||||
|
||||
1. **SessionStart** (context-hook.ts + user-message-hook.ts)
|
||||
- context-hook: Fetches context via HTTP/curl
|
||||
- user-message-hook: Displays context to user via stderr
|
||||
|
||||
2. **UserPromptSubmit** (new-hook.ts)
|
||||
- Creates/retrieves SDK session
|
||||
- Strips privacy tags from prompt
|
||||
- Initializes session via HTTP
|
||||
|
||||
3. **PostToolUse** (save-hook.ts)
|
||||
- Filters skipped tools
|
||||
- Sends observation to worker via HTTP
|
||||
|
||||
4. **Stop** (summary-hook.ts)
|
||||
- Parses transcript JSONL
|
||||
- Extracts last user/assistant messages
|
||||
- Requests summary generation via HTTP
|
||||
|
||||
5. **SessionEnd** (cleanup-hook.ts)
|
||||
- Marks session complete
|
||||
- Fire-and-forget HTTP request
|
||||
|
||||
---
|
||||
|
||||
## Cross-Platform Compatibility Issues
|
||||
|
||||
### 🔴 CRITICAL: curl Dependency (context-hook.ts)
|
||||
|
||||
**Location:** `src/hooks/context-hook.ts:32`
|
||||
|
||||
```typescript
|
||||
const result = execSync(`curl -s "${url}"`, { encoding: "utf-8", timeout: 5000 });
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
1. **Windows Compatibility:** curl is not guaranteed to be available on Windows systems (though included in Windows 10 1803+, it may be missing on older systems or custom installations)
|
||||
2. **Error Handling:** No try-catch around execSync - will throw unhandled exception if curl fails
|
||||
3. **Redundancy:** Uses curl when JavaScript's native `fetch` is already used everywhere else in the codebase
|
||||
|
||||
**Impact:** High - SessionStart hook will crash if curl is unavailable or returns non-zero exit code
|
||||
|
||||
**Edge Cases:**
|
||||
- Corporate proxies blocking curl
|
||||
- Systems without curl in PATH
|
||||
- curl returning non-zero exit with valid output (warnings, etc.)
|
||||
|
||||
**Recommendation:**
|
||||
```typescript
|
||||
// Replace curl with fetch (already used in user-message-hook.ts)
|
||||
const response = await fetch(url, { signal: AbortSignal.timeout(5000) });
|
||||
const result = await response.text();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🟡 MEDIUM: Platform-Specific Process Spawning (worker-utils.ts)
|
||||
|
||||
**Location:** `src/shared/worker-utils.ts:55-93`
|
||||
|
||||
**Windows Implementation:**
|
||||
```typescript
|
||||
spawnSync('powershell.exe', [
|
||||
'-NoProfile',
|
||||
'-NonInteractive',
|
||||
'-Command',
|
||||
`Start-Process -FilePath 'node' -ArgumentList '${workerScript}' -WorkingDirectory '${MARKETPLACE_ROOT}' -WindowStyle Hidden`
|
||||
])
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
1. **PowerShell Dependency:** Assumes PowerShell is available and in PATH
|
||||
2. **Command Injection Risk:** Worker script path inserted directly into command string without escaping
|
||||
3. **Process Monitoring:** Windows approach launches detached process with no Bun monitoring - harder to debug/restart
|
||||
4. **Health Check Timeout:** Comment says "Windows needs longer timeouts" but timeout is same for all platforms (500ms)
|
||||
|
||||
**Edge Cases:**
|
||||
- Windows systems with PowerShell execution policy restrictions
|
||||
- Paths containing single quotes or special characters
|
||||
- Windows subsystem for Linux (WSL) environments
|
||||
- Wine/Proton compatibility layers
|
||||
|
||||
**Unix Implementation:**
|
||||
```typescript
|
||||
const localBunBase = path.join(MARKETPLACE_ROOT, 'node_modules', '.bin', 'bun');
|
||||
const bunCommand = existsSync(localBunBase) ? localBunBase : 'bun';
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
1. **Bun Dependency:** Falls back to global bun if local not found, but doesn't verify it exists
|
||||
2. **Silent Failure:** If Bun not installed globally, spawnSync will fail with cryptic ENOENT error
|
||||
|
||||
**Recommendation:**
|
||||
- Add bun existence check before spawn
|
||||
- Implement consistent process monitoring across platforms
|
||||
- Add path escaping for Windows command construction
|
||||
- Actually implement longer timeout for Windows if needed
|
||||
|
||||
---
|
||||
|
||||
### 🟡 MEDIUM: Git Dependency (paths.ts)
|
||||
|
||||
**Location:** `src/shared/paths.ts:89-97`
|
||||
|
||||
```typescript
|
||||
export function getCurrentProjectName(): string {
|
||||
try {
|
||||
const gitRoot = execSync('git rev-parse --show-toplevel', {
|
||||
cwd: process.cwd(),
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'ignore']
|
||||
}).trim();
|
||||
return basename(gitRoot);
|
||||
} catch {
|
||||
return basename(process.cwd());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Issues:**
|
||||
1. **Git Assumption:** Assumes git is installed and available in PATH
|
||||
2. **Non-Git Projects:** Silently falls back to cwd basename, but this behavior is undocumented
|
||||
|
||||
**Edge Cases:**
|
||||
- Projects not using git
|
||||
- Monorepos where cwd !== git root is desired
|
||||
- Systems without git installed
|
||||
|
||||
**Status:** ✅ Already handled with fallback, but could benefit from debug logging
|
||||
|
||||
---
|
||||
|
||||
## Error Handling Analysis
|
||||
|
||||
### 🔴 CRITICAL: Silent Failures Without Logging
|
||||
|
||||
#### 1. Settings File Loading (early-settings.ts:20-28)
|
||||
|
||||
```typescript
|
||||
try {
|
||||
if (existsSync(SETTINGS_PATH)) {
|
||||
const data = JSON.parse(readFileSync(SETTINGS_PATH, 'utf-8'));
|
||||
const fileValue = data.env?.[key];
|
||||
if (fileValue !== undefined) return fileValue;
|
||||
}
|
||||
} catch {
|
||||
// Fail silently - fall through to env var
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:**
|
||||
- Invalid JSON in settings file fails silently
|
||||
- File read permission errors fail silently
|
||||
- Users have no way to know their settings file is being ignored
|
||||
|
||||
**Impact:** High - Users may think settings are applied when they're actually using defaults
|
||||
|
||||
**Recommendation:**
|
||||
```typescript
|
||||
} catch (error) {
|
||||
logger.warn('SETTINGS', 'Failed to load settings file', { path: SETTINGS_PATH }, error);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 2. Worker Startup Failure (worker-utils.ts:104-107)
|
||||
|
||||
```typescript
|
||||
try {
|
||||
// ... worker startup logic ...
|
||||
} catch (error) {
|
||||
// Failed to start worker
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:**
|
||||
- Catches ALL errors during worker startup
|
||||
- Returns boolean with no information about what failed
|
||||
- User only gets generic error after all retries exhausted
|
||||
|
||||
**Impact:** High - Makes debugging worker startup issues extremely difficult
|
||||
|
||||
**Recommendation:**
|
||||
```typescript
|
||||
} catch (error) {
|
||||
logger.error('WORKER', 'Failed to start worker', {}, error as Error);
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 3. Worker Health Check (worker-utils.ts:30-40)
|
||||
|
||||
```typescript
|
||||
async function isWorkerHealthy(): Promise<boolean> {
|
||||
try {
|
||||
const port = getWorkerPort();
|
||||
const response = await fetch(`http://127.0.0.1:${port}/health`, {
|
||||
signal: AbortSignal.timeout(HEALTH_CHECK_TIMEOUT_MS)
|
||||
});
|
||||
return response.ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:**
|
||||
- Network errors, timeouts, and non-200 responses all indistinguishable
|
||||
- No logging at all - completely silent
|
||||
|
||||
**Impact:** Medium - Hard to debug why health checks fail
|
||||
|
||||
**Recommendation:**
|
||||
```typescript
|
||||
} catch (error) {
|
||||
logger.debug('WORKER', 'Health check failed', { port }, error);
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### 4. Tool Formatting (logger.ts:122-124)
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const input = typeof toolInput === 'string' ? JSON.parse(toolInput) : toolInput;
|
||||
// ...
|
||||
} catch {
|
||||
return toolName;
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:**
|
||||
- Invalid JSON in tool input fails silently
|
||||
- Could mask data corruption issues
|
||||
|
||||
**Impact:** Low - Only affects log formatting
|
||||
|
||||
**Status:** ✅ Acceptable for log formatting, but could log at DEBUG level
|
||||
|
||||
---
|
||||
|
||||
### 🟢 GOOD: No Nested Try-Catch Anti-Patterns
|
||||
|
||||
Analysis confirmed zero instances of nested try-catch blocks. Error handling is consistently at single level per function.
|
||||
|
||||
---
|
||||
|
||||
## Artificial Blockers & Unnecessary Checks
|
||||
|
||||
### 🔴 CRITICAL: First-Run Detection (user-message-hook.ts:14-40)
|
||||
|
||||
```typescript
|
||||
const nodeModulesPath = join(pluginDir, 'node_modules');
|
||||
|
||||
if (!existsSync(nodeModulesPath)) {
|
||||
// Show first-time setup message
|
||||
console.error(`...`);
|
||||
process.exit(3);
|
||||
}
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
1. **False Positive:** Will trigger if user manually deletes node_modules (e.g., for troubleshooting)
|
||||
2. **Installation Race:** Could fail if installation is still in progress
|
||||
3. **Hook-Level Check:** Runs on EVERY SessionStart, not just actual first run
|
||||
|
||||
**Impact:** High - Prevents usage until node_modules exists, even if dependencies are installed elsewhere
|
||||
|
||||
**Edge Cases:**
|
||||
- User runs `rm -rf node_modules` for troubleshooting
|
||||
- Package manager installation interrupted
|
||||
- Symlinked node_modules (some package managers)
|
||||
|
||||
**Recommendation:**
|
||||
- Use a `.first-run-complete` marker file instead
|
||||
- Move check to npm postinstall script
|
||||
- Make check more robust (check for specific required modules)
|
||||
|
||||
---
|
||||
|
||||
### 🟡 MEDIUM: Overly Specific Validation (paths.ts:117-119)
|
||||
|
||||
```typescript
|
||||
if (!existsSync(join(commandsDir, 'save.md'))) {
|
||||
throw new Error('Package commands directory missing required files');
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:**
|
||||
- Checks for ONE specific file to validate entire directory
|
||||
- Hardcoded filename could break if files reorganized
|
||||
- Error message doesn't specify what's missing
|
||||
|
||||
**Impact:** Medium - Could prevent package from working after internal refactoring
|
||||
|
||||
**Recommendation:**
|
||||
- Remove check entirely (let actual command invocation fail with better error)
|
||||
- Or check all required files if validation is critical
|
||||
|
||||
---
|
||||
|
||||
### 🟡 MEDIUM: Duplicate Health Endpoints
|
||||
|
||||
**Locations:**
|
||||
- `src/services/worker-service.ts:107` - `/api/health`
|
||||
- `src/services/worker/http/routes/ViewerRoutes.ts:27` - `/health`
|
||||
|
||||
**Usage:**
|
||||
- `worker-utils.ts` uses `/health`
|
||||
- `mcp-server.ts` uses `/api/health`
|
||||
|
||||
**Problem:**
|
||||
- Redundant endpoints doing the same thing
|
||||
- Inconsistent usage across codebase
|
||||
- Maintenance burden
|
||||
|
||||
**Impact:** Low - Both work, but creates confusion
|
||||
|
||||
**Recommendation:**
|
||||
- Standardize on `/api/health` (follows REST convention)
|
||||
- Remove `/health` endpoint
|
||||
- Update worker-utils.ts to use `/api/health`
|
||||
|
||||
---
|
||||
|
||||
## Timeout Configuration Issues
|
||||
|
||||
### Inconsistent Timeouts Across Components
|
||||
|
||||
| Component | Timeout | Location | Purpose |
|
||||
|-----------|---------|----------|---------|
|
||||
| Health check | 500ms | worker-utils.ts:13 | Check if worker alive |
|
||||
| Worker startup wait | 1000ms | worker-utils.ts:14 | Wait between health checks |
|
||||
| Worker startup retries | 15x | worker-utils.ts:15 | Max retries (15s total) |
|
||||
| Hook HTTP requests | 2000ms | cleanup-hook.ts:61, save-hook.ts:70, summary-hook.ts:164 | Send data to worker |
|
||||
| New hook session init | 5000ms | new-hook.ts:129 | Initialize session |
|
||||
| Context hook fetch | 5000ms | context-hook.ts:32 | Fetch context via curl |
|
||||
| User message hook | 5000ms | user-message-hook.ts:52 | Fetch context display |
|
||||
|
||||
**Problems:**
|
||||
1. **Health Check Too Aggressive:** 500ms may be too short for loaded systems or slow network
|
||||
2. **No Platform Adjustment:** Comment says "Windows needs longer timeouts" but values are same
|
||||
3. **Hook Timeout Variation:** Some hooks use 2s, others use 5s with no clear reasoning
|
||||
|
||||
**Recommendations:**
|
||||
- Increase health check timeout to 1000ms minimum
|
||||
- Actually implement longer timeouts for Windows
|
||||
- Standardize hook timeouts to 5000ms across the board
|
||||
- Make timeouts configurable via settings
|
||||
|
||||
---
|
||||
|
||||
## Edge Case Analysis
|
||||
|
||||
### Handled Well ✅
|
||||
|
||||
1. **JSONL Parsing:** summary-hook.ts continues on malformed lines (60-64, 117-121)
|
||||
2. **Git Not Available:** paths.ts falls back to cwd basename (89-97)
|
||||
3. **Settings File Missing:** early-settings.ts falls back to env vars and defaults (20-28)
|
||||
4. **Privacy Tags:** new-hook.ts handles fully-private prompts (99-109)
|
||||
5. **Tool Skipping:** save-hook.ts filters low-value tools (24-30)
|
||||
|
||||
### Missing Edge Case Handling ⚠️
|
||||
|
||||
1. **curl Failure:** context-hook.ts has no error handling for curl failures
|
||||
2. **Bun Not Installed:** worker-utils.ts assumes bun exists globally
|
||||
3. **PowerShell Restrictions:** worker-utils.ts doesn't check execution policy
|
||||
4. **Concurrent Worker Starts:** No locking to prevent multiple hooks from starting worker simultaneously
|
||||
5. **Port Already In Use:** No detection or recovery if worker port is taken
|
||||
6. **Zombie Processes:** Windows approach doesn't track PIDs, can't detect/kill zombies
|
||||
|
||||
---
|
||||
|
||||
## Recommendations Summary
|
||||
|
||||
### High Priority 🔴
|
||||
|
||||
1. **Replace curl with fetch** in context-hook.ts
|
||||
- Eliminates external dependency
|
||||
- Consistent with rest of codebase
|
||||
- Better error handling
|
||||
|
||||
2. **Add logging to silent failures**
|
||||
- early-settings.ts: Log when settings file fails to load
|
||||
- worker-utils.ts: Log startup failures with details
|
||||
- worker-utils.ts: Log health check failures at debug level
|
||||
|
||||
3. **Fix first-run detection**
|
||||
- Use marker file instead of node_modules check
|
||||
- More reliable and intentional
|
||||
|
||||
### Medium Priority 🟡
|
||||
|
||||
4. **Verify Bun availability** before attempting to use it
|
||||
- Check existence before spawn
|
||||
- Provide clear error message if missing
|
||||
|
||||
5. **Implement platform-specific timeouts**
|
||||
- Actually use longer timeouts on Windows as comment suggests
|
||||
- Make timeouts configurable
|
||||
|
||||
6. **Standardize health endpoints**
|
||||
- Remove duplicate `/health` endpoint
|
||||
- Use `/api/health` everywhere
|
||||
|
||||
7. **Add path escaping** for Windows PowerShell commands
|
||||
- Prevent injection issues
|
||||
- Handle paths with special characters
|
||||
|
||||
### Low Priority 🟢
|
||||
|
||||
8. **Standardize HTTP timeouts** across all hooks
|
||||
9. **Add concurrent startup protection** (locking mechanism)
|
||||
10. **Improve error messages** with actionable recovery steps
|
||||
|
||||
---
|
||||
|
||||
## Testing Recommendations
|
||||
|
||||
### Cross-Platform Testing Needed
|
||||
|
||||
1. **Windows Environments:**
|
||||
- Windows 10 (various versions)
|
||||
- Windows 11
|
||||
- Windows Server
|
||||
- WSL/WSL2
|
||||
- PowerShell execution policies (Restricted, RemoteSigned, Unrestricted)
|
||||
|
||||
2. **Unix Environments:**
|
||||
- macOS (Intel + Apple Silicon)
|
||||
- Linux (Ubuntu, Fedora, Arch)
|
||||
- FreeBSD
|
||||
|
||||
3. **Edge Environments:**
|
||||
- Docker containers
|
||||
- CI/CD environments
|
||||
- Systems without git installed
|
||||
- Systems without curl (or with restricted curl)
|
||||
- Corporate networks with proxies
|
||||
- Low-spec systems (slow startup)
|
||||
|
||||
### Test Scenarios
|
||||
|
||||
1. **Cold Start:** First run with no existing data
|
||||
2. **Corrupt Settings:** Invalid JSON in settings.json
|
||||
3. **Missing Dependencies:** No Bun, no git, no curl
|
||||
4. **Port Conflicts:** Worker port already in use
|
||||
5. **Rapid Hook Invocations:** Multiple hooks trying to start worker simultaneously
|
||||
6. **Permission Issues:** Read-only filesystem, restricted execution
|
||||
7. **Network Issues:** Localhost blocked, slow network
|
||||
|
||||
---
|
||||
|
||||
## Code Quality Assessment
|
||||
|
||||
### Strengths ✅
|
||||
|
||||
- Clean separation of concerns (hooks → worker → database)
|
||||
- No nested try-catch anti-patterns
|
||||
- Consistent use of modern async/await
|
||||
- Good use of TypeScript for type safety
|
||||
- Idempotent database operations
|
||||
- Clear documentation in critical sections
|
||||
|
||||
### Weaknesses ⚠️
|
||||
|
||||
- Silent failures hinder debugging
|
||||
- Inconsistent error handling patterns
|
||||
- Platform-specific code not fully tested/documented
|
||||
- Timeout configuration hardcoded and inconsistent
|
||||
- Some artificial blockers prevent legitimate use cases
|
||||
|
||||
### Technical Debt
|
||||
|
||||
- Duplicate health endpoints
|
||||
- curl dependency when fetch available
|
||||
- Bun dependency on Unix but not Windows (inconsistent monitoring)
|
||||
- First-run detection using node_modules existence
|
||||
- Hardcoded timeout values
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The claude-mem smart install and plugin hook system is architecturally sound with a well-designed separation of concerns. However, several cross-platform compatibility issues and silent failure patterns could cause problems in production, particularly on Windows systems or in edge case scenarios.
|
||||
|
||||
The highest priority improvements are:
|
||||
1. Removing the curl dependency
|
||||
2. Adding proper logging to silent failures
|
||||
3. Fixing the fragile first-run detection
|
||||
4. Verifying external dependencies before use
|
||||
|
||||
These changes would significantly improve debuggability and cross-platform reliability without requiring major architectural changes.
|
||||
|
||||
---
|
||||
|
||||
**Analysis Methodology:**
|
||||
- Systematic review of all TypeScript source files
|
||||
- Static analysis of error handling patterns
|
||||
- Cross-platform compatibility assessment
|
||||
- Edge case identification through code path analysis
|
||||
- Comparison against best practices and KISS principles
|
||||
|
||||
**Files Analyzed:**
|
||||
- src/hooks/*.ts (6 files)
|
||||
- src/services/worker-service.ts
|
||||
- src/services/worker/*.ts (10+ files)
|
||||
- src/servers/mcp-server.ts
|
||||
- src/shared/*.ts (worker-utils, early-settings, paths)
|
||||
- src/utils/*.ts (logger, silent-debug, tag-stripping)
|
||||
@@ -0,0 +1,360 @@
|
||||
# Dual-Tag System Architecture
|
||||
|
||||
**Date**: 2025-11-30
|
||||
**Branch**: `feature/meta-observation-control`
|
||||
**Status**: Implemented
|
||||
**Based on**: PR #105 dual-tag system
|
||||
|
||||
## Overview
|
||||
|
||||
The dual-tag system provides fine-grained control over what content gets persisted in claude-mem's observation database. It uses an edge processing pattern to filter tagged content at the hook layer before it reaches the worker service.
|
||||
|
||||
## The Two Tags
|
||||
|
||||
### Tag 1: `<private>`
|
||||
**Purpose**: User-controlled privacy
|
||||
**Status**: User-facing feature (documented)
|
||||
**Use case**: Users wrap content they don't want persisted
|
||||
|
||||
```xml
|
||||
<private>
|
||||
This content won't be stored in observations
|
||||
</private>
|
||||
```
|
||||
|
||||
**Examples**:
|
||||
- Sensitive information (API keys, credentials, internal URLs)
|
||||
- Temporary context (deadlines, personal notes)
|
||||
- Debug output (logs, stack traces)
|
||||
- Exploratory prompts (brainstorming, hypotheticals)
|
||||
|
||||
### Tag 2: `<claude-mem-context>`
|
||||
**Purpose**: System-level meta-observation control
|
||||
**Status**: Infrastructure-ready (not user-facing yet)
|
||||
**Use case**: Prevents recursive storage when real-time context injection is active
|
||||
|
||||
```xml
|
||||
<claude-mem-context>
|
||||
# Relevant Context from Past Sessions
|
||||
|
||||
[Auto-injected past observations...]
|
||||
</claude-mem-context>
|
||||
```
|
||||
|
||||
**Context**: This tag is used by the real-time context injection feature (not yet shipped). When past observations are injected into new prompts, they're wrapped in this tag to prevent them from being re-stored as new observations (recursive storage problem).
|
||||
|
||||
## Architecture Pattern: Edge Processing
|
||||
|
||||
**Principle**: "Process at edge, send clean data to server"
|
||||
|
||||
The dual-tag system follows the edge processing pattern from hooks-in-composition:
|
||||
|
||||
```text
|
||||
UserPrompt → [Hook Layer] → Worker → Database
|
||||
↑
|
||||
Filter here
|
||||
(strip tags at edge)
|
||||
```
|
||||
|
||||
### Data Flow
|
||||
|
||||
**Without Filtering** (broken):
|
||||
```
|
||||
UserPrompt with <private> → PostToolUse hook → Worker → Memory Agent → Database
|
||||
↓
|
||||
Private content stored
|
||||
```
|
||||
|
||||
**With Edge Processing** (correct):
|
||||
```
|
||||
UserPrompt with <private> → PostToolUse hook → stripMemoryTags() → Worker → Memory Agent → Database
|
||||
↑ ↓
|
||||
Filter at edge Only clean data stored
|
||||
```
|
||||
|
||||
## Implementation
|
||||
|
||||
### File: `src/hooks/save-hook.ts`
|
||||
|
||||
**Function Added** (lines 31-53):
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Strip memory tags to prevent recursive storage and enable privacy control
|
||||
*/
|
||||
function stripMemoryTags(content: string): string {
|
||||
if (typeof content !== 'string') {
|
||||
silentDebug('[save-hook] stripMemoryTags received non-string:', { type: typeof content });
|
||||
return '{}'; // Safe default for JSON context
|
||||
}
|
||||
|
||||
return content
|
||||
.replace(/<claude-mem-context>[\s\S]*?<\/claude-mem-context>/g, '')
|
||||
.replace(/<private>[\s\S]*?<\/private>/g, '')
|
||||
.trim();
|
||||
}
|
||||
```
|
||||
|
||||
**Application** (lines 95-100):
|
||||
|
||||
```typescript
|
||||
tool_input: tool_input !== undefined
|
||||
? stripMemoryTags(JSON.stringify(tool_input))
|
||||
: '{}',
|
||||
tool_response: tool_response !== undefined
|
||||
? stripMemoryTags(JSON.stringify(tool_response))
|
||||
: '{}',
|
||||
```
|
||||
|
||||
### File: `tests/strip-memory-tags.test.ts`
|
||||
|
||||
**Test Coverage**: 19 tests across 4 categories:
|
||||
|
||||
1. **Basic Functionality** (7 tests)
|
||||
- Strip `<claude-mem-context>` tags
|
||||
- Strip `<private>` tags
|
||||
- Strip both tag types
|
||||
- Handle nested tags
|
||||
- Multiline content
|
||||
- Multiple tags
|
||||
- Empty results
|
||||
|
||||
2. **Edge Cases** (5 tests)
|
||||
- Malformed tags (unclosed)
|
||||
- Tag-like strings (not actual tags)
|
||||
- Very large content (10k+ chars)
|
||||
- Whitespace trimming
|
||||
- Strings without tags
|
||||
|
||||
3. **Type Safety** (5 tests)
|
||||
- Non-string inputs (number, null, undefined, object, array)
|
||||
- All return safe default '{}'
|
||||
|
||||
4. **Real-World Scenarios** (2 tests)
|
||||
- JSON.stringify output
|
||||
- Efficient large content handling
|
||||
|
||||
**All tests passing** ✅ (19/19)
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### 1. Always Active (No Configuration)
|
||||
|
||||
**Decision**: Tag stripping is always on, no environment variable needed
|
||||
**Rationale**: Privacy and anti-recursion protection should be default, not opt-in
|
||||
|
||||
### 2. Edge Processing (Not Worker-Level)
|
||||
|
||||
**Decision**: Filter at hook layer before sending to worker
|
||||
**Rationale**:
|
||||
- Keeps worker service simple
|
||||
- Follows one-way data stream
|
||||
- No worker changes needed
|
||||
- Hook becomes a filter/gateway
|
||||
|
||||
### 3. Defensive Coding with Silent Debug
|
||||
|
||||
**Decision**: Handle non-string inputs with silentDebug, return safe default
|
||||
**Rationale**:
|
||||
- Never block the agent (hooks-in-composition principle)
|
||||
- Log issues for observability
|
||||
- Safe fallback maintains system stability
|
||||
|
||||
### 4. Both Tags Now (Progressive Enhancement)
|
||||
|
||||
**Decision**: Implement both tags even though only `<private>` is user-facing
|
||||
**Rationale**:
|
||||
- Infrastructure ready for real-time context feature
|
||||
- No rework needed when context injection ships
|
||||
- Same code path for both tags (simple)
|
||||
- Progressive enhancement approach
|
||||
|
||||
### 5. Regex-Based Stripping
|
||||
|
||||
**Decision**: Use regex `/<tag>[\s\S]*?<\/tag>/g` instead of XML parser
|
||||
**Rationale**:
|
||||
- No dependencies needed
|
||||
- Handles multiline content (`[\s\S]*?`)
|
||||
- Non-greedy (`*?`) prevents over-matching
|
||||
- Global flag (`g`) handles multiple tags
|
||||
- Good enough for this use case
|
||||
|
||||
## Edge Cases Handled
|
||||
|
||||
| Case | Input | Output | Why |
|
||||
|------|-------|--------|-----|
|
||||
| Nested tags | `<private>a <private>b</private> a</private>` | `` | Outer tag matches all |
|
||||
| Malformed | `<private>unclosed` | `<private>unclosed` | Regex requires closing tag |
|
||||
| Multiple | `<private>a</private> b <private>c</private>` | `b` | Global flag removes all |
|
||||
| Empty | `<private></private>` | `` | Matches and removes |
|
||||
| Tag-like | `<tag>not private</tag>` | `<tag>not private</tag>` | Different tag name |
|
||||
| Large content | 10MB+ string | (stripped) | O(n) regex handles it |
|
||||
| Non-string | `123`, `null`, `{}` | `'{}'` | Defensive default |
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### 1. Real-Time Context Injection
|
||||
|
||||
**Status**: Deferred (not in this PR)
|
||||
**When ready**: The `<claude-mem-context>` tag infrastructure is already in place
|
||||
|
||||
The missing piece is in `src/hooks/new-hook.ts`:
|
||||
- Select relevant observations from timeline
|
||||
- Wrap in `<claude-mem-context>` tags
|
||||
- Return via `hookSpecificOutput`
|
||||
- Tag stripping already handles the rest
|
||||
|
||||
### 2. System-Level Meta-Observation Tagging
|
||||
|
||||
**Concept**: Auto-tag observations about observations
|
||||
**Examples**:
|
||||
- Search skill results: `<claude-mem-context>[search results]</claude-mem-context>`
|
||||
- Memory lookups: Fetched observations wrapped in tag
|
||||
- Observation summaries: Meta-level analysis wrapped
|
||||
|
||||
**Implementation**: Tools/skills that produce meta-observations can wrap output in `<claude-mem-context>` tags to prevent recursive storage.
|
||||
|
||||
### 3. Additional Tag Types
|
||||
|
||||
**Potential tags**:
|
||||
- `<ephemeral>`: Content that should be seen but not stored (alias for `<private>`)
|
||||
- `<debug>`: Debug output that should be logged but not persisted
|
||||
- `<scratch>`: Thinking/planning content not meant for observations
|
||||
|
||||
**Note**: Current implementation handles any tag you add to the regex. Adding new tags requires one line change in `stripMemoryTags()`.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
```bash
|
||||
node --test tests/strip-memory-tags.test.ts
|
||||
```
|
||||
**Expected**: 19/19 passing ✅
|
||||
|
||||
### Integration Tests
|
||||
|
||||
**Test 1: Basic Privacy**
|
||||
```bash
|
||||
# Submit prompt with <private> tag
|
||||
# Query database: should not contain private content
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations WHERE narrative LIKE '%<private>%';"
|
||||
# Expected: 0
|
||||
```
|
||||
|
||||
**Test 2: Dual Tags**
|
||||
```bash
|
||||
# Submit prompt with both tags
|
||||
# Verify neither tag appears in database
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations WHERE narrative LIKE '%<private>%' OR narrative LIKE '%<claude-mem-context>%';"
|
||||
# Expected: 0
|
||||
```
|
||||
|
||||
**Test 3: Function Exists**
|
||||
```bash
|
||||
# Verify stripMemoryTags in built file
|
||||
grep -c "claude-mem-context.*private.*trim" ~/.claude/plugins/marketplaces/thedotmack/plugin/scripts/save-hook.js
|
||||
# Expected: 1
|
||||
```
|
||||
|
||||
### Regression Tests
|
||||
|
||||
**Ensure**:
|
||||
- Normal observations still work (no tags broken)
|
||||
- Worker service receives clean data
|
||||
- No errors in `~/.claude-mem/silent.log`
|
||||
- Tool executions still captured correctly
|
||||
|
||||
## Known Limitations
|
||||
|
||||
### 1. Tag Format is Fixed
|
||||
|
||||
Tags must use exact XML-style format: `<tag>content</tag>`
|
||||
|
||||
**Won't work**:
|
||||
- `[private]content[/private]` (wrong syntax)
|
||||
- `<!-- private -->content<!-- /private -->` (comment syntax)
|
||||
- `{{private}}content{{/private}}` (curly braces)
|
||||
|
||||
**Future**: Could add support for alternative formats if needed.
|
||||
|
||||
### 2. Partial Tag Matching
|
||||
|
||||
If user writes about tags without intending to use them:
|
||||
```
|
||||
I want to add a <private> tag feature to my app
|
||||
```
|
||||
|
||||
This won't be stripped (no closing tag). But if they accidentally write:
|
||||
```
|
||||
I want to add a <private>tag</private> feature
|
||||
```
|
||||
|
||||
"tag" gets stripped.
|
||||
|
||||
**Mitigation**: Documentation educates users on proper usage.
|
||||
|
||||
### 3. Performance with Very Large Content
|
||||
|
||||
Regex performance is O(n) where n = content length.
|
||||
|
||||
**Tested**: Works fine with 10,000 character strings
|
||||
**Unknown**: Performance with multi-megabyte tool responses
|
||||
|
||||
**Mitigation**: Most tool I/O is small. If issues arise, could optimize with:
|
||||
- Early exit if no '<' character found
|
||||
- Streaming regex for very large content
|
||||
- Size limits on stripMemoryTags input
|
||||
|
||||
## Documentation
|
||||
|
||||
### User-Facing
|
||||
|
||||
**Location**: `docs/public/usage/private-tags.mdx`
|
||||
**Content**:
|
||||
- How to use `<private>` tags
|
||||
- Use cases and examples
|
||||
- Best practices
|
||||
- Troubleshooting
|
||||
|
||||
**Available in**: Mintlify docs site, navigation under "Get Started"
|
||||
|
||||
### Technical/Internal
|
||||
|
||||
**Location**: `docs/context/dual-tag-system-architecture.md` (this file)
|
||||
**Content**:
|
||||
- Complete dual-tag system architecture
|
||||
- Implementation details
|
||||
- Design decisions
|
||||
- Future enhancements
|
||||
|
||||
**Audience**: Contributors, maintainers, future developers
|
||||
|
||||
## References
|
||||
|
||||
### Original Work
|
||||
- **PR #105**: Real-time context injection with dual-tag system
|
||||
- **Branch**: `feature/real-time-context` (merged to main)
|
||||
- **Investigator**: @basher83
|
||||
|
||||
### Documentation
|
||||
- **Investigation**: `docs/context/real-time-context-recursive-memory-investigation.md`
|
||||
- **User Guide**: `docs/public/usage/private-tags.mdx`
|
||||
- **This Document**: `docs/context/dual-tag-system-architecture.md`
|
||||
|
||||
### Patterns Applied
|
||||
- **Edge Processing**: From hooks-in-composition pattern
|
||||
- **Never Block the Agent**: Defensive coding, safe defaults
|
||||
- **One-Way Data Stream**: Hook → Worker → Database
|
||||
|
||||
## Summary
|
||||
|
||||
The dual-tag system is a complete, production-ready implementation that:
|
||||
- ✅ Gives users privacy control via `<private>` tags
|
||||
- ✅ Prepares infrastructure for real-time context injection
|
||||
- ✅ Uses edge processing pattern for clean architecture
|
||||
- ✅ Has comprehensive test coverage (19 tests, all passing)
|
||||
- ✅ Includes user documentation and technical reference
|
||||
- ✅ Requires no configuration (always active)
|
||||
- ✅ Handles edge cases defensively
|
||||
|
||||
**Status**: Ready to ship 🚀
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,83 @@
|
||||
# Claude-Mem Hooks Cleanup Todo
|
||||
|
||||
## ✅ Phase 1: Delete Dead Code (Modified)
|
||||
|
||||
**hook-response.ts**
|
||||
|
||||
- [ ] Remove `| string` from HookType union to restore type safety
|
||||
- [ ] Delete PreCompact branch (lines 23-36, 14 lines)
|
||||
- [x] ~~Delete pointless branches~~ — SKIP (intentional)
|
||||
- [x] ~~Simplify wrapper function~~ — SKIP (intentional)
|
||||
|
||||
**new-hook.ts**
|
||||
|
||||
- [ ] Delete 34-line architecture comment block (lines 1-34)
|
||||
- [ ] Replace 18 lines of debug logging with single 4-line log call (lines 64-81)
|
||||
|
||||
**cleanup-hook.ts**
|
||||
|
||||
- [ ] Remove `cwd`, `transcript_path`, `hook_event_name` from SessionEndInput interface
|
||||
- [ ] Replace 12-line manual mode help with simple error throw
|
||||
|
||||
**user-message-hook.ts**
|
||||
|
||||
- [ ] Delete all 40 lines of expired announcement code (lines 31-70)
|
||||
- [ ] Add comment explaining exit code 3: `// exit code 3 = show user message that Claude does NOT receive as context`
|
||||
|
||||
---
|
||||
|
||||
## ✅ Phase 2: Extract Shared Utilities
|
||||
|
||||
- [ ] Create `src/shared/hook-error-handler.ts` with `handleWorkerError()`
|
||||
- [ ] Update all 4 hooks to use shared error handler (context-hook, new-hook, save-hook, summary-hook)
|
||||
- [ ] Create `src/shared/transcript-parser.ts` — merge `extractLastUserMessage` + `extractLastAssistantMessage` into single parameterized function
|
||||
- [ ] Create `src/shared/hook-constants.ts` for exit codes, timeouts
|
||||
|
||||
---
|
||||
|
||||
## ❌ Phase 3: SKIPPED
|
||||
|
||||
_(Entry points stay as-is, hook-response.ts wrapper stays as-is)_
|
||||
|
||||
---
|
||||
|
||||
## ✅ Phase 4: Restore Type Safety
|
||||
|
||||
**context-hook.ts**
|
||||
|
||||
- [ ] Make `session_id`, `cwd`, `transcript_path` required in SessionStartInput
|
||||
- [ ] Remove `[key: string]: any`
|
||||
- [ ] Remove unused `source` field
|
||||
- [ ] Keep using `happy_path_error__with_fallback` for defaults (hooks use exit codes, logging tool is appropriate)
|
||||
|
||||
**All 4 hook interfaces**
|
||||
|
||||
- [ ] Remove `[key: string]: any` from all interfaces
|
||||
|
||||
**save-hook.ts**
|
||||
|
||||
- [ ] Keep `happy_path_error__with_fallback` usage (it's appropriate for hook context)
|
||||
|
||||
**summary-hook.ts**
|
||||
|
||||
- [ ] Add timeout (2s) and error logging to spinner stop request
|
||||
|
||||
---
|
||||
|
||||
## ✅ Phase 5: Relocate Business Logic (Modified)
|
||||
|
||||
- [ ] Move `SKIP_TOOLS` from save-hook.ts to worker service
|
||||
- [ ] Make `SKIP_TOOLS` configurable via settings.json
|
||||
- [x] ~~Move announcements to database~~ — SKIP
|
||||
- [x] ~~Merge context-hook + user-message-hook~~ — SKIP (intentionally separate)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
| Action | Count |
|
||||
| ----------------- | ----- |
|
||||
| Lines to delete | ~150 |
|
||||
| New shared files | 3 |
|
||||
| Interfaces to fix | 4 |
|
||||
| Items skipped | 5 |
|
||||
@@ -1,96 +0,0 @@
|
||||
# Multi-Platform Build Guide
|
||||
|
||||
This project now supports building binaries for multiple platforms using Bun's cross-compilation capabilities.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
- **Windows x64**: `claude-mem.exe`
|
||||
- **Linux x64**: `claude-mem-linux`
|
||||
- **Linux ARM64**: `claude-mem-linux-arm64`
|
||||
- **macOS ARM64**: `claude-mem-macos-arm64`
|
||||
- **macOS x64**: `claude-mem-macos-x64`
|
||||
|
||||
## Building
|
||||
|
||||
### Build All Platforms
|
||||
|
||||
To build binaries for all supported platforms:
|
||||
|
||||
```bash
|
||||
npm run build:multiplatform
|
||||
```
|
||||
|
||||
This will create binaries in the `releases/binaries/` directory.
|
||||
|
||||
### Build for NPM Package
|
||||
|
||||
To build a complete npm package with all platform binaries:
|
||||
|
||||
```bash
|
||||
npm run publish
|
||||
```
|
||||
|
||||
This creates a package in `releases/npm-package/` that includes:
|
||||
- Platform detection wrapper script
|
||||
- All platform-specific binaries
|
||||
- Hooks and configuration files
|
||||
|
||||
## How Platform Detection Works
|
||||
|
||||
The npm package includes a Node.js wrapper script (`claude-mem`) that:
|
||||
|
||||
1. Detects the current platform using `process.platform` and `process.arch`
|
||||
2. Maps the platform to the appropriate binary filename
|
||||
3. Executes the correct binary with all command-line arguments
|
||||
|
||||
### Platform Mapping
|
||||
|
||||
| Platform | Architecture | Binary Filename |
|
||||
|----------|-------------|------------------|
|
||||
| Windows | x64 | `claude-mem.exe` |
|
||||
| Linux | x64 | `claude-mem-linux` |
|
||||
| Linux | arm64/aarch64 | `claude-mem-linux-arm64` |
|
||||
| macOS | arm64 | `claude-mem-macos-arm64` |
|
||||
| macOS | x64 | `claude-mem-macos-x64` |
|
||||
|
||||
## Usage
|
||||
|
||||
After installation via npm, users can run:
|
||||
|
||||
```bash
|
||||
npx claude-mem --help
|
||||
```
|
||||
|
||||
The wrapper will automatically select and execute the correct binary for their platform.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Unsupported Platform Error
|
||||
|
||||
If you see an "Unsupported platform" error, check that your platform/architecture combination is in the supported list above.
|
||||
|
||||
### Binary Not Found Error
|
||||
|
||||
This indicates the platform detection worked, but the expected binary file is missing from the package. This shouldn't happen with properly built packages.
|
||||
|
||||
## Development
|
||||
|
||||
### Adding New Platforms
|
||||
|
||||
To add support for new platforms:
|
||||
|
||||
1. Add the platform to the `PLATFORMS` array in `scripts/build-multiplatform.sh`
|
||||
2. Update the platform detection logic in `scripts/claude-mem-wrapper.js`
|
||||
3. Update this documentation
|
||||
|
||||
### Testing Binaries
|
||||
|
||||
Test that a specific binary works:
|
||||
|
||||
```bash
|
||||
# Test Linux binary
|
||||
./releases/binaries/claude-mem-linux --help
|
||||
|
||||
# Test Windows binary (on Windows or with Wine)
|
||||
./releases/binaries/claude-mem.exe --help
|
||||
```
|
||||
@@ -0,0 +1,88 @@
|
||||
# Claude-Mem Public Documentation
|
||||
|
||||
## What This Folder Is
|
||||
|
||||
This `docs/public/` folder contains the **Mintlify documentation site** - the official user-facing documentation for claude-mem. It's a structured documentation platform with a specific file format and organization.
|
||||
|
||||
## Folder Structure
|
||||
|
||||
```
|
||||
docs/
|
||||
├── public/ ← You are here (Mintlify MDX files)
|
||||
│ ├── *.mdx - User-facing documentation pages
|
||||
│ ├── docs.json - Mintlify configuration and navigation
|
||||
│ ├── architecture/ - Technical architecture docs
|
||||
│ ├── usage/ - User guides and workflows
|
||||
│ └── *.webp, *.gif - Assets (logos, screenshots)
|
||||
└── context/ ← Internal documentation (DO NOT put here)
|
||||
└── *.md - Planning docs, audits, references
|
||||
```
|
||||
|
||||
## File Requirements
|
||||
|
||||
### Mintlify Documentation Files (.mdx)
|
||||
All official documentation files must be:
|
||||
- Written in `.mdx` format (Markdown with JSX support)
|
||||
- Listed in `docs.json` navigation structure
|
||||
- Follow Mintlify's schema and conventions
|
||||
|
||||
The documentation is organized into these sections:
|
||||
- **Get Started**: Introduction, installation, usage guides
|
||||
- **Best Practices**: Context engineering, progressive disclosure
|
||||
- **Configuration & Development**: Settings, dev workflow, troubleshooting
|
||||
- **Architecture**: System design, components, technical details
|
||||
|
||||
### Configuration File
|
||||
`docs.json` defines:
|
||||
- Site metadata (name, description, theme)
|
||||
- Navigation structure
|
||||
- Branding (logos, colors)
|
||||
- Footer links and social media
|
||||
|
||||
## What Does NOT Belong Here
|
||||
|
||||
**Planning documents, design docs, and reference materials go in `/docs/context/` instead:**
|
||||
|
||||
Files that belong in `/docs/context/` (NOT here):
|
||||
- Planning documents (`*-plan.md`, `*-outline.md`)
|
||||
- Implementation analysis (`*-audit.md`, `*-code-reference.md`)
|
||||
- Error tracking (`typescript-errors.md`)
|
||||
- Internal design documents
|
||||
- PR review responses
|
||||
- Reference materials (like `agent-sdk-ref.md`)
|
||||
- Work-in-progress documentation
|
||||
|
||||
## How to Add Official Documentation
|
||||
|
||||
1. Create a new `.mdx` file in the appropriate subdirectory
|
||||
2. Add the file path to `docs.json` navigation
|
||||
3. Use Mintlify's frontmatter and components
|
||||
4. Follow the existing documentation style
|
||||
5. Test locally: `npx mintlify dev`
|
||||
|
||||
## Development Workflow
|
||||
|
||||
**For contributors working on claude-mem:**
|
||||
- Read `/CLAUDE.md` in the project root for development instructions
|
||||
- Place planning/design docs in `/docs/context/`
|
||||
- Only add user-facing documentation to `/docs/public/`
|
||||
- Test documentation locally with Mintlify CLI before committing
|
||||
|
||||
## Testing Documentation
|
||||
|
||||
```bash
|
||||
# Validate docs structure
|
||||
npx mintlify validate
|
||||
|
||||
# Check for broken links
|
||||
npx mintlify broken-links
|
||||
|
||||
# Run local dev server
|
||||
npx mintlify dev
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
**Simple Rule**:
|
||||
- `/docs/public/` = Official user documentation (Mintlify .mdx files) ← YOU ARE HERE
|
||||
- `/docs/context/` = Internal docs, plans, references, audits
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,309 @@
|
||||
---
|
||||
title: "Database Architecture"
|
||||
description: "SQLite schema, FTS5 search, and data storage"
|
||||
---
|
||||
|
||||
# Database Architecture
|
||||
|
||||
Claude-Mem uses SQLite 3 with the bun:sqlite native module for persistent storage and FTS5 for full-text search.
|
||||
|
||||
## Database Location
|
||||
|
||||
**Path**: `~/.claude-mem/claude-mem.db`
|
||||
|
||||
The database uses SQLite's WAL (Write-Ahead Logging) mode for concurrent reads/writes.
|
||||
|
||||
## Database Implementation
|
||||
|
||||
**Primary Implementation**: bun:sqlite (native SQLite module)
|
||||
- Used by: SessionStore and SessionSearch
|
||||
- Format: Synchronous API with better performance
|
||||
- **Note**: Database.ts (using bun:sqlite) is legacy code
|
||||
|
||||
## Core Tables
|
||||
|
||||
### 1. sdk_sessions
|
||||
|
||||
Tracks active and completed sessions.
|
||||
|
||||
```sql
|
||||
CREATE TABLE sdk_sessions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
sdk_session_id TEXT UNIQUE NOT NULL,
|
||||
claude_session_id TEXT,
|
||||
project TEXT NOT NULL,
|
||||
prompt_counter INTEGER DEFAULT 0,
|
||||
status TEXT NOT NULL DEFAULT 'active',
|
||||
created_at TEXT NOT NULL,
|
||||
created_at_epoch INTEGER NOT NULL,
|
||||
completed_at TEXT,
|
||||
completed_at_epoch INTEGER,
|
||||
last_activity_at TEXT,
|
||||
last_activity_epoch INTEGER
|
||||
);
|
||||
```
|
||||
|
||||
**Indexes**:
|
||||
- `idx_sdk_sessions_claude_session` on `claude_session_id`
|
||||
- `idx_sdk_sessions_project` on `project`
|
||||
- `idx_sdk_sessions_status` on `status`
|
||||
- `idx_sdk_sessions_created_at` on `created_at_epoch DESC`
|
||||
|
||||
### 2. observations
|
||||
|
||||
Individual tool executions with hierarchical structure.
|
||||
|
||||
```sql
|
||||
CREATE TABLE observations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_id TEXT NOT NULL,
|
||||
sdk_session_id TEXT NOT NULL,
|
||||
claude_session_id TEXT,
|
||||
project TEXT NOT NULL,
|
||||
prompt_number INTEGER,
|
||||
tool_name TEXT NOT NULL,
|
||||
correlation_id TEXT,
|
||||
|
||||
-- Hierarchical fields
|
||||
title TEXT,
|
||||
subtitle TEXT,
|
||||
narrative TEXT,
|
||||
text TEXT,
|
||||
facts TEXT,
|
||||
concepts TEXT,
|
||||
type TEXT,
|
||||
files_read TEXT,
|
||||
files_modified TEXT,
|
||||
|
||||
created_at TEXT NOT NULL,
|
||||
created_at_epoch INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY (sdk_session_id) REFERENCES sdk_sessions(sdk_session_id)
|
||||
);
|
||||
```
|
||||
|
||||
**Observation Types**:
|
||||
- `decision` - Architectural or design decisions
|
||||
- `bugfix` - Bug fixes and corrections
|
||||
- `feature` - New features or capabilities
|
||||
- `refactor` - Code refactoring and cleanup
|
||||
- `discovery` - Learnings about the codebase
|
||||
- `change` - General changes and modifications
|
||||
|
||||
**Indexes**:
|
||||
- `idx_observations_session` on `session_id`
|
||||
- `idx_observations_sdk_session` on `sdk_session_id`
|
||||
- `idx_observations_project` on `project`
|
||||
- `idx_observations_tool_name` on `tool_name`
|
||||
- `idx_observations_created_at` on `created_at_epoch DESC`
|
||||
- `idx_observations_type` on `type`
|
||||
|
||||
### 3. session_summaries
|
||||
|
||||
AI-generated session summaries (multiple per session).
|
||||
|
||||
```sql
|
||||
CREATE TABLE session_summaries (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
sdk_session_id TEXT NOT NULL,
|
||||
claude_session_id TEXT,
|
||||
project TEXT NOT NULL,
|
||||
prompt_number INTEGER,
|
||||
|
||||
-- Summary fields
|
||||
request TEXT,
|
||||
investigated TEXT,
|
||||
learned TEXT,
|
||||
completed TEXT,
|
||||
next_steps TEXT,
|
||||
notes TEXT,
|
||||
|
||||
created_at TEXT NOT NULL,
|
||||
created_at_epoch INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY (sdk_session_id) REFERENCES sdk_sessions(sdk_session_id)
|
||||
);
|
||||
```
|
||||
|
||||
**Indexes**:
|
||||
- `idx_session_summaries_sdk_session` on `sdk_session_id`
|
||||
- `idx_session_summaries_project` on `project`
|
||||
- `idx_session_summaries_created_at` on `created_at_epoch DESC`
|
||||
|
||||
### 4. user_prompts
|
||||
|
||||
Raw user prompts with FTS5 search (as of v4.2.0).
|
||||
|
||||
```sql
|
||||
CREATE TABLE user_prompts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
sdk_session_id TEXT NOT NULL,
|
||||
claude_session_id TEXT,
|
||||
project TEXT NOT NULL,
|
||||
prompt_number INTEGER,
|
||||
prompt_text TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
created_at_epoch INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY (sdk_session_id) REFERENCES sdk_sessions(sdk_session_id)
|
||||
);
|
||||
```
|
||||
|
||||
**Indexes**:
|
||||
- `idx_user_prompts_sdk_session` on `sdk_session_id`
|
||||
- `idx_user_prompts_project` on `project`
|
||||
- `idx_user_prompts_created_at` on `created_at_epoch DESC`
|
||||
|
||||
### Legacy Tables
|
||||
|
||||
- **sessions**: Legacy session tracking (v3.x)
|
||||
- **memories**: Legacy compressed memory chunks (v3.x)
|
||||
- **overviews**: Legacy session summaries (v3.x)
|
||||
|
||||
## FTS5 Full-Text Search
|
||||
|
||||
SQLite FTS5 (Full-Text Search) virtual tables enable fast full-text search across observations, summaries, and user prompts.
|
||||
|
||||
### FTS5 Virtual Tables
|
||||
|
||||
#### observations_fts
|
||||
|
||||
```sql
|
||||
CREATE VIRTUAL TABLE observations_fts USING fts5(
|
||||
title,
|
||||
subtitle,
|
||||
narrative,
|
||||
text,
|
||||
facts,
|
||||
concepts,
|
||||
content='observations',
|
||||
content_rowid='id'
|
||||
);
|
||||
```
|
||||
|
||||
#### session_summaries_fts
|
||||
|
||||
```sql
|
||||
CREATE VIRTUAL TABLE session_summaries_fts USING fts5(
|
||||
request,
|
||||
investigated,
|
||||
learned,
|
||||
completed,
|
||||
next_steps,
|
||||
notes,
|
||||
content='session_summaries',
|
||||
content_rowid='id'
|
||||
);
|
||||
```
|
||||
|
||||
#### user_prompts_fts
|
||||
|
||||
```sql
|
||||
CREATE VIRTUAL TABLE user_prompts_fts USING fts5(
|
||||
prompt_text,
|
||||
content='user_prompts',
|
||||
content_rowid='id'
|
||||
);
|
||||
```
|
||||
|
||||
### Automatic Synchronization
|
||||
|
||||
FTS5 tables stay in sync via triggers:
|
||||
|
||||
```sql
|
||||
-- Insert trigger example
|
||||
CREATE TRIGGER observations_ai AFTER INSERT ON observations BEGIN
|
||||
INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
|
||||
VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts);
|
||||
END;
|
||||
|
||||
-- Update trigger example
|
||||
CREATE TRIGGER observations_au AFTER UPDATE ON observations BEGIN
|
||||
INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts)
|
||||
VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts);
|
||||
INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
|
||||
VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts);
|
||||
END;
|
||||
|
||||
-- Delete trigger example
|
||||
CREATE TRIGGER observations_ad AFTER DELETE ON observations BEGIN
|
||||
INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts)
|
||||
VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts);
|
||||
END;
|
||||
```
|
||||
|
||||
### FTS5 Query Syntax
|
||||
|
||||
FTS5 supports rich query syntax:
|
||||
|
||||
- **Simple**: `"error handling"`
|
||||
- **AND**: `"error" AND "handling"`
|
||||
- **OR**: `"bug" OR "fix"`
|
||||
- **NOT**: `"bug" NOT "feature"`
|
||||
- **Phrase**: `"'exact phrase'"`
|
||||
- **Column**: `title:"authentication"`
|
||||
|
||||
### Security
|
||||
|
||||
As of v4.2.3, all FTS5 queries are properly escaped to prevent SQL injection:
|
||||
- Double quotes are escaped: `query.replace(/"/g, '""')`
|
||||
- Comprehensive test suite with 332 injection attack tests
|
||||
|
||||
## Database Classes
|
||||
|
||||
### SessionStore
|
||||
|
||||
CRUD operations for sessions, observations, summaries, and user prompts.
|
||||
|
||||
**Location**: `src/services/sqlite/SessionStore.ts`
|
||||
|
||||
**Methods**:
|
||||
- `createSession()`
|
||||
- `getSession()`
|
||||
- `updateSession()`
|
||||
- `createObservation()`
|
||||
- `getObservations()`
|
||||
- `createSummary()`
|
||||
- `getSummaries()`
|
||||
- `createUserPrompt()`
|
||||
|
||||
### SessionSearch
|
||||
|
||||
FTS5 full-text search with 8 specialized search methods.
|
||||
|
||||
**Location**: `src/services/sqlite/SessionSearch.ts`
|
||||
|
||||
**Methods**:
|
||||
- `searchObservations()` - Full-text search across observations
|
||||
- `searchSessions()` - Full-text search across summaries
|
||||
- `searchUserPrompts()` - Full-text search across user prompts
|
||||
- `findByConcept()` - Find by concept tags
|
||||
- `findByFile()` - Find by file references
|
||||
- `findByType()` - Find by observation type
|
||||
- `getRecentContext()` - Get recent session context
|
||||
- `advancedSearch()` - Combined filters
|
||||
|
||||
## Migrations
|
||||
|
||||
Database schema is managed via migrations in `src/services/sqlite/migrations.ts`.
|
||||
|
||||
**Migration History**:
|
||||
- Migration 001: Initial schema (sessions, memories, overviews, diagnostics, transcript_events)
|
||||
- Migration 002: Hierarchical memory fields (title, subtitle, facts, concepts, files_touched)
|
||||
- Migration 003: SDK sessions and observations
|
||||
- Migration 004: Session summaries
|
||||
- Migration 005: Multi-prompt sessions (prompt_counter, prompt_number)
|
||||
- Migration 006: FTS5 virtual tables and triggers
|
||||
- Migration 007-010: Various improvements and user prompts table
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- **Indexes**: All foreign keys and frequently queried columns are indexed
|
||||
- **FTS5**: Full-text search is significantly faster than LIKE queries
|
||||
- **Triggers**: Automatic synchronization has minimal overhead
|
||||
- **Connection Pooling**: bun:sqlite reuses connections efficiently
|
||||
- **Synchronous API**: bun:sqlite uses synchronous API for better performance
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
See [Troubleshooting - Database Issues](../troubleshooting.md#database-issues) for common problems and solutions.
|
||||
@@ -0,0 +1,959 @@
|
||||
---
|
||||
title: "Hook Lifecycle"
|
||||
description: "Complete guide to the 5-stage memory agent lifecycle for platform implementers"
|
||||
---
|
||||
|
||||
# Hook Lifecycle
|
||||
|
||||
Claude-Mem implements a **5-stage hook system** that captures development work across Claude Code sessions. This document provides a complete technical reference for developers implementing this pattern on other platforms.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
### System Architecture
|
||||
|
||||
This two-process architecture works in both Claude Code and VS Code:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph EXT["Extension Process (runs in IDE)"]
|
||||
direction TB
|
||||
ACT[Extension Activation]
|
||||
HOOKS[Hook Event Handlers]
|
||||
ACT --> HOOKS
|
||||
|
||||
subgraph HOOK_HANDLERS["5 Lifecycle Hooks"]
|
||||
H1[SessionStart<br/>activate function]
|
||||
H2[UserPromptSubmit<br/>command handler]
|
||||
H3[PostToolUse<br/>middleware]
|
||||
H4[Stop<br/>idle timeout]
|
||||
H5[SessionEnd<br/>deactivate function]
|
||||
end
|
||||
|
||||
HOOKS --> HOOK_HANDLERS
|
||||
end
|
||||
|
||||
HOOK_HANDLERS -->|"HTTP<br/>(fire-and-forget<br/>2s timeout)"| HTTP[Worker HTTP API<br/>Port 37777]
|
||||
|
||||
subgraph WORKER["Worker Process (separate Node.js)"]
|
||||
direction TB
|
||||
HTTP --> API[Express Server]
|
||||
API --> SESS[Session Manager]
|
||||
API --> AGENT[SDK Agent]
|
||||
API --> DB[Database Manager]
|
||||
|
||||
AGENT -->|Event-Driven| CLAUDE[Claude Agent SDK]
|
||||
CLAUDE --> SQLITE[(SQLite + FTS5)]
|
||||
CLAUDE --> CHROMA[(Chroma Vectors)]
|
||||
end
|
||||
|
||||
style EXT fill:#e1f5ff
|
||||
style WORKER fill:#fff4e1
|
||||
style HOOK_HANDLERS fill:#f0f0f0
|
||||
```
|
||||
|
||||
**Key Principles:**
|
||||
- Extension process never blocks (fire-and-forget HTTP)
|
||||
- Worker processes observations asynchronously
|
||||
- Session state persists across IDE restarts
|
||||
|
||||
### VS Code Extension API Integration Points
|
||||
|
||||
For developers porting to VS Code, here's where to hook into the VS Code Extension API:
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
subgraph VSCODE["VS Code Extension API"]
|
||||
direction TB
|
||||
A["activate(context)"]
|
||||
B["commands.registerCommand()"]
|
||||
C["chat.createChatParticipant()"]
|
||||
D["workspace.onDidSaveTextDocument()"]
|
||||
E["window.onDidChangeActiveTextEditor()"]
|
||||
F["deactivate()"]
|
||||
end
|
||||
|
||||
subgraph HOOKS["Hook Equivalents"]
|
||||
direction TB
|
||||
G[SessionStart]
|
||||
H[UserPromptSubmit]
|
||||
I[PostToolUse]
|
||||
J[Stop/Summary]
|
||||
K[SessionEnd]
|
||||
end
|
||||
|
||||
subgraph WORKER_API["Worker HTTP Endpoints"]
|
||||
direction TB
|
||||
L[GET /api/context/inject]
|
||||
M[POST /sessions/init]
|
||||
N[POST /sessions/observations]
|
||||
O[POST /sessions/summarize]
|
||||
P[POST /sessions/complete]
|
||||
end
|
||||
|
||||
A --> G
|
||||
B --> H
|
||||
C --> H
|
||||
D --> I
|
||||
E --> I
|
||||
F --> K
|
||||
|
||||
G --> L
|
||||
H --> M
|
||||
I --> N
|
||||
J --> O
|
||||
K --> P
|
||||
|
||||
style VSCODE fill:#007acc,color:#fff
|
||||
style HOOKS fill:#f0f0f0
|
||||
style WORKER_API fill:#4caf50,color:#fff
|
||||
```
|
||||
|
||||
**Implementation Examples:**
|
||||
|
||||
```typescript
|
||||
// VS Code Extension - SessionStart Hook
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
const sessionId = generateSessionId()
|
||||
const project = workspace.name || 'default'
|
||||
|
||||
// Fetch context from worker
|
||||
const response = await fetch(`http://localhost:37777/api/context/inject?project=${project}`)
|
||||
const context = await response.text()
|
||||
|
||||
// Inject into chat or UI panel
|
||||
injectContextToChat(context)
|
||||
}
|
||||
|
||||
// VS Code Extension - UserPromptSubmit Hook
|
||||
const command = vscode.commands.registerCommand('extension.command', async (prompt) => {
|
||||
await fetch('http://localhost:37777/sessions/init', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ sessionId, project, userPrompt: prompt })
|
||||
})
|
||||
})
|
||||
|
||||
// VS Code Extension - PostToolUse Hook (middleware pattern)
|
||||
workspace.onDidSaveTextDocument(async (document) => {
|
||||
await fetch('http://localhost:37777/api/sessions/observations', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
claudeSessionId: sessionId,
|
||||
tool_name: 'FileSave',
|
||||
tool_input: { path: document.uri.path },
|
||||
tool_response: 'File saved successfully'
|
||||
})
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### Async Processing Pipeline
|
||||
|
||||
How observations flow from extension to database without blocking the IDE:
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A["Extension: Tool Use Event"] --> B{"Skip List?<br/>(TodoWrite, AskUserQuestion, etc.)"}
|
||||
B -->|"Skip"| X["Discard"]
|
||||
B -->|"Keep"| C["Strip Privacy Tags<br/><private>...</private>"]
|
||||
C --> D["HTTP POST to Worker<br/>Port 37777"]
|
||||
D --> E["2s timeout<br/>fire-and-forget"]
|
||||
E --> F["Extension continues<br/>(non-blocking)"]
|
||||
|
||||
D -.Async Path.-> G["Worker: Queue Observation"]
|
||||
G --> H["SDK Agent picks up<br/>(event-driven)"]
|
||||
H --> I["Call Claude API<br/>(compress observation)"]
|
||||
I --> J["Parse XML response"]
|
||||
J --> K["Save to SQLite<br/>(sdk_sessions table)"]
|
||||
K --> L["Sync to Chroma<br/>(vector embeddings)"]
|
||||
|
||||
style F fill:#90EE90,stroke:#2d6b2d,stroke-width:3px
|
||||
style L fill:#87CEEB,stroke:#2d5f8d,stroke-width:3px
|
||||
style E fill:#ffeb3b,stroke:#c6a700,stroke-width:2px
|
||||
```
|
||||
|
||||
**Critical Pattern:** The extension's HTTP call has a 2-second timeout and doesn't wait for AI processing. The worker handles compression asynchronously using an event-driven queue.
|
||||
|
||||
## The 5 Lifecycle Stages
|
||||
|
||||
| Stage | Hook | Trigger | Purpose |
|
||||
|-------|------|---------|---------|
|
||||
| **1. SessionStart** | `context-hook.js` + `user-message-hook.js` | User opens Claude Code | Inject prior context, show UI messages |
|
||||
| **2. UserPromptSubmit** | `new-hook.js` | User submits a prompt | Create/get session, save prompt, init worker |
|
||||
| **3. PostToolUse** | `save-hook.js` | Claude uses any tool | Queue observation for AI compression |
|
||||
| **4. Stop** | `summary-hook.js` | User stops asking questions | Generate session summary |
|
||||
| **5. SessionEnd** | `cleanup-hook.js` | Session closes | Mark session completed |
|
||||
|
||||
## Hook Configuration
|
||||
|
||||
Hooks are configured in `plugin/hooks/hooks.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [{
|
||||
"matcher": "startup|clear|compact",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js",
|
||||
"timeout": 300
|
||||
}, {
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/user-message-hook.js",
|
||||
"timeout": 10
|
||||
}]
|
||||
}],
|
||||
"UserPromptSubmit": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/new-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "*",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}],
|
||||
"Stop": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/summary-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}],
|
||||
"SessionEnd": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Stage 1: SessionStart
|
||||
|
||||
**Timing**: When user opens Claude Code or resumes session
|
||||
|
||||
**Hooks Triggered** (in order):
|
||||
1. `context-hook.js` - Fetches and injects prior session context
|
||||
2. `user-message-hook.js` - Displays context info to user via stderr
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant IDE as IDE/Extension
|
||||
participant ContextHook as context-hook.js
|
||||
participant Worker as Worker Service
|
||||
participant DB as SQLite Database
|
||||
|
||||
User->>IDE: Opens workspace / resumes session
|
||||
IDE->>ContextHook: Trigger SessionStart hook
|
||||
ContextHook->>ContextHook: Generate/reuse session_id
|
||||
ContextHook->>Worker: Health check (max 10s retry)
|
||||
|
||||
alt Worker Ready
|
||||
ContextHook->>Worker: GET /api/context/inject?project=X
|
||||
Worker->>DB: SELECT * FROM observations<br/>WHERE project=X<br/>ORDER BY created_at DESC<br/>LIMIT 50
|
||||
DB-->>Worker: Last 50 observations
|
||||
Worker-->>ContextHook: Context markdown
|
||||
ContextHook-->>IDE: hookSpecificOutput.additionalContext
|
||||
IDE->>IDE: Inject context to Claude's prompt
|
||||
IDE-->>User: Session ready with context
|
||||
else Worker Not Ready
|
||||
ContextHook-->>IDE: Empty context (graceful degradation)
|
||||
IDE-->>User: Session ready without context
|
||||
end
|
||||
|
||||
Note over User,DB: Total time: <300ms (with health check)
|
||||
```
|
||||
|
||||
### Context Hook (`context-hook.js`)
|
||||
|
||||
**Purpose**: Inject context from previous sessions into Claude's initial context.
|
||||
|
||||
**Input** (via stdin):
|
||||
```json
|
||||
{
|
||||
"session_id": "claude-session-123",
|
||||
"cwd": "/path/to/project",
|
||||
"source": "startup"
|
||||
}
|
||||
```
|
||||
|
||||
**Processing**:
|
||||
1. Wait for worker to be available (health check, max 10 seconds)
|
||||
2. Call: `GET http://127.0.0.1:37777/api/context/inject?project={project}`
|
||||
3. Return formatted context as `additionalContext` in `hookSpecificOutput`
|
||||
|
||||
**Output** (via stdout):
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "<<formatted context markdown>>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Implementation**: `src/hooks/context-hook.ts`
|
||||
|
||||
### User Message Hook (`user-message-hook.js`)
|
||||
|
||||
**Purpose**: Display helpful user messages during first-time setup or when viewing context.
|
||||
|
||||
**Behavior**:
|
||||
- Shows first-time setup message when `node_modules` is missing
|
||||
- Displays formatted context information with colors
|
||||
- Provides tips for using claude-mem effectively
|
||||
- Shows link to viewer UI (`http://localhost:37777`)
|
||||
- Uses stderr as communication channel (only output available in Claude Code UI)
|
||||
|
||||
**Implementation**: `src/hooks/user-message-hook.ts`
|
||||
|
||||
---
|
||||
|
||||
## Stage 2: UserPromptSubmit
|
||||
|
||||
**Timing**: When user submits any prompt in a session
|
||||
|
||||
**Hook**: `new-hook.js`
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant IDE as IDE/Extension
|
||||
participant NewHook as new-hook.js
|
||||
participant DB as Direct SQLite Access
|
||||
participant Worker as Worker Service
|
||||
|
||||
User->>IDE: Submits prompt: "Add login feature"
|
||||
IDE->>NewHook: Trigger UserPromptSubmit<br/>{ session_id, cwd, prompt }
|
||||
|
||||
NewHook->>NewHook: Extract project = basename(cwd)
|
||||
NewHook->>NewHook: Strip privacy tags<br/><private>...</private>
|
||||
|
||||
alt Prompt fully private (empty after stripping)
|
||||
NewHook-->>IDE: Skip (don't save)
|
||||
else Prompt has content
|
||||
NewHook->>DB: INSERT OR IGNORE INTO sdk_sessions<br/>(claude_session_id, project, first_user_prompt)
|
||||
DB-->>NewHook: sessionDbId (new or existing)
|
||||
|
||||
NewHook->>DB: UPDATE sdk_sessions<br/>SET prompt_counter = prompt_counter + 1<br/>WHERE id = sessionDbId
|
||||
DB-->>NewHook: promptNumber (e.g., 1 for first, 2 for continuation)
|
||||
|
||||
NewHook->>DB: INSERT INTO user_prompts<br/>(session_id, prompt_number, prompt)
|
||||
|
||||
NewHook->>Worker: POST /sessions/{sessionDbId}/init<br/>{ project, userPrompt, promptNumber }<br/>(fire-and-forget, 2s timeout)
|
||||
Worker-->>NewHook: 200 OK (or timeout)
|
||||
|
||||
NewHook-->>IDE: { continue: true, suppressOutput: true }
|
||||
IDE-->>User: Prompt accepted
|
||||
end
|
||||
|
||||
Note over NewHook,DB: Idempotent: Same session_id → same sessionDbId
|
||||
```
|
||||
|
||||
**Key Pattern:** The `INSERT OR IGNORE` ensures the same `session_id` always maps to the same `sessionDbId`, enabling conversation continuations.
|
||||
|
||||
**Input** (via stdin):
|
||||
```json
|
||||
{
|
||||
"session_id": "claude-session-123",
|
||||
"cwd": "/path/to/project",
|
||||
"prompt": "User's actual prompt text"
|
||||
}
|
||||
```
|
||||
|
||||
**Processing Steps**:
|
||||
|
||||
```typescript
|
||||
// 1. Extract project name from working directory
|
||||
project = path.basename(cwd)
|
||||
|
||||
// 2. Create or get database session (IDEMPOTENT)
|
||||
sessionDbId = db.createSDKSession(session_id, project, prompt)
|
||||
// INSERT OR IGNORE: Creates new row if first prompt, returns existing if continuation
|
||||
|
||||
// 3. Increment prompt counter
|
||||
promptNumber = db.incrementPromptCounter(sessionDbId)
|
||||
// Returns 1 for first prompt, 2 for continuation, etc.
|
||||
|
||||
// 4. Strip privacy tags
|
||||
cleanedPrompt = stripMemoryTagsFromPrompt(prompt)
|
||||
// Removes <private>...</private> and <claude-mem-context>...</claude-mem-context>
|
||||
|
||||
// 5. Skip if fully private
|
||||
if (!cleanedPrompt || cleanedPrompt.trim() === '') {
|
||||
return // Don't save, don't call worker
|
||||
}
|
||||
|
||||
// 6. Save user prompt to database
|
||||
db.saveUserPrompt(session_id, promptNumber, cleanedPrompt)
|
||||
|
||||
// 7. Initialize session via worker HTTP
|
||||
POST http://127.0.0.1:37777/sessions/{sessionDbId}/init
|
||||
Body: { project, userPrompt, promptNumber }
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```json
|
||||
{ "continue": true, "suppressOutput": true }
|
||||
```
|
||||
|
||||
**Implementation**: `src/hooks/new-hook.ts`
|
||||
|
||||
<Note>
|
||||
The same `session_id` flows through ALL hooks in a conversation. The `createSDKSession` call is idempotent - it returns the existing session for continuation prompts.
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Stage 3: PostToolUse
|
||||
|
||||
**Timing**: After Claude uses any tool (Read, Bash, Grep, Write, etc.)
|
||||
|
||||
**Hook**: `save-hook.js`
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Claude as Claude AI
|
||||
participant IDE as IDE/Extension
|
||||
participant SaveHook as save-hook.js
|
||||
participant Worker as Worker Service
|
||||
participant Agent as SDK Agent
|
||||
participant DB as SQLite + Chroma
|
||||
|
||||
Claude->>IDE: Uses tool: Read("/src/auth.ts")
|
||||
IDE->>SaveHook: PostToolUse hook triggered<br/>{ session_id, tool_name, tool_input, tool_response }
|
||||
|
||||
SaveHook->>SaveHook: Check skip list<br/>(TodoWrite, AskUserQuestion, etc.)
|
||||
|
||||
alt Tool in skip list
|
||||
SaveHook-->>IDE: Discard (low-value tool)
|
||||
else Tool allowed
|
||||
SaveHook->>SaveHook: Strip privacy tags from input/response
|
||||
|
||||
SaveHook->>SaveHook: Ensure worker running<br/>(health check)
|
||||
|
||||
SaveHook->>Worker: POST /api/sessions/observations<br/>{ claudeSessionId, tool_name, tool_input, tool_response, cwd }<br/>(fire-and-forget, 2s timeout)
|
||||
|
||||
SaveHook-->>IDE: { continue: true, suppressOutput: true }
|
||||
IDE-->>Claude: Tool execution complete
|
||||
|
||||
Note over Worker,DB: Async path (doesn't block IDE)
|
||||
|
||||
Worker->>Worker: createSDKSession(claudeSessionId)<br/>→ returns sessionDbId
|
||||
Worker->>Worker: Check if prompt was private<br/>(skip if fully private)
|
||||
Worker->>Agent: Queue observation for processing
|
||||
Agent->>Agent: Call Claude SDK to compress<br/>observation into structured format
|
||||
Agent->>DB: Save compressed observation<br/>to sdk_sessions table
|
||||
Agent->>DB: Sync to Chroma vector DB
|
||||
end
|
||||
|
||||
Note over SaveHook,DB: Total sync time: ~2ms<br/>AI processing: 1-3s (async)
|
||||
```
|
||||
|
||||
**Key Pattern:** The hook returns immediately after HTTP POST. AI compression happens asynchronously in the worker without blocking Claude's tool execution.
|
||||
|
||||
**Input** (via stdin):
|
||||
```json
|
||||
{
|
||||
"session_id": "claude-session-123",
|
||||
"cwd": "/path/to/project",
|
||||
"tool_name": "Read",
|
||||
"tool_input": { "file_path": "/src/index.ts" },
|
||||
"tool_response": "file contents..."
|
||||
}
|
||||
```
|
||||
|
||||
**Processing Steps**:
|
||||
|
||||
```typescript
|
||||
// 1. Check blocklist - skip low-value tools
|
||||
const SKIP_TOOLS = {
|
||||
'ListMcpResourcesTool', // MCP infrastructure noise
|
||||
'SlashCommand', // Command invocation
|
||||
'Skill', // Skill invocation
|
||||
'TodoWrite', // Task management meta-tool
|
||||
'AskUserQuestion' // User interaction
|
||||
}
|
||||
|
||||
if (SKIP_TOOLS[tool_name]) return
|
||||
|
||||
// 2. Ensure worker is running
|
||||
await ensureWorkerRunning()
|
||||
|
||||
// 3. Send to worker (fire-and-forget HTTP)
|
||||
POST http://127.0.0.1:37777/api/sessions/observations
|
||||
Body: {
|
||||
claudeSessionId: session_id,
|
||||
tool_name,
|
||||
tool_input,
|
||||
tool_response,
|
||||
cwd
|
||||
}
|
||||
Timeout: 2000ms
|
||||
```
|
||||
|
||||
**Worker Processing**:
|
||||
1. Looks up or creates session: `createSDKSession(claudeSessionId, '', '')`
|
||||
2. Gets prompt counter
|
||||
3. Checks privacy (skips if user prompt was entirely private)
|
||||
4. Strips memory tags from `tool_input` and `tool_response`
|
||||
5. Queues observation for SDK agent processing
|
||||
6. SDK agent calls Claude to compress into structured observation
|
||||
7. Stores observation in database and syncs to Chroma
|
||||
|
||||
**Output**:
|
||||
```json
|
||||
{ "continue": true, "suppressOutput": true }
|
||||
```
|
||||
|
||||
**Implementation**: `src/hooks/save-hook.ts`
|
||||
|
||||
---
|
||||
|
||||
## Stage 4: Stop
|
||||
|
||||
**Timing**: When user stops or pauses asking questions
|
||||
|
||||
**Hook**: `summary-hook.js`
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant IDE as IDE/Extension
|
||||
participant SummaryHook as summary-hook.js
|
||||
participant Worker as Worker Service
|
||||
participant Agent as SDK Agent
|
||||
participant DB as SQLite Database
|
||||
|
||||
User->>IDE: Stops asking questions<br/>(pause, idle, or explicit stop)
|
||||
IDE->>SummaryHook: Stop hook triggered<br/>{ session_id, cwd, transcript_path }
|
||||
|
||||
SummaryHook->>SummaryHook: Read transcript JSONL file
|
||||
SummaryHook->>SummaryHook: Extract last user message<br/>(type: "user")
|
||||
SummaryHook->>SummaryHook: Extract last assistant message<br/>(type: "assistant", filter <system-reminder>)
|
||||
|
||||
SummaryHook->>Worker: POST /api/sessions/summarize<br/>{ claudeSessionId, last_user_message, last_assistant_message }<br/>(fire-and-forget, 2s timeout)
|
||||
|
||||
SummaryHook->>Worker: POST /api/processing<br/>{ isProcessing: false }<br/>(stop spinner)
|
||||
|
||||
SummaryHook-->>IDE: { continue: true, suppressOutput: true }
|
||||
IDE-->>User: Session paused/stopped
|
||||
|
||||
Note over Worker,DB: Async path
|
||||
|
||||
Worker->>Worker: Lookup sessionDbId from claudeSessionId
|
||||
Worker->>Agent: Queue summarization request
|
||||
Agent->>Agent: Call Claude SDK with prompt:<br/>"Summarize: request, investigated, learned, completed, next_steps"
|
||||
Agent->>Agent: Parse XML response
|
||||
Agent->>DB: INSERT INTO session_summaries<br/>{ session_id, request, investigated, learned, completed, next_steps }
|
||||
Agent->>DB: Sync to Chroma (for semantic search)
|
||||
|
||||
Note over SummaryHook,DB: Total sync time: ~2ms<br/>AI summarization: 2-5s (async)
|
||||
```
|
||||
|
||||
**Key Pattern:** The summary is generated asynchronously and doesn't block the user from resuming work or closing the session.
|
||||
|
||||
**Input** (via stdin):
|
||||
```json
|
||||
{
|
||||
"session_id": "claude-session-123",
|
||||
"cwd": "/path/to/project",
|
||||
"transcript_path": "/path/to/transcript.jsonl"
|
||||
}
|
||||
```
|
||||
|
||||
**Processing Steps**:
|
||||
|
||||
```typescript
|
||||
// 1. Extract last messages from transcript JSONL
|
||||
const lines = fs.readFileSync(transcript_path, 'utf-8').split('\n')
|
||||
// Find last user message (type: "user")
|
||||
// Find last assistant message (type: "assistant", filter <system-reminder> tags)
|
||||
|
||||
// 2. Ensure worker is running
|
||||
await ensureWorkerRunning()
|
||||
|
||||
// 3. Send summarization request (fire-and-forget HTTP)
|
||||
POST http://127.0.0.1:37777/api/sessions/summarize
|
||||
Body: {
|
||||
claudeSessionId: session_id,
|
||||
last_user_message: string,
|
||||
last_assistant_message: string
|
||||
}
|
||||
Timeout: 2000ms
|
||||
|
||||
// 4. Stop processing spinner
|
||||
POST http://127.0.0.1:37777/api/processing
|
||||
Body: { isProcessing: false }
|
||||
```
|
||||
|
||||
**Worker Processing**:
|
||||
1. Queues summarization for SDK agent
|
||||
2. Agent calls Claude to generate structured summary
|
||||
3. Summary stored in database with fields: `request`, `investigated`, `learned`, `completed`, `next_steps`
|
||||
|
||||
**Output**:
|
||||
```json
|
||||
{ "continue": true, "suppressOutput": true }
|
||||
```
|
||||
|
||||
**Implementation**: `src/hooks/summary-hook.ts`
|
||||
|
||||
---
|
||||
|
||||
## Stage 5: SessionEnd
|
||||
|
||||
**Timing**: When Claude Code session closes (exit, clear, logout, etc.)
|
||||
|
||||
**Hook**: `cleanup-hook.js`
|
||||
|
||||
### Sequence Diagram
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant IDE as IDE/Extension
|
||||
participant CleanupHook as cleanup-hook.js
|
||||
participant Worker as Worker Service
|
||||
participant DB as SQLite Database
|
||||
participant SSE as SSE Clients (Viewer UI)
|
||||
|
||||
User->>IDE: Closes session<br/>(exit, clear, logout)
|
||||
IDE->>CleanupHook: SessionEnd hook triggered<br/>{ session_id, cwd, transcript_path, reason }
|
||||
|
||||
CleanupHook->>Worker: POST /api/sessions/complete<br/>{ claudeSessionId, reason }<br/>(fire-and-forget, 2s timeout)
|
||||
|
||||
CleanupHook-->>IDE: { continue: true, suppressOutput: true }
|
||||
IDE-->>User: Session closed
|
||||
|
||||
Note over Worker,SSE: Async path
|
||||
|
||||
Worker->>Worker: Lookup sessionDbId from claudeSessionId
|
||||
Worker->>DB: UPDATE sdk_sessions<br/>SET status = 'completed', completed_at = NOW()<br/>WHERE claude_session_id = claudeSessionId
|
||||
Worker->>SSE: Broadcast session completion event<br/>(for live viewer UI updates)
|
||||
|
||||
SSE-->>SSE: Update UI to show session as completed
|
||||
|
||||
Note over CleanupHook,SSE: Total sync time: ~2ms
|
||||
```
|
||||
|
||||
**Key Pattern:** Session completion is tracked for analytics and UI updates, but doesn't prevent the user from closing the IDE.
|
||||
|
||||
**Input** (via stdin):
|
||||
```json
|
||||
{
|
||||
"session_id": "claude-session-123",
|
||||
"cwd": "/path/to/project",
|
||||
"transcript_path": "/path/to/transcript.jsonl",
|
||||
"reason": "exit"
|
||||
}
|
||||
```
|
||||
|
||||
**Processing Steps**:
|
||||
|
||||
```typescript
|
||||
// Send session complete (fire-and-forget HTTP)
|
||||
POST http://127.0.0.1:37777/api/sessions/complete
|
||||
Body: {
|
||||
claudeSessionId: session_id,
|
||||
reason: string // 'exit' | 'clear' | 'logout' | 'prompt_input_exit' | 'other'
|
||||
}
|
||||
Timeout: 2000ms
|
||||
```
|
||||
|
||||
**Worker Processing**:
|
||||
1. Finds session by `claudeSessionId`
|
||||
2. Marks session as 'completed' in database
|
||||
3. Broadcasts session completion event to SSE clients
|
||||
|
||||
**Output**:
|
||||
```json
|
||||
{ "continue": true, "suppressOutput": true }
|
||||
```
|
||||
|
||||
**Implementation**: `src/hooks/cleanup-hook.ts`
|
||||
|
||||
---
|
||||
|
||||
## Session State Machine
|
||||
|
||||
Understanding session lifecycle and state transitions:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> Initialized: SessionStart hook<br/>(generate session_id)
|
||||
|
||||
Initialized --> Active: UserPromptSubmit<br/>(first prompt)
|
||||
|
||||
Active --> Active: UserPromptSubmit<br/>(continuation prompts)<br/>promptNumber++
|
||||
|
||||
Active --> ObservationQueued: PostToolUse hook<br/>(tool execution captured)
|
||||
|
||||
ObservationQueued --> Active: Observation processed<br/>(async, non-blocking)
|
||||
|
||||
Active --> Summarizing: Stop hook<br/>(user pauses/stops)
|
||||
|
||||
Summarizing --> Active: User resumes<br/>(new prompt submitted)
|
||||
|
||||
Summarizing --> Completed: SessionEnd hook<br/>(session closes)
|
||||
|
||||
Active --> Completed: SessionEnd hook<br/>(session closes)
|
||||
|
||||
Completed --> [*]
|
||||
|
||||
note right of Active
|
||||
session_id: constant (e.g., "claude-session-abc123")
|
||||
sessionDbId: constant (e.g., 42)
|
||||
promptNumber: increments (1, 2, 3, ...)
|
||||
All operations use same sessionDbId
|
||||
end note
|
||||
|
||||
note right of ObservationQueued
|
||||
Fire-and-forget HTTP
|
||||
AI compression happens async
|
||||
IDE never blocks
|
||||
end note
|
||||
```
|
||||
|
||||
**Key Insights:**
|
||||
- `session_id` never changes during a conversation
|
||||
- `sessionDbId` is the database primary key for the session
|
||||
- `promptNumber` increments with each user prompt
|
||||
- State transitions are non-blocking (fire-and-forget pattern)
|
||||
|
||||
---
|
||||
|
||||
## Database Schema
|
||||
|
||||
The session-centric data model that enables cross-session memory:
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
SDK_SESSIONS ||--o{ USER_PROMPTS : "has many"
|
||||
SDK_SESSIONS ||--o{ OBSERVATIONS : "has many"
|
||||
SDK_SESSIONS ||--o{ SESSION_SUMMARIES : "has many"
|
||||
|
||||
SDK_SESSIONS {
|
||||
integer id PK "Auto-increment primary key"
|
||||
text claude_session_id UK "From IDE (e.g., 'claude-session-123')"
|
||||
text project "Project name from cwd basename"
|
||||
text first_user_prompt "Initial prompt that started session"
|
||||
integer prompt_counter "Increments with each UserPromptSubmit"
|
||||
text status "initialized | active | completed"
|
||||
datetime created_at
|
||||
datetime completed_at
|
||||
}
|
||||
|
||||
USER_PROMPTS {
|
||||
integer id PK
|
||||
integer session_id FK "References SDK_SESSIONS.id"
|
||||
integer prompt_number "1, 2, 3, ... matches prompt_counter"
|
||||
text prompt "User's actual prompt (tags stripped)"
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
OBSERVATIONS {
|
||||
integer id PK
|
||||
integer session_id FK "References SDK_SESSIONS.id"
|
||||
integer prompt_number "Which prompt this observation belongs to"
|
||||
text tool_name "Read, Bash, Grep, Write, etc."
|
||||
text tool_input_json "Stripped of privacy tags"
|
||||
text tool_response_text "Stripped of privacy tags"
|
||||
text compressed_observation "AI-generated structured observation"
|
||||
datetime created_at
|
||||
}
|
||||
|
||||
SESSION_SUMMARIES {
|
||||
integer id PK
|
||||
integer session_id FK "References SDK_SESSIONS.id"
|
||||
text request "What user requested"
|
||||
text investigated "What was explored"
|
||||
text learned "What was discovered"
|
||||
text completed "What was accomplished"
|
||||
text next_steps "What remains to be done"
|
||||
datetime created_at
|
||||
}
|
||||
```
|
||||
|
||||
**Idempotency Pattern:**
|
||||
|
||||
```sql
|
||||
-- This ensures same session_id always maps to same sessionDbId
|
||||
INSERT OR IGNORE INTO sdk_sessions (claude_session_id, project, first_user_prompt)
|
||||
VALUES (?, ?, ?)
|
||||
RETURNING id;
|
||||
|
||||
-- If already exists, returns existing row
|
||||
-- If new, creates and returns new row
|
||||
```
|
||||
|
||||
**Foreign Key Cascade:**
|
||||
|
||||
All child tables (user_prompts, observations, session_summaries) use `session_id` foreign key referencing `SDK_SESSIONS.id`. This ensures:
|
||||
- All data for a session is queryable by sessionDbId
|
||||
- Session deletions cascade to child tables
|
||||
- Efficient joins for context injection
|
||||
|
||||
<Warning>
|
||||
Never generate your own session IDs. Always use the `session_id` provided by the IDE - this is the source of truth for linking all data together.
|
||||
</Warning>
|
||||
|
||||
---
|
||||
|
||||
## Privacy & Tag Stripping
|
||||
|
||||
### Dual-Tag System
|
||||
|
||||
```typescript
|
||||
// User-Level Privacy Control (manual)
|
||||
<private>sensitive data</private>
|
||||
|
||||
// System-Level Recursion Prevention (auto-injected)
|
||||
<claude-mem-context>...</claude-mem-context>
|
||||
```
|
||||
|
||||
### Processing Pipeline
|
||||
|
||||
**Location**: `src/utils/tag-stripping.ts`
|
||||
|
||||
```typescript
|
||||
// Called by: new-hook.js (user prompts)
|
||||
stripMemoryTagsFromPrompt(prompt: string): string
|
||||
|
||||
// Called by: save-hook.js (tool_input, tool_response)
|
||||
stripMemoryTagsFromJson(jsonString: string): string
|
||||
```
|
||||
|
||||
**Execution Order** (Edge Processing):
|
||||
1. `new-hook.js` strips tags from user prompt before saving
|
||||
2. `save-hook.js` strips tags from tool data before sending to worker
|
||||
3. Worker strips tags again (defense in depth) before storing
|
||||
|
||||
---
|
||||
|
||||
## SDK Agent Processing
|
||||
|
||||
### Query Loop (Event-Driven)
|
||||
|
||||
**Location**: `src/services/worker/SDKAgent.ts`
|
||||
|
||||
```typescript
|
||||
async startSession(session: ActiveSession, worker?: any) {
|
||||
// 1. Create event-driven message generator
|
||||
const messageGenerator = this.createMessageGenerator(session)
|
||||
|
||||
// 2. Run Agent SDK query loop
|
||||
const queryResult = query({
|
||||
prompt: messageGenerator,
|
||||
options: {
|
||||
model: 'claude-haiku-4-5',
|
||||
disallowedTools: ['Bash', 'Read', 'Write', ...], // Observer-only
|
||||
abortController: session.abortController
|
||||
}
|
||||
})
|
||||
|
||||
// 3. Process responses
|
||||
for await (const message of queryResult) {
|
||||
if (message.type === 'assistant') {
|
||||
await this.processSDKResponse(session, text, worker)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Message Types
|
||||
|
||||
The message generator yields three types of prompts:
|
||||
|
||||
1. **Initial Prompt** (prompt #1): Full instructions for starting observation
|
||||
2. **Continuation Prompt** (prompt #2+): Context-only for continuing work
|
||||
3. **Observation Prompts**: Tool use data to compress into observations
|
||||
4. **Summary Prompts**: Session data to summarize
|
||||
|
||||
---
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
For developers implementing this pattern on other platforms:
|
||||
|
||||
### Hook Registration
|
||||
- [ ] Define hook entry points in platform config
|
||||
- [ ] 5 hook types: SessionStart (2 hooks), UserPromptSubmit, PostToolUse, Stop, SessionEnd
|
||||
- [ ] Pass `session_id`, `cwd`, and context-specific data
|
||||
|
||||
### Database Schema
|
||||
- [ ] SQLite with WAL mode
|
||||
- [ ] 4 main tables: `sdk_sessions`, `user_prompts`, `observations`, `session_summaries`
|
||||
- [ ] Indices for common queries
|
||||
|
||||
### Worker Service
|
||||
- [ ] HTTP server on configurable port (default 37777)
|
||||
- [ ] Bun runtime for process management
|
||||
- [ ] 3 core services: SessionManager, SDKAgent, DatabaseManager
|
||||
|
||||
### Hook Implementation
|
||||
- [ ] context-hook: `GET /api/context/inject` (with health check)
|
||||
- [ ] new-hook: createSDKSession, saveUserPrompt, `POST /sessions/{id}/init`
|
||||
- [ ] save-hook: Skip low-value tools, `POST /api/sessions/observations`
|
||||
- [ ] summary-hook: Parse transcript, `POST /api/sessions/summarize`
|
||||
- [ ] cleanup-hook: `POST /api/sessions/complete`
|
||||
|
||||
### Privacy & Tags
|
||||
- [ ] Implement `stripMemoryTagsFromPrompt()` and `stripMemoryTagsFromJson()`
|
||||
- [ ] Process tags at hook layer (edge processing)
|
||||
- [ ] Max tag count = 100 (ReDoS protection)
|
||||
|
||||
### SDK Integration
|
||||
- [ ] Call Claude Agent SDK to process observations/summaries
|
||||
- [ ] Parse XML responses for structured data
|
||||
- [ ] Store to database + sync to vector DB
|
||||
|
||||
---
|
||||
|
||||
## Key Design Principles
|
||||
|
||||
1. **Session ID is Source of Truth**: Never generate your own session IDs
|
||||
2. **Idempotent Database Operations**: Use `INSERT OR IGNORE` for session creation
|
||||
3. **Edge Processing for Privacy**: Strip tags at hook layer before data reaches worker
|
||||
4. **Fire-and-Forget for Non-Blocking**: HTTP timeouts prevent IDE blocking
|
||||
5. **Event-Driven, Not Polling**: Zero-latency queue notification to SDK agent
|
||||
6. **Everything Saves Always**: No "orphaned" sessions
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
| Problem | Root Cause | Solution |
|
||||
|---------|-----------|----------|
|
||||
| Session ID mismatch | Different `session_id` used in different hooks | Always use ID from hook input |
|
||||
| Duplicate sessions | Creating new session instead of using existing | Use `INSERT OR IGNORE` with `session_id` as key |
|
||||
| Blocking IDE | Waiting for full response | Use fire-and-forget with short timeouts |
|
||||
| Memory tags in DB | Stripping tags in wrong layer | Strip at hook layer, before HTTP send |
|
||||
| Worker not found | Health check too fast | Add retry loop with exponential backoff |
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Worker Service](/architecture/worker-service) - HTTP API and async processing
|
||||
- [Database Schema](/architecture/database) - SQLite tables and FTS5 search
|
||||
- [Privacy Tags](/usage/private-tags) - Using `<private>` tags
|
||||
- [Troubleshooting](/troubleshooting) - Common hook issues
|
||||
@@ -0,0 +1,240 @@
|
||||
---
|
||||
title: "Architecture Overview"
|
||||
description: "System components and data flow in Claude-Mem"
|
||||
---
|
||||
|
||||
# Architecture Overview
|
||||
|
||||
## System Components
|
||||
|
||||
Claude-Mem operates as a Claude Code plugin with five core components:
|
||||
|
||||
1. **Plugin Hooks** - Capture lifecycle events (6 hook files)
|
||||
2. **Smart Install** - Cached dependency checker (pre-hook script, runs before context-hook)
|
||||
3. **Worker Service** - Process observations via Claude Agent SDK + HTTP API (10 search endpoints)
|
||||
4. **Database Layer** - Store sessions and observations (SQLite + FTS5 + ChromaDB)
|
||||
5. **mem-search Skill** - Skill-based search with progressive disclosure (v5.4.0+)
|
||||
6. **Viewer UI** - Web-based real-time memory stream visualization
|
||||
|
||||
## Technology Stack
|
||||
|
||||
| Layer | Technology |
|
||||
|------------------------|-------------------------------------------|
|
||||
| **Language** | TypeScript (ES2022, ESNext modules) |
|
||||
| **Runtime** | Node.js 18+ |
|
||||
| **Database** | SQLite 3 with bun:sqlite driver |
|
||||
| **Vector Store** | ChromaDB (optional, for semantic search) |
|
||||
| **HTTP Server** | Express.js 4.18 |
|
||||
| **Real-time** | Server-Sent Events (SSE) |
|
||||
| **UI Framework** | React + TypeScript |
|
||||
| **AI SDK** | @anthropic-ai/claude-agent-sdk |
|
||||
| **Build Tool** | esbuild (bundles TypeScript) |
|
||||
| **Process Manager** | Bun |
|
||||
| **Testing** | Node.js built-in test runner |
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Memory Pipeline
|
||||
```
|
||||
Hook (stdin) → Database → Worker Service → SDK Processor → Database → Next Session Hook
|
||||
```
|
||||
|
||||
1. **Input**: Claude Code sends tool execution data via stdin to hooks
|
||||
2. **Storage**: Hooks write observations to SQLite database
|
||||
3. **Processing**: Worker service reads observations, processes via SDK
|
||||
4. **Output**: Processed summaries written back to database
|
||||
5. **Retrieval**: Next session's context hook reads summaries from database
|
||||
|
||||
### Search Pipeline (v5.4.0+)
|
||||
```
|
||||
User Query → mem-search Skill Invoked → HTTP API → SessionSearch Service → FTS5 Database → Search Results → Claude
|
||||
```
|
||||
|
||||
1. **User Query**: User asks naturally: "What bugs did we fix?"
|
||||
2. **Skill Invoked**: Claude recognizes intent and invokes mem-search skill
|
||||
3. **HTTP API**: Skill uses curl to call HTTP endpoint (e.g., `/api/search/observations`)
|
||||
4. **SessionSearch**: Worker service queries FTS5 virtual tables
|
||||
5. **Format**: Results formatted and returned to skill
|
||||
6. **Return**: Claude presents formatted results to user
|
||||
|
||||
**Token Savings**: ~2,250 tokens per session vs MCP approach through progressive disclosure
|
||||
|
||||
## Session Lifecycle
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 0. Smart Install Pre-Hook Fires │
|
||||
│ Checks dependencies (cached), only runs on version changes │
|
||||
│ Not a lifecycle hook - runs before context-hook starts │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 1. Session Starts → Context Hook Fires │
|
||||
│ Starts Bun worker if needed, injects context from previous │
|
||||
│ sessions (configurable observation count) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 2. User Types Prompt → UserPromptSubmit Hook Fires │
|
||||
│ Creates session in database, saves raw user prompt for FTS5 │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 3. Claude Uses Tools → PostToolUse Hook Fires (100+ times) │
|
||||
│ Captures tool executions, sends to worker for AI compression │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 4. Worker Processes → Claude Agent SDK Analyzes │
|
||||
│ Extracts structured learnings via iterative AI processing │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 5. Claude Stops → Summary Hook Fires │
|
||||
│ Generates final summary with request, completions, learnings │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ 6. Session Ends → Cleanup Hook Fires │
|
||||
│ Marks session complete (graceful, not DELETE), ready for │
|
||||
│ next session context. Skips on /clear to preserve ongoing │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
claude-mem/
|
||||
├── src/
|
||||
│ ├── hooks/ # Hook implementations (6 hooks)
|
||||
│ │ ├── context-hook.ts # SessionStart
|
||||
│ │ ├── user-message-hook.ts # UserMessage (for debugging)
|
||||
│ │ ├── new-hook.ts # UserPromptSubmit
|
||||
│ │ ├── save-hook.ts # PostToolUse
|
||||
│ │ ├── summary-hook.ts # Stop
|
||||
│ │ ├── cleanup-hook.ts # SessionEnd
|
||||
│ │ └── hook-response.ts # Hook response utilities
|
||||
│ │
|
||||
│ ├── sdk/ # Claude Agent SDK integration
|
||||
│ │ ├── prompts.ts # XML prompt builders
|
||||
│ │ ├── parser.ts # XML response parser
|
||||
│ │ └── worker.ts # Main SDK agent loop
|
||||
│ │
|
||||
│ ├── services/
|
||||
│ │ ├── worker-service.ts # Express HTTP + SSE service
|
||||
│ │ └── sqlite/ # Database layer
|
||||
│ │ ├── SessionStore.ts # CRUD operations
|
||||
│ │ ├── SessionSearch.ts # FTS5 search service
|
||||
│ │ ├── migrations.ts
|
||||
│ │ └── types.ts
|
||||
│ │
|
||||
│ ├── ui/ # Viewer UI
|
||||
│ │ └── viewer/ # React + TypeScript web interface
|
||||
│ │ ├── components/ # UI components
|
||||
│ │ ├── hooks/ # React hooks
|
||||
│ │ ├── utils/ # Utilities
|
||||
│ │ └── assets/ # Fonts, logos
|
||||
│ │
|
||||
│ ├── shared/ # Shared utilities
|
||||
│ │ ├── config.ts
|
||||
│ │ ├── paths.ts
|
||||
│ │ └── storage.ts
|
||||
│ │
|
||||
│ └── utils/
|
||||
│ ├── logger.ts
|
||||
│ ├── platform.ts
|
||||
│ └── port-allocator.ts
|
||||
│
|
||||
├── scripts/ # Build and utility scripts
|
||||
│ └── smart-install.js # Cached dependency checker (pre-hook)
|
||||
│
|
||||
├── plugin/ # Plugin distribution
|
||||
│ ├── .claude-plugin/
|
||||
│ │ └── plugin.json
|
||||
│ ├── hooks/
|
||||
│ │ └── hooks.json
|
||||
│ ├── scripts/ # Built executables
|
||||
│ │ ├── context-hook.js
|
||||
│ │ ├── user-message-hook.js
|
||||
│ │ ├── new-hook.js
|
||||
│ │ ├── save-hook.js
|
||||
│ │ ├── summary-hook.js
|
||||
│ │ ├── cleanup-hook.js
|
||||
│ │ └── worker-service.cjs # Background worker + HTTP API
|
||||
│ │
|
||||
│ ├── skills/ # Agent skills (v5.4.0+)
|
||||
│ │ ├── mem-search/ # Search skill with progressive disclosure (v5.5.0)
|
||||
│ │ │ ├── SKILL.md # Skill frontmatter (~250 tokens)
|
||||
│ │ │ ├── operations/ # 12 detailed operation docs
|
||||
│ │ │ └── principles/ # 2 principle guides
|
||||
│ │ ├── troubleshoot/ # Troubleshooting skill
|
||||
│ │ │ ├── SKILL.md
|
||||
│ │ │ └── operations/ # 6 operation docs
|
||||
│ │ └── version-bump/ # Version management skill (deprecated)
|
||||
│ │
|
||||
│ └── ui/ # Built viewer UI
|
||||
│ └── viewer.html # Self-contained bundle
|
||||
│
|
||||
├── tests/ # Test suite
|
||||
├── docs/ # Documentation
|
||||
└── ecosystem.config.cjs # Process configuration (deprecated)
|
||||
```
|
||||
|
||||
## Component Details
|
||||
|
||||
### 1. Plugin Hooks (6 Hooks)
|
||||
- **context-hook.js** - SessionStart: Starts Bun worker, injects context
|
||||
- **user-message-hook.js** - UserMessage: Debugging hook
|
||||
- **new-hook.js** - UserPromptSubmit: Creates session, saves prompt
|
||||
- **save-hook.js** - PostToolUse: Captures tool executions
|
||||
- **summary-hook.js** - Stop: Generates session summary
|
||||
- **cleanup-hook.js** - SessionEnd: Marks session complete
|
||||
|
||||
**Note**: smart-install.js is a pre-hook dependency checker (not a lifecycle hook). It's called before context-hook via command chaining in hooks.json and only runs when dependencies need updating.
|
||||
|
||||
See [Plugin Hooks](/architecture/hooks) for detailed hook documentation.
|
||||
|
||||
### 2. Worker Service
|
||||
Express.js HTTP server on port 37777 (configurable) with:
|
||||
- 10 search HTTP API endpoints (v5.4.0+)
|
||||
- 8 viewer UI HTTP/SSE endpoints
|
||||
- Async observation processing via Claude Agent SDK
|
||||
- Real-time updates via Server-Sent Events
|
||||
- Auto-managed by Bun
|
||||
|
||||
See [Worker Service](/architecture/worker-service) for HTTP API and endpoints.
|
||||
|
||||
### 3. Database Layer
|
||||
SQLite3 with bun:sqlite driver featuring:
|
||||
- FTS5 virtual tables for full-text search
|
||||
- SessionStore for CRUD operations
|
||||
- SessionSearch for FTS5 queries
|
||||
- Location: `~/.claude-mem/claude-mem.db`
|
||||
|
||||
See [Database Architecture](/architecture/database) for schema and FTS5 search.
|
||||
|
||||
### 4. mem-search Skill (v5.4.0+)
|
||||
Skill-based search with progressive disclosure providing 10 search operations:
|
||||
- Search observations, sessions, prompts (full-text FTS5)
|
||||
- Filter by type, concept, file
|
||||
- Get recent context, timeline, timeline by query
|
||||
- API help documentation
|
||||
|
||||
**Token Savings**: ~2,250 tokens per session vs MCP approach
|
||||
- Skill frontmatter: ~250 tokens (loaded at session start)
|
||||
- Full instructions: ~2,500 tokens (loaded on-demand when invoked)
|
||||
- HTTP API endpoints instead of MCP tools
|
||||
|
||||
**Skill Enhancement (v5.5.0)**: Renamed from "search" to "mem-search" for better scope differentiation. Effectiveness increased from 67% to 100% with enhanced triggers and comprehensive documentation.
|
||||
|
||||
See [Search Architecture](/architecture/search-architecture) for technical details and examples.
|
||||
|
||||
### 5. Viewer UI
|
||||
React + TypeScript web interface at http://localhost:37777 featuring:
|
||||
- Real-time memory stream via Server-Sent Events
|
||||
- Infinite scroll pagination with automatic deduplication
|
||||
- Project filtering and settings persistence
|
||||
- GPU-accelerated animations
|
||||
- Self-contained HTML bundle (viewer.html)
|
||||
|
||||
Built with esbuild into a single file deployment.
|
||||
@@ -0,0 +1,551 @@
|
||||
---
|
||||
title: "PM2 to Bun Migration"
|
||||
description: "Complete technical documentation for the process management and database driver migration in v7.1.0"
|
||||
---
|
||||
|
||||
# PM2 to Bun Migration: Complete Technical Documentation
|
||||
|
||||
**Version**: 7.1.0
|
||||
**Date**: December 2025
|
||||
**Migration Type**: Process Management (PM2 → Bun) + Database Driver (better-sqlite3 → bun:sqlite)
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Claude-mem version 7.1.0 introduces two major architectural migrations:
|
||||
|
||||
1. **Process Management**: PM2 → Custom Bun-based ProcessManager
|
||||
2. **Database Driver**: better-sqlite3 npm package → bun:sqlite runtime module
|
||||
|
||||
Both migrations are **automatic** and **transparent** to end users. The first time a hook fires after updating to 7.1.0+, the system performs a one-time cleanup of legacy PM2 processes and transitions to the new architecture.
|
||||
|
||||
### Key Benefits
|
||||
|
||||
- **Simplified Dependencies**: Removes PM2 and better-sqlite3 npm packages
|
||||
- **Improved Cross-Platform Support**: Better Windows compatibility
|
||||
- **Faster Installation**: No native module compilation required
|
||||
- **Built-in Runtime**: Leverages Bun's built-in process management and SQLite
|
||||
- **Reduced Complexity**: Custom ProcessManager is simpler than PM2 integration
|
||||
|
||||
### Migration Impact
|
||||
|
||||
- **Data Preservation**: User data, settings, and database remain unchanged
|
||||
- **Automatic Cleanup**: Old PM2 processes automatically terminated (all platforms)
|
||||
- **No User Action Required**: Migration happens automatically on first hook trigger
|
||||
- **Backward Compatible**: SQLite database format unchanged (only driver changed)
|
||||
|
||||
## Architecture Comparison
|
||||
|
||||
### Old System (PM2-based)
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Process Management (PM2)">
|
||||
**Component**: PM2 (Process Manager 2)
|
||||
- **Package**: `pm2` npm dependency
|
||||
- **Process Name**: `claude-mem-worker`
|
||||
- **Management**: External PM2 daemon manages lifecycle
|
||||
- **Discovery**: `pm2 list`, `pm2 describe` commands
|
||||
- **Auto-restart**: PM2 automatically restarts on crash
|
||||
- **Logs**: `~/.pm2/logs/claude-mem-worker-*.log`
|
||||
- **PID File**: `~/.pm2/pids/claude-mem-worker.pid`
|
||||
|
||||
**Lifecycle Commands**:
|
||||
```bash
|
||||
pm2 start <script> # Start worker
|
||||
pm2 stop claude-mem-worker # Stop worker
|
||||
pm2 restart claude-mem-worker # Restart worker
|
||||
pm2 delete claude-mem-worker # Remove from PM2
|
||||
pm2 logs claude-mem-worker # View logs
|
||||
```
|
||||
|
||||
**Pain Points**:
|
||||
- Additional npm dependency required
|
||||
- PM2 daemon must be running
|
||||
- Potential conflicts with other PM2 processes
|
||||
- Windows compatibility issues
|
||||
- Complex configuration for simple use case
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Database Driver (better-sqlite3)">
|
||||
**Component**: better-sqlite3
|
||||
- **Package**: `better-sqlite3` npm package (native module)
|
||||
- **Installation**: Requires native compilation (node-gyp)
|
||||
- **Windows**: Requires Visual Studio build tools + Python
|
||||
- **Import**: `import Database from 'better-sqlite3'`
|
||||
|
||||
**Installation Requirements**:
|
||||
- Node.js development headers
|
||||
- C++ compiler (gcc/clang on Mac/Linux, MSVC on Windows)
|
||||
- Python (for node-gyp)
|
||||
- Windows: Visual Studio Build Tools
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
### New System (Bun-based)
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Process Management (Custom ProcessManager)">
|
||||
**Component**: Custom ProcessManager (`src/services/process/ProcessManager.ts`)
|
||||
- **Package**: Built-in Bun APIs (no external dependency)
|
||||
- **Process Spawn**: `Bun.spawn()` with detached mode
|
||||
- **Management**: Direct process control via PID file
|
||||
- **Discovery**: PID file + process existence check + HTTP health check
|
||||
- **Auto-restart**: Hook-triggered restart on failure detection
|
||||
- **Logs**: `~/.claude-mem/logs/worker-YYYY-MM-DD.log`
|
||||
- **PID File**: `~/.claude-mem/.worker.pid`
|
||||
- **Port File**: `~/.claude-mem/.worker.port` (new)
|
||||
|
||||
**Lifecycle Commands**:
|
||||
```bash
|
||||
npm run worker:start # Start worker
|
||||
npm run worker:stop # Stop worker
|
||||
npm run worker:restart # Restart worker
|
||||
npm run worker:status # Check status
|
||||
npm run worker:logs # View logs
|
||||
```
|
||||
|
||||
**Core Mechanisms**:
|
||||
|
||||
1. **PID File Management**:
|
||||
- File: `~/.claude-mem/.worker.pid`
|
||||
- Content: Process ID (e.g., "35557")
|
||||
- Validation: Process existence via `kill(pid, 0)` signal
|
||||
|
||||
2. **Port File Management**:
|
||||
- File: `~/.claude-mem/.worker.port`
|
||||
- Content: Two lines (port number, PID)
|
||||
- Purpose: Track port binding and validate PID match
|
||||
|
||||
3. **Health Checking**:
|
||||
- Layer 1: PID file exists?
|
||||
- Layer 2: Process alive? (`kill(pid, 0)`)
|
||||
- Layer 3: HTTP health check (`GET /health`)
|
||||
- All three must pass for "healthy" status
|
||||
|
||||
**Advantages**:
|
||||
- No external dependencies
|
||||
- Simpler codebase (direct control)
|
||||
- Better error handling and validation
|
||||
- Platform-agnostic (Bun handles platform differences)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Database Driver (bun:sqlite)">
|
||||
**Component**: bun:sqlite
|
||||
- **Package**: Built into Bun runtime (no npm package)
|
||||
- **Installation**: None required (comes with Bun ≥1.0)
|
||||
- **Platform**: Works anywhere Bun works
|
||||
- **Import**: `import { Database } from 'bun:sqlite'`
|
||||
- **API**: Similar to better-sqlite3 (synchronous)
|
||||
|
||||
**Installation Requirements**:
|
||||
- Bun ≥1.0 (automatically installed if missing)
|
||||
- No native compilation required
|
||||
- No platform-specific build tools needed
|
||||
|
||||
**Compatibility**:
|
||||
- SQLite database format: **Unchanged**
|
||||
- Database file: `~/.claude-mem/claude-mem.db` (same location)
|
||||
- Query syntax: **Identical** (both use SQLite SQL)
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
## Migration Mechanics
|
||||
|
||||
### One-Time PM2 Cleanup
|
||||
|
||||
The migration system uses a marker-based approach to perform PM2 cleanup exactly once.
|
||||
|
||||
**Implementation**: `src/shared/worker-utils.ts:73-86`
|
||||
|
||||
```typescript
|
||||
// Clean up legacy PM2 (one-time migration)
|
||||
const pm2MigratedMarker = join(DATA_DIR, '.pm2-migrated');
|
||||
|
||||
if (!existsSync(pm2MigratedMarker)) {
|
||||
try {
|
||||
spawnSync('pm2', ['delete', 'claude-mem-worker'], { stdio: 'ignore' });
|
||||
// Mark migration as complete
|
||||
writeFileSync(pm2MigratedMarker, new Date().toISOString(), 'utf-8');
|
||||
logger.debug('SYSTEM', 'PM2 cleanup completed and marked');
|
||||
} catch {
|
||||
// PM2 not installed or process doesn't exist - still mark as migrated
|
||||
writeFileSync(pm2MigratedMarker, new Date().toISOString(), 'utf-8');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Migration Trigger Points
|
||||
|
||||
<Steps>
|
||||
<Step title="Hook Execution">
|
||||
SessionStart, UserPromptSubmit, or PostToolUse hooks execute using new 7.1.0 code
|
||||
</Step>
|
||||
<Step title="Worker Status Check">
|
||||
`ensureWorkerRunning()` checks if `~/.claude-mem/.worker.pid` exists (it doesn't for first run after update)
|
||||
</Step>
|
||||
<Step title="Start Worker Decision">
|
||||
Worker not running → Call `startWorker()`
|
||||
</Step>
|
||||
<Step title="Migration Check">
|
||||
Check if `~/.claude-mem/.pm2-migrated` exists
|
||||
</Step>
|
||||
<Step title="PM2 Cleanup">
|
||||
Execute `pm2 delete claude-mem-worker` (errors ignored), create marker file
|
||||
</Step>
|
||||
<Step title="New Worker Start">
|
||||
Spawn new Bun-managed worker process with PID and port files
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
### Marker File
|
||||
|
||||
**Location**: `~/.claude-mem/.pm2-migrated`
|
||||
|
||||
**Content**: ISO 8601 timestamp
|
||||
```
|
||||
2025-12-13T00:18:39.673Z
|
||||
```
|
||||
|
||||
**Purpose**:
|
||||
- One-time migration flag
|
||||
- Prevents repeated PM2 cleanup on every start
|
||||
- Persists across restarts and reboots
|
||||
|
||||
**Lifecycle**:
|
||||
- Created: First hook trigger after update to 7.1.0+ (all platforms)
|
||||
- Updated: Never
|
||||
- Deleted: Never (user could manually delete to force re-migration)
|
||||
|
||||
## User Experience Timeline
|
||||
|
||||
### First Session After Update
|
||||
|
||||
<Note>
|
||||
This is the critical migration moment. The process takes approximately 2-5 seconds.
|
||||
</Note>
|
||||
|
||||
**Step-by-Step Execution**:
|
||||
|
||||
1. **Hook fires** (SessionStart most common)
|
||||
2. **Worker status check**: No PID file → worker not running
|
||||
3. **Migration check**: No marker file → run PM2 cleanup
|
||||
4. **PM2 cleanup**: `pm2 delete claude-mem-worker` (old worker terminated)
|
||||
5. **Marker creation**: `~/.claude-mem/.pm2-migrated` with timestamp
|
||||
6. **New worker start**: Bun process spawned, PID/port files created
|
||||
7. **Verification**: Process check + HTTP health check
|
||||
8. **Hook completes**: Claude Code session starts normally
|
||||
|
||||
**User Observable Behavior**:
|
||||
- Slight delay on first startup (PM2 cleanup + new worker spawn)
|
||||
- No error messages (cleanup failures silently handled)
|
||||
- Worker appears running via `npm run worker:status`
|
||||
- Old PM2 worker no longer in `pm2 list`
|
||||
|
||||
### Subsequent Sessions
|
||||
|
||||
After migration completes, every hook trigger follows the fast path:
|
||||
|
||||
1. PID file exists? **YES**
|
||||
2. Process alive? **YES**
|
||||
3. HTTP health check? **SUCCESS**
|
||||
4. Result: Worker already running, done (~50ms)
|
||||
|
||||
No migration logic runs on subsequent sessions.
|
||||
|
||||
## Platform-Specific Behavior
|
||||
|
||||
### Platform Comparison
|
||||
|
||||
| Feature | macOS | Linux | Windows |
|
||||
|---------|-------|-------|---------|
|
||||
| PM2 Cleanup | Attempted | Attempted | Attempted |
|
||||
| Marker File | Created | Created | Created |
|
||||
| Process Signals | POSIX (native) | POSIX (native) | Bun abstraction |
|
||||
| Bun Support | Full | Full | Full |
|
||||
| PID File | Yes | Yes | Yes |
|
||||
| Port File | Yes | Yes | Yes |
|
||||
| Health Check | HTTP | HTTP | HTTP |
|
||||
| Migration Delay | ~2-5s first time | ~2-5s first time | ~2-5s first time |
|
||||
|
||||
### Platform Notes
|
||||
|
||||
<Tabs>
|
||||
<Tab title="macOS">
|
||||
- POSIX signal handling works natively
|
||||
- Bun fully supported
|
||||
- No platform-specific workarounds needed
|
||||
</Tab>
|
||||
<Tab title="Linux">
|
||||
- Identical behavior to macOS
|
||||
- POSIX signal handling
|
||||
- Works on Ubuntu, Debian, RHEL, CentOS, Arch
|
||||
- Alpine may require glibc (not musl)
|
||||
</Tab>
|
||||
<Tab title="Windows">
|
||||
- PM2 cleanup now runs (safe due to try/catch)
|
||||
- Bun abstracts signal handling differences
|
||||
- Path module handles Windows separators
|
||||
- File locking handled by SQLite
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Observable Changes
|
||||
|
||||
### Command Changes
|
||||
|
||||
| Old (PM2) | New (Bun) | Notes |
|
||||
|-----------|-----------|-------|
|
||||
| `pm2 list` | `npm run worker:status` | Shows worker status |
|
||||
| `pm2 start <script>` | `npm run worker:start` | Start worker |
|
||||
| `pm2 stop claude-mem-worker` | `npm run worker:stop` | Stop worker |
|
||||
| `pm2 restart claude-mem-worker` | `npm run worker:restart` | Restart worker |
|
||||
| `pm2 delete claude-mem-worker` | `npm run worker:stop` | Remove worker |
|
||||
| `pm2 logs claude-mem-worker` | `npm run worker:logs` | View logs |
|
||||
| `pm2 describe claude-mem-worker` | `npm run worker:status` | Detailed status |
|
||||
| `pm2 monit` | No equivalent | PM2-specific monitoring |
|
||||
|
||||
### File Location Changes
|
||||
|
||||
**Logs**:
|
||||
```
|
||||
Old: ~/.pm2/logs/claude-mem-worker-out.log
|
||||
~/.pm2/logs/claude-mem-worker-error.log
|
||||
|
||||
New: ~/.claude-mem/logs/worker-YYYY-MM-DD.log
|
||||
```
|
||||
|
||||
**PID Files**:
|
||||
```
|
||||
Old: ~/.pm2/pids/claude-mem-worker.pid
|
||||
|
||||
New: ~/.claude-mem/.worker.pid
|
||||
```
|
||||
|
||||
**Process State**:
|
||||
```
|
||||
Old: PM2 daemon memory (pm2 save)
|
||||
|
||||
New: ~/.claude-mem/.worker.pid
|
||||
~/.claude-mem/.worker.port
|
||||
~/.claude-mem/.pm2-migrated (all platforms)
|
||||
```
|
||||
|
||||
**Database** (unchanged):
|
||||
```
|
||||
Same: ~/.claude-mem/claude-mem.db
|
||||
```
|
||||
|
||||
### User-Visible Changes
|
||||
|
||||
**Before Update**:
|
||||
```bash
|
||||
$ pm2 list
|
||||
┌────┬────────────────────┬─────────┬─────────┬──────────┐
|
||||
│ id │ name │ status │ restart │ uptime │
|
||||
├────┼────────────────────┼─────────┼─────────┼──────────┤
|
||||
│ 0 │ claude-mem-worker │ online │ 0 │ 2d 5h │
|
||||
└────┴────────────────────┴─────────┴─────────┴──────────┘
|
||||
```
|
||||
|
||||
**After Update**:
|
||||
```bash
|
||||
$ pm2 list
|
||||
# Empty - worker no longer managed by PM2
|
||||
|
||||
$ npm run worker:status
|
||||
Worker is running
|
||||
PID: 35557
|
||||
Port: 37777
|
||||
Uptime: 2h 15m
|
||||
```
|
||||
|
||||
### Orphaned Files
|
||||
|
||||
After migration, these PM2 files may remain (safe to delete):
|
||||
|
||||
```
|
||||
~/.pm2/ # Entire PM2 directory
|
||||
~/.pm2/logs/ # Old logs
|
||||
~/.pm2/pids/ # Old PID files
|
||||
~/.pm2/pm2.log # PM2 daemon log
|
||||
~/.pm2/dump.pm2 # PM2 process dump
|
||||
```
|
||||
|
||||
**Cleanup (optional)**:
|
||||
```bash
|
||||
# Remove PM2 entirely (if not used for other processes)
|
||||
pm2 kill
|
||||
rm -rf ~/.pm2
|
||||
|
||||
# Or just remove claude-mem logs
|
||||
rm -f ~/.pm2/logs/claude-mem-worker-*.log
|
||||
rm -f ~/.pm2/pids/claude-mem-worker.pid
|
||||
```
|
||||
|
||||
## File System State
|
||||
|
||||
### State Directory Structure
|
||||
|
||||
**Before Migration** (PM2 system):
|
||||
```
|
||||
~/.claude-mem/
|
||||
├── claude-mem.db # Database (unchanged)
|
||||
├── chroma/ # Vector embeddings (unchanged)
|
||||
├── logs/ # Application logs (unchanged)
|
||||
└── settings.json # User settings (unchanged)
|
||||
|
||||
~/.pm2/
|
||||
├── logs/
|
||||
│ ├── claude-mem-worker-out.log
|
||||
│ └── claude-mem-worker-error.log
|
||||
├── pids/
|
||||
│ └── claude-mem-worker.pid
|
||||
└── pm2.log
|
||||
```
|
||||
|
||||
**After Migration** (Bun system):
|
||||
```
|
||||
~/.claude-mem/
|
||||
├── claude-mem.db # Database (same file)
|
||||
├── chroma/ # Vector embeddings (unchanged)
|
||||
├── logs/
|
||||
│ └── worker-2025-12-13.log # New log format
|
||||
├── settings.json # User settings (unchanged)
|
||||
├── .worker.pid # NEW: Process ID
|
||||
├── .worker.port # NEW: Port + PID
|
||||
└── .pm2-migrated # NEW: Migration marker (all platforms)
|
||||
|
||||
~/.pm2/ # Orphaned (safe to delete)
|
||||
├── logs/ # Old logs (no longer written)
|
||||
├── pids/ # Old PID (no longer updated)
|
||||
└── pm2.log # PM2 daemon log (not used)
|
||||
```
|
||||
|
||||
## Edge Cases and Troubleshooting
|
||||
|
||||
### Scenario 1: Migration Fails (PM2 Still Running)
|
||||
|
||||
<Warning>
|
||||
This is rare but can happen if PM2 has watch mode enabled or the process is manually restarted.
|
||||
</Warning>
|
||||
|
||||
**Symptoms**:
|
||||
- `pm2 list` still shows `claude-mem-worker`
|
||||
- Port conflict errors in logs
|
||||
- Worker fails to start
|
||||
|
||||
**Resolution**:
|
||||
```bash
|
||||
# Manual cleanup
|
||||
pm2 delete claude-mem-worker
|
||||
pm2 save # Persist the deletion
|
||||
|
||||
# Force re-migration (optional)
|
||||
rm ~/.claude-mem/.pm2-migrated
|
||||
|
||||
# Restart worker
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
### Scenario 2: Stale PID File (Process Dead)
|
||||
|
||||
**Symptoms**:
|
||||
- `npm run worker:status` shows "not running"
|
||||
- `.worker.pid` file exists
|
||||
- Process ID doesn't exist
|
||||
|
||||
**Automatic Recovery**: Next hook trigger detects dead process and starts a fresh worker.
|
||||
|
||||
**Manual Resolution**:
|
||||
```bash
|
||||
rm ~/.claude-mem/.worker.pid
|
||||
rm ~/.claude-mem/.worker.port
|
||||
npm run worker:start
|
||||
```
|
||||
|
||||
### Scenario 3: Port Already in Use
|
||||
|
||||
**Error**: `EADDRINUSE: address already in use`
|
||||
|
||||
**Resolution**:
|
||||
```bash
|
||||
# Check what's using the port
|
||||
lsof -i :37777
|
||||
|
||||
# Kill the process
|
||||
kill -9 <PID>
|
||||
|
||||
# Restart worker
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
### Common Error Messages
|
||||
|
||||
| Error | Cause | Resolution |
|
||||
|-------|-------|------------|
|
||||
| `EADDRINUSE` | Port already in use | `lsof -i :37777` then kill conflicting process |
|
||||
| `No such process` | Stale PID file | Automatic cleanup on next hook trigger |
|
||||
| `pm2: command not found` | PM2 not installed | None needed (error is caught and ignored) |
|
||||
| `Invalid port X` | Port validation failed | Update `CLAUDE_MEM_WORKER_PORT` in settings |
|
||||
|
||||
## Developer Notes
|
||||
|
||||
### Testing the Migration
|
||||
|
||||
```bash
|
||||
# 1. Install old version (with PM2)
|
||||
git checkout <pre-7.1.0-tag>
|
||||
npm install && npm run build && npm run sync-marketplace
|
||||
|
||||
# 2. Start PM2 worker
|
||||
pm2 start plugin/scripts/worker-cli.js --name claude-mem-worker
|
||||
|
||||
# 3. Update to new version
|
||||
git checkout main
|
||||
npm install && npm run build && npm run sync-marketplace
|
||||
|
||||
# 4. Trigger hook
|
||||
node plugin/scripts/session-start-hook.js
|
||||
|
||||
# 5. Verify migration
|
||||
pm2 list # Should NOT show claude-mem-worker
|
||||
cat ~/.claude-mem/.pm2-migrated # Should exist
|
||||
npm run worker:status # Should show Bun worker running
|
||||
```
|
||||
|
||||
### Architecture Decisions
|
||||
|
||||
**Why Custom ProcessManager Instead of PM2?**
|
||||
1. **Simplicity**: Direct control, no external daemon
|
||||
2. **Dependencies**: Remove npm dependency
|
||||
3. **Cross-platform**: Bun handles platform differences
|
||||
4. **Bundle Size**: Reduce plugin package size
|
||||
5. **Control**: Fine-grained error handling and validation
|
||||
|
||||
**Why One-Time Marker Instead of Always Running PM2 Delete?**
|
||||
1. **Performance**: Avoid unnecessary process spawning
|
||||
2. **Idempotency**: Migration runs exactly once
|
||||
3. **Debugging**: Timestamp shows when migration occurred
|
||||
4. **Simplicity**: Clear migration state
|
||||
|
||||
**Why Run PM2 Cleanup on All Platforms?**
|
||||
1. **Quality Migration**: Clean up orphaned processes
|
||||
2. **Consistency**: Same behavior across all platforms
|
||||
3. **Safety**: Error handling already in place (try/catch)
|
||||
4. **No Downside**: If PM2 not installed, error is caught and ignored
|
||||
|
||||
## Summary
|
||||
|
||||
The migration from PM2 to Bun-based ProcessManager is a **one-time, automatic, transparent** transition that:
|
||||
|
||||
1. **Removes external dependencies** (PM2, better-sqlite3)
|
||||
2. **Simplifies architecture** (direct process control)
|
||||
3. **Improves cross-platform support** (especially Windows)
|
||||
4. **Preserves user data** (database, settings, logs unchanged)
|
||||
5. **Requires no user action** (automatic on first hook trigger)
|
||||
|
||||
**Key Migration Moment**: First hook trigger after update to 7.1.0+
|
||||
**Duration**: ~2-5 seconds (one-time delay)
|
||||
**Impact**: Seamless transition, user-invisible
|
||||
**Rollback**: Not needed (migration is forward-only, safe)
|
||||
|
||||
For most users, the migration will be completely transparent - they'll see no errors, no data loss, and experience improved reliability and simpler troubleshooting going forward.
|
||||
@@ -0,0 +1,448 @@
|
||||
---
|
||||
title: "Search Architecture"
|
||||
description: "mem-search skill with HTTP API and progressive disclosure"
|
||||
---
|
||||
|
||||
# Search Architecture
|
||||
|
||||
Claude-Mem uses a skill-based search architecture that provides intelligent memory retrieval through natural language queries. This replaced the MCP-based approach in v5.4.0, saving ~2,250 tokens per session start. The skill was enhanced and renamed to "mem-search" in v5.5.0 for better scope differentiation.
|
||||
|
||||
## Overview
|
||||
|
||||
**Architecture**: Skill-Based Search + HTTP API + Progressive Disclosure
|
||||
|
||||
**Key Components**:
|
||||
1. **mem-search Skill** (`plugin/skills/mem-search/SKILL.md`) - Auto-invoked when users ask about past work
|
||||
2. **HTTP API Endpoints** (10 routes) - Fast, efficient search operations on port 37777
|
||||
3. **Worker Service** - Express.js server with FTS5 full-text search
|
||||
4. **SQLite Database** - Persistent storage with FTS5 virtual tables
|
||||
5. **Chroma Vector DB** - Semantic search with hybrid retrieval
|
||||
|
||||
**v5.5.0 Enhancement**: Renamed from "search" to "mem-search" with:
|
||||
- Effectiveness increased from 67% to 100%
|
||||
- Concrete triggers increased from 44% to 85%
|
||||
- 5+ unique identifiers for better scope differentiation
|
||||
- Comprehensive documentation (17 files, 12 operation guides)
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. User Query (Natural Language)
|
||||
|
||||
```
|
||||
User: "What bugs did we fix last session?"
|
||||
```
|
||||
|
||||
### 2. Skill Invocation
|
||||
|
||||
Claude recognizes the intent and invokes the mem-search skill:
|
||||
- Skill frontmatter (~250 tokens) loaded at session start
|
||||
- Full skill instructions loaded on-demand when skill is invoked
|
||||
- Progressive disclosure pattern minimizes context overhead
|
||||
- "mem-search" naming provides clear scope differentiation from native memory
|
||||
|
||||
### 3. HTTP API Call
|
||||
|
||||
The skill uses `curl` to call the HTTP API:
|
||||
|
||||
```bash
|
||||
curl "http://localhost:37777/api/search/observations?query=bugs&type=bugfix&limit=5"
|
||||
```
|
||||
|
||||
### 4. FTS5 Search
|
||||
|
||||
Worker service queries SQLite FTS5 virtual tables:
|
||||
|
||||
```sql
|
||||
SELECT * FROM observations_fts
|
||||
WHERE observations_fts MATCH ?
|
||||
AND type = 'bugfix'
|
||||
ORDER BY rank
|
||||
LIMIT 5
|
||||
```
|
||||
|
||||
### 5. Results Formatted
|
||||
|
||||
Skill formats results and returns to Claude:
|
||||
|
||||
```
|
||||
## Recent Bugfixes
|
||||
|
||||
1. [bugfix] Fixed authentication token expiry
|
||||
Date: 2025-11-08 14:23:45
|
||||
Files: src/auth/jwt.ts
|
||||
|
||||
2. [bugfix] Resolved database connection leak
|
||||
Date: 2025-11-08 13:15:22
|
||||
Files: src/services/database.ts
|
||||
```
|
||||
|
||||
### 6. User Sees Answer
|
||||
|
||||
Claude presents the formatted results naturally in conversation.
|
||||
|
||||
## Architecture Change (v5.4.0)
|
||||
|
||||
### Before: MCP-Based Search
|
||||
|
||||
**Approach**: 9 MCP tools registered at session start
|
||||
|
||||
**Token Cost**: ~2,500 tokens in tool definitions per session
|
||||
- Each tool's schema, parameters, descriptions loaded
|
||||
- All 9 tools available whether needed or not
|
||||
- No progressive disclosure
|
||||
|
||||
**Example MCP Tool**:
|
||||
```json
|
||||
{
|
||||
"name": "search_observations",
|
||||
"description": "Full-text search across observations...",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": { "type": "string", "description": "..." },
|
||||
"type": { "type": "array", "items": { "enum": [...] } },
|
||||
"format": { "enum": ["index", "full"] },
|
||||
// ... many more parameters
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### After: Skill-Based Search
|
||||
|
||||
**Approach**: 1 mem-search skill with progressive disclosure
|
||||
|
||||
**Token Cost**: ~250 tokens in skill frontmatter per session
|
||||
- Only skill description loaded at session start
|
||||
- Full instructions loaded on-demand when skill is invoked
|
||||
- HTTP API endpoints instead of MCP protocol
|
||||
|
||||
**Example Skill Frontmatter**:
|
||||
```markdown
|
||||
# Claude-Mem mem-search Skill
|
||||
|
||||
Access claude-mem's persistent memory through a comprehensive HTTP API.
|
||||
Search for past work, understand context, and learn from previous decisions.
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Invoke this skill when users ask about:
|
||||
- Past work: "What did we do last session?"
|
||||
- Bug fixes: "Did we fix this before?"
|
||||
- Features: "How did we implement authentication?"
|
||||
...
|
||||
```
|
||||
|
||||
**Token Savings**: ~2,250 tokens per session start (90% reduction)
|
||||
|
||||
## HTTP API Endpoints
|
||||
|
||||
The worker service exposes 10 search endpoints:
|
||||
|
||||
### Full-Text Search
|
||||
|
||||
```
|
||||
GET /api/search/observations
|
||||
GET /api/search/sessions
|
||||
GET /api/search/prompts
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `query` - FTS5 search query (required)
|
||||
- `type` - Filter by type (bugfix, feature, refactor, etc.)
|
||||
- `project` - Filter by project name
|
||||
- `limit` - Maximum results (default: 20)
|
||||
- `offset` - Pagination offset
|
||||
- `format` - Response format (index or full)
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
curl "http://localhost:37777/api/search/observations?query=authentication&type=decision&limit=5"
|
||||
```
|
||||
|
||||
### Filtered Search
|
||||
|
||||
```
|
||||
GET /api/search/by-type
|
||||
GET /api/search/by-concept
|
||||
GET /api/search/by-file
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `type` / `concept` / `filePath` - Filter criteria (required)
|
||||
- `project` - Filter by project
|
||||
- `limit` - Maximum results
|
||||
- `format` - Response format
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
curl "http://localhost:37777/api/search/by-file?filePath=worker-service.ts&limit=10"
|
||||
```
|
||||
|
||||
### Context Retrieval
|
||||
|
||||
```
|
||||
GET /api/context/recent
|
||||
GET /api/context/timeline
|
||||
GET /api/timeline/by-query
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
- `project` - Filter by project
|
||||
- `limit` - Number of sessions/records
|
||||
- `anchor` - Timeline anchor point (ID or timestamp)
|
||||
- `depth_before` - Records before anchor
|
||||
- `depth_after` - Records after anchor
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
curl "http://localhost:37777/api/context/recent?project=claude-mem&limit=5"
|
||||
```
|
||||
|
||||
### Documentation
|
||||
|
||||
```
|
||||
GET /api/search/help
|
||||
```
|
||||
|
||||
Returns API documentation in JSON format.
|
||||
|
||||
## Progressive Disclosure Pattern
|
||||
|
||||
The mem-search skill uses progressive disclosure to minimize token usage:
|
||||
|
||||
### Layer 1: Skill Frontmatter (Session Start)
|
||||
|
||||
**What's Loaded**: Skill description and when to use it (~250 tokens)
|
||||
|
||||
**Purpose**: Claude can recognize when to invoke the skill
|
||||
|
||||
**Example**:
|
||||
```markdown
|
||||
# Claude-Mem mem-search Skill
|
||||
|
||||
Access claude-mem's persistent memory through a comprehensive HTTP API.
|
||||
|
||||
## When to Use This Skill
|
||||
Invoke this skill when users ask about:
|
||||
- Past work: "What did we do last session?"
|
||||
- Bug fixes: "Did we fix this before?"
|
||||
...
|
||||
```
|
||||
|
||||
### Layer 2: Full Skill Instructions (On-Demand)
|
||||
|
||||
**What's Loaded**: Complete operation documentation (~2,500 tokens)
|
||||
|
||||
**Purpose**: Detailed instructions for each search operation
|
||||
|
||||
**When Loaded**: Only when Claude invokes the skill
|
||||
|
||||
**Example Structure**:
|
||||
```
|
||||
/skills/search/
|
||||
├── SKILL.md (main frontmatter)
|
||||
├── operations/
|
||||
│ ├── observations.md (detailed instructions)
|
||||
│ ├── sessions.md
|
||||
│ ├── prompts.md
|
||||
│ ├── by-type.md
|
||||
│ ├── by-concept.md
|
||||
│ ├── by-file.md
|
||||
│ ├── recent-context.md
|
||||
│ ├── timeline.md
|
||||
│ ├── timeline-by-query.md
|
||||
│ ├── help.md
|
||||
│ ├── formatting.md
|
||||
│ └── common-workflows.md
|
||||
```
|
||||
|
||||
### Layer 3: API Response
|
||||
|
||||
**What's Returned**: Search results in requested format
|
||||
|
||||
**Format Options**:
|
||||
- `index` - Titles, dates, IDs only (~50-100 tokens per result)
|
||||
- `full` - Complete details (~500-1000 tokens per result)
|
||||
|
||||
**Progressive Usage**: Start with `index`, drill down with `full` as needed
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### mem-search Skill Structure
|
||||
|
||||
```
|
||||
plugin/skills/mem-search/
|
||||
├── SKILL.md # Main frontmatter (~250 tokens)
|
||||
├── operations/
|
||||
│ ├── observations.md # Search observations
|
||||
│ ├── sessions.md # Search sessions
|
||||
│ ├── prompts.md # Search prompts
|
||||
│ ├── by-type.md # Filter by type
|
||||
│ ├── by-concept.md # Filter by concept
|
||||
│ ├── by-file.md # Filter by file
|
||||
│ ├── recent-context.md # Get recent context
|
||||
│ ├── timeline.md # Timeline around point
|
||||
│ ├── timeline-by-query.md # Search + timeline
|
||||
│ ├── help.md # API documentation
|
||||
│ ├── formatting.md # Result formatting guide
|
||||
│ └── common-workflows.md # Usage patterns
|
||||
```
|
||||
|
||||
### Worker Service Integration
|
||||
|
||||
**File**: `src/services/worker-service.ts`
|
||||
|
||||
**Search Routes**:
|
||||
```typescript
|
||||
// Full-text search
|
||||
app.get('/api/search/observations', handleSearchObservations);
|
||||
app.get('/api/search/sessions', handleSearchSessions);
|
||||
app.get('/api/search/prompts', handleSearchPrompts);
|
||||
|
||||
// Filtered search
|
||||
app.get('/api/search/by-type', handleSearchByType);
|
||||
app.get('/api/search/by-concept', handleSearchByConcept);
|
||||
app.get('/api/search/by-file', handleSearchByFile);
|
||||
|
||||
// Context retrieval
|
||||
app.get('/api/context/recent', handleRecentContext);
|
||||
app.get('/api/context/timeline', handleTimeline);
|
||||
app.get('/api/timeline/by-query', handleTimelineByQuery);
|
||||
|
||||
// Documentation
|
||||
app.get('/api/search/help', handleHelp);
|
||||
```
|
||||
|
||||
**Database Access**:
|
||||
- Uses `SessionSearch` service for FTS5 queries
|
||||
- Uses `SessionStore` for structured queries
|
||||
- Hybrid search with ChromaDB for semantic similarity
|
||||
|
||||
### Security
|
||||
|
||||
**FTS5 Injection Prevention** (v4.2.3):
|
||||
```typescript
|
||||
function escapeFTS5Query(query: string): string {
|
||||
return query.replace(/"/g, '""');
|
||||
}
|
||||
```
|
||||
|
||||
All user-provided search queries are properly escaped to prevent SQL injection.
|
||||
|
||||
**Comprehensive Testing**: 332 injection attack tests covering:
|
||||
- Special characters
|
||||
- SQL keywords
|
||||
- Quote escaping
|
||||
- Boolean operators
|
||||
|
||||
## Benefits
|
||||
|
||||
### 1. Token Efficiency
|
||||
|
||||
**Before (MCP)**:
|
||||
- Session start: ~2,500 tokens for tool definitions
|
||||
- Every session pays this cost
|
||||
- No progressive disclosure
|
||||
|
||||
**After (Skill)**:
|
||||
- Session start: ~250 tokens for skill frontmatter
|
||||
- Full instructions: ~2,500 tokens (only when invoked)
|
||||
- Net savings: ~2,250 tokens per session (~90% reduction)
|
||||
|
||||
### 2. Natural Language Interface
|
||||
|
||||
**Before**: Users needed to learn MCP tool syntax
|
||||
```
|
||||
search_observations with query="authentication" and type="decision"
|
||||
```
|
||||
|
||||
**After**: Users ask naturally
|
||||
```
|
||||
"What decisions did we make about authentication?"
|
||||
```
|
||||
|
||||
Claude translates to appropriate API call.
|
||||
|
||||
### 3. Flexibility
|
||||
|
||||
**HTTP API Benefits**:
|
||||
- Can be called from skills, MCP tools, or other clients
|
||||
- Easy to test with curl
|
||||
- Standard REST conventions
|
||||
- JSON responses
|
||||
|
||||
**Progressive Disclosure**:
|
||||
- Loads only what's needed
|
||||
- Can add more operations without increasing base cost
|
||||
- Documentation co-located with operations
|
||||
|
||||
### 4. Performance
|
||||
|
||||
**Fast Queries**: FTS5 full-text search under 10ms for typical queries
|
||||
|
||||
**Caching**: HTTP layer allows response caching
|
||||
|
||||
**Pagination**: Efficient result pagination with offset/limit
|
||||
|
||||
## Migration Notes
|
||||
|
||||
### For Users
|
||||
|
||||
**No Action Required**: The migration from MCP to skill-based search is transparent.
|
||||
|
||||
**Same Questions Work**: Natural language queries work exactly the same way.
|
||||
|
||||
**Invisible Change**: Users won't notice any difference except better performance.
|
||||
|
||||
### For Developers
|
||||
|
||||
**Renamed**: MCP server (formerly `search-server.ts`, now `src/servers/mcp-server.ts`)
|
||||
- Source file kept for reference
|
||||
- No longer built or registered
|
||||
- MCP configuration removed from `plugin/.mcp.json`
|
||||
|
||||
**New Implementation**: Skill-based search
|
||||
- Skill files: `plugin/skills/mem-search/`
|
||||
- HTTP endpoints: `src/services/worker-service.ts` (lines 200-400)
|
||||
- Build script: `npm run build` includes skill files
|
||||
- Sync script: `npm run sync-marketplace` copies to plugin directory
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Worker Service Not Running
|
||||
|
||||
If searches fail, check worker service:
|
||||
|
||||
```bash
|
||||
npm run worker:status # Check status
|
||||
npm run worker:restart # Restart worker
|
||||
npm run worker:logs # View logs
|
||||
```
|
||||
|
||||
### HTTP Endpoints Not Responding
|
||||
|
||||
Test endpoints directly:
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl http://localhost:37777/health
|
||||
|
||||
# Search test
|
||||
curl "http://localhost:37777/api/search/observations?query=test&limit=1"
|
||||
```
|
||||
|
||||
### Skill Not Invoking
|
||||
|
||||
If Claude doesn't invoke the mem-search skill automatically:
|
||||
|
||||
1. Check skill files exist: `ls ~/.claude/plugins/marketplaces/thedotmack/plugin/skills/mem-search/`
|
||||
2. Restart Claude Code session to reload skill definitions
|
||||
3. Try more explicit phrasing: "Search past sessions for bug fixes" or "What did we do in yesterday's session?"
|
||||
4. Ensure your question is about previous sessions (not current conversation context)
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Search Tools Usage](/usage/search-tools) - User guide with examples
|
||||
- [Worker Service Architecture](/architecture/worker-service) - HTTP API details
|
||||
- [Database Schema](/architecture/database) - FTS5 tables and indexes
|
||||
@@ -0,0 +1,441 @@
|
||||
---
|
||||
title: "Worker Service"
|
||||
description: "HTTP API and Bun process management"
|
||||
---
|
||||
|
||||
# Worker Service
|
||||
|
||||
The worker service is a long-running HTTP API built with Express.js and managed natively by Bun. It processes observations through the Claude Agent SDK separately from hook execution to prevent timeout issues.
|
||||
|
||||
## Overview
|
||||
|
||||
- **Technology**: Express.js HTTP server
|
||||
- **Runtime**: Bun (auto-installed if missing)
|
||||
- **Process Manager**: Native Bun process management via ProcessManager
|
||||
- **Port**: Fixed port 37777 (configurable via `CLAUDE_MEM_WORKER_PORT`)
|
||||
- **Location**: `src/services/worker-service.ts`
|
||||
- **Built Output**: `plugin/scripts/worker-service.cjs`
|
||||
- **Model**: Configurable via `CLAUDE_MEM_MODEL` environment variable (default: sonnet)
|
||||
|
||||
## REST API Endpoints
|
||||
|
||||
The worker service exposes 14 HTTP endpoints organized into four categories:
|
||||
|
||||
### Viewer & Health Endpoints
|
||||
|
||||
#### 1. Viewer UI
|
||||
```
|
||||
GET /
|
||||
```
|
||||
|
||||
**Purpose**: Serves the web-based viewer UI (v5.1.0+)
|
||||
|
||||
**Response**: HTML page with embedded React application
|
||||
|
||||
**Features**:
|
||||
- Real-time memory stream visualization
|
||||
- Infinite scroll pagination
|
||||
- Project filtering
|
||||
- SSE-based live updates
|
||||
- Theme toggle (light/dark mode) as of v5.1.2
|
||||
|
||||
#### 2. Health Check
|
||||
```
|
||||
GET /health
|
||||
```
|
||||
|
||||
**Purpose**: Worker health status check
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"uptime": 12345,
|
||||
"port": 37777
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Server-Sent Events Stream
|
||||
```
|
||||
GET /stream
|
||||
```
|
||||
|
||||
**Purpose**: Real-time updates for viewer UI
|
||||
|
||||
**Response**: SSE stream with events:
|
||||
- `observation-created`: New observation added
|
||||
- `session-summary-created`: New summary generated
|
||||
- `user-prompt-created`: New prompt recorded
|
||||
|
||||
**Event Format**:
|
||||
```
|
||||
event: observation-created
|
||||
data: {"id": 123, "title": "...", ...}
|
||||
```
|
||||
|
||||
### Data Retrieval Endpoints
|
||||
|
||||
#### 4. Get Prompts
|
||||
```
|
||||
GET /api/prompts?project=my-project&limit=20&offset=0
|
||||
```
|
||||
|
||||
**Purpose**: Retrieve paginated user prompts
|
||||
|
||||
**Query Parameters**:
|
||||
- `project` (optional): Filter by project name
|
||||
- `limit` (default: 20): Number of results
|
||||
- `offset` (default: 0): Pagination offset
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"prompts": [{
|
||||
"id": 1,
|
||||
"session_id": "abc123",
|
||||
"prompt": "User's prompt text",
|
||||
"prompt_number": 1,
|
||||
"created_at": "2025-11-06T10:30:00Z"
|
||||
}],
|
||||
"total": 150,
|
||||
"hasMore": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 5. Get Observations
|
||||
```
|
||||
GET /api/observations?project=my-project&limit=20&offset=0
|
||||
```
|
||||
|
||||
**Purpose**: Retrieve paginated observations
|
||||
|
||||
**Query Parameters**:
|
||||
- `project` (optional): Filter by project name
|
||||
- `limit` (default: 20): Number of results
|
||||
- `offset` (default: 0): Pagination offset
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"observations": [{
|
||||
"id": 123,
|
||||
"title": "Fix authentication bug",
|
||||
"type": "bugfix",
|
||||
"narrative": "...",
|
||||
"created_at": "2025-11-06T10:30:00Z"
|
||||
}],
|
||||
"total": 500,
|
||||
"hasMore": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 6. Get Summaries
|
||||
```
|
||||
GET /api/summaries?project=my-project&limit=20&offset=0
|
||||
```
|
||||
|
||||
**Purpose**: Retrieve paginated session summaries
|
||||
|
||||
**Query Parameters**:
|
||||
- `project` (optional): Filter by project name
|
||||
- `limit` (default: 20): Number of results
|
||||
- `offset` (default: 0): Pagination offset
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"summaries": [{
|
||||
"id": 456,
|
||||
"session_id": "abc123",
|
||||
"request": "User's original request",
|
||||
"completed": "Work finished",
|
||||
"created_at": "2025-11-06T10:30:00Z"
|
||||
}],
|
||||
"total": 100,
|
||||
"hasMore": true
|
||||
}
|
||||
```
|
||||
|
||||
#### 7. Get Stats
|
||||
```
|
||||
GET /api/stats
|
||||
```
|
||||
|
||||
**Purpose**: Get database statistics by project
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"byProject": {
|
||||
"my-project": {
|
||||
"observations": 245,
|
||||
"summaries": 12,
|
||||
"prompts": 48
|
||||
},
|
||||
"other-project": {
|
||||
"observations": 156,
|
||||
"summaries": 8,
|
||||
"prompts": 32
|
||||
}
|
||||
},
|
||||
"total": {
|
||||
"observations": 401,
|
||||
"summaries": 20,
|
||||
"prompts": 80,
|
||||
"sessions": 20
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Settings Endpoints
|
||||
|
||||
#### 8. Get Settings
|
||||
```
|
||||
GET /api/settings
|
||||
```
|
||||
|
||||
**Purpose**: Retrieve user settings
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"sidebarOpen": true,
|
||||
"selectedProject": "my-project",
|
||||
"theme": "dark"
|
||||
}
|
||||
```
|
||||
|
||||
#### 9. Save Settings
|
||||
```
|
||||
POST /api/settings
|
||||
```
|
||||
|
||||
**Purpose**: Persist user settings
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"sidebarOpen": false,
|
||||
"selectedProject": "other-project",
|
||||
"theme": "light"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
### Session Management Endpoints
|
||||
|
||||
#### 10. Initialize Session
|
||||
```
|
||||
POST /sessions/:sessionDbId/init
|
||||
```
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"sdk_session_id": "abc-123",
|
||||
"project": "my-project"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"session_id": "abc-123"
|
||||
}
|
||||
```
|
||||
|
||||
#### 11. Add Observation
|
||||
```
|
||||
POST /sessions/:sessionDbId/observations
|
||||
```
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"tool_name": "Read",
|
||||
"tool_input": {...},
|
||||
"tool_result": "...",
|
||||
"correlation_id": "xyz-789"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"observation_id": 123
|
||||
}
|
||||
```
|
||||
|
||||
#### 12. Generate Summary
|
||||
```
|
||||
POST /sessions/:sessionDbId/summarize
|
||||
```
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
{
|
||||
"trigger": "stop"
|
||||
}
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"summary_id": 456
|
||||
}
|
||||
```
|
||||
|
||||
#### 13. Session Status
|
||||
```
|
||||
GET /sessions/:sessionDbId/status
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"session_id": "abc-123",
|
||||
"status": "active",
|
||||
"observation_count": 42,
|
||||
"summary_count": 1
|
||||
}
|
||||
```
|
||||
|
||||
#### 14. Delete Session
|
||||
```
|
||||
DELETE /sessions/:sessionDbId
|
||||
```
|
||||
|
||||
**Response**:
|
||||
```json
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: As of v4.1.0, the cleanup hook no longer calls this endpoint. Sessions are marked complete instead of deleted to allow graceful worker shutdown.
|
||||
|
||||
## Bun Process Management
|
||||
|
||||
### Overview
|
||||
|
||||
The worker is managed by the native `ProcessManager` class which handles:
|
||||
- Process spawning with Bun runtime
|
||||
- PID file tracking at `~/.claude-mem/worker.pid`
|
||||
- Health checks with automatic retry
|
||||
- Graceful shutdown with SIGTERM/SIGKILL fallback
|
||||
|
||||
### Commands
|
||||
|
||||
```bash
|
||||
# Start worker (auto-starts on first session)
|
||||
npm run worker:start
|
||||
|
||||
# Stop worker
|
||||
npm run worker:stop
|
||||
|
||||
# Restart worker
|
||||
npm run worker:restart
|
||||
|
||||
# View logs
|
||||
npm run worker:logs
|
||||
|
||||
# Check status
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
### Auto-Start Behavior
|
||||
|
||||
The worker service auto-starts when the SessionStart hook fires. Manual start is optional.
|
||||
|
||||
### Bun Requirement
|
||||
|
||||
Bun is required to run the worker service. If Bun is not installed, the smart-install script will automatically install it on first run:
|
||||
|
||||
- **Windows**: `powershell -c "irm bun.sh/install.ps1 | iex"`
|
||||
- **macOS/Linux**: `curl -fsSL https://bun.sh/install | bash`
|
||||
|
||||
You can also install manually via:
|
||||
- `winget install Oven-sh.Bun` (Windows)
|
||||
- `brew install oven-sh/bun/bun` (macOS)
|
||||
|
||||
## Claude Agent SDK Integration
|
||||
|
||||
The worker service routes observations to the Claude Agent SDK for AI-powered processing:
|
||||
|
||||
### Processing Flow
|
||||
|
||||
1. **Observation Queue**: Observations accumulate in memory
|
||||
2. **SDK Processing**: Observations sent to Claude via Agent SDK
|
||||
3. **XML Parsing**: Responses parsed for structured data
|
||||
4. **Database Storage**: Processed observations stored in SQLite
|
||||
|
||||
### SDK Components
|
||||
|
||||
- **Prompts** (`src/sdk/prompts.ts`): Builds XML-structured prompts
|
||||
- **Parser** (`src/sdk/parser.ts`): Parses Claude's XML responses
|
||||
- **Worker** (`src/sdk/worker.ts`): Main SDK agent loop
|
||||
|
||||
### Model Configuration
|
||||
|
||||
Set the AI model used for processing via environment variable:
|
||||
|
||||
```bash
|
||||
export CLAUDE_MEM_MODEL=sonnet
|
||||
```
|
||||
|
||||
Available shorthand models (forward to latest version):
|
||||
- `haiku` - Fast, cost-efficient
|
||||
- `sonnet` - Balanced (default)
|
||||
- `opus` - Most capable
|
||||
|
||||
## Port Allocation
|
||||
|
||||
The worker uses a fixed port (37777 by default) for consistent communication:
|
||||
|
||||
- **Default**: Port 37777
|
||||
- **Override**: Set `CLAUDE_MEM_WORKER_PORT` environment variable
|
||||
- **Port File**: `${CLAUDE_PLUGIN_ROOT}/data/worker.port` tracks current port
|
||||
|
||||
If port 37777 is in use, the worker will fail to start. Set a custom port via environment variable.
|
||||
|
||||
## Data Storage
|
||||
|
||||
The worker service stores data in the user data directory:
|
||||
|
||||
```
|
||||
~/.claude-mem/
|
||||
├── claude-mem.db # SQLite database (bun:sqlite)
|
||||
├── worker.pid # PID file for process tracking
|
||||
├── settings.json # User settings
|
||||
└── logs/
|
||||
└── worker-YYYY-MM-DD.log # Daily rotating logs
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The worker implements graceful degradation:
|
||||
|
||||
- **Database Errors**: Logged but don't crash the service
|
||||
- **SDK Errors**: Retried with exponential backoff
|
||||
- **Network Errors**: Logged and skipped
|
||||
- **Invalid Input**: Validated and rejected with error response
|
||||
|
||||
## Performance
|
||||
|
||||
- **Async Processing**: Observations processed asynchronously
|
||||
- **In-Memory Queue**: Fast observation accumulation
|
||||
- **Batch Processing**: Multiple observations processed together
|
||||
- **Connection Pooling**: SQLite connections reused
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
See [Troubleshooting - Worker Issues](../troubleshooting.md#worker-service-issues) for common problems and solutions.
|
||||
@@ -0,0 +1,144 @@
|
||||
---
|
||||
title: "Beta Features"
|
||||
description: "Try experimental features like Endless Mode before they're released"
|
||||
---
|
||||
|
||||
# Beta Features
|
||||
|
||||
Claude-Mem offers a beta channel for users who want to try experimental features before they're released to the stable channel.
|
||||
|
||||
## Version Channel Switching
|
||||
|
||||
You can switch between stable and beta versions directly from the web viewer UI at http://localhost:37777.
|
||||
|
||||
### How to Access
|
||||
|
||||
1. Open the Claude-Mem viewer at http://localhost:37777
|
||||
2. Click the **Settings** gear icon in the top-right
|
||||
3. Find the **Version Channel** section
|
||||
4. Click **Try Beta (Endless Mode)** to switch to beta, or **Switch to Stable** to return
|
||||
|
||||
### What Happens When You Switch
|
||||
|
||||
When switching versions:
|
||||
|
||||
1. **Local changes are discarded** - Any modifications in the plugin directory are reset
|
||||
2. **Git fetch and checkout** - The installed plugin switches to the target branch
|
||||
3. **Dependencies reinstall** - `npm install` runs to ensure correct dependencies
|
||||
4. **Worker restarts automatically** - The background service restarts with the new version
|
||||
|
||||
**Your memory data is always preserved.** The database at `~/.claude-mem/claude-mem.db` is not affected by version switching. All your observations, sessions, and summaries remain intact.
|
||||
|
||||
### Version Indicators
|
||||
|
||||
The Version Channel section shows your current status:
|
||||
|
||||
- **Stable** (green badge) - You're running the production release
|
||||
- **Beta** (orange badge) - You're running the beta with experimental features
|
||||
|
||||
You'll also see the exact branch name (e.g., `main` for stable, `beta/7.0` for beta).
|
||||
|
||||
## Endless Mode (Beta)
|
||||
|
||||
The flagship experimental feature in beta is **Endless Mode** - a biomimetic memory architecture that dramatically extends how long Claude can maintain context in a session.
|
||||
|
||||
### The Problem Endless Mode Solves
|
||||
|
||||
In standard Claude Code sessions:
|
||||
|
||||
- Tool outputs (file reads, bash output, search results) accumulate in the context window
|
||||
- Each tool can add 1-10k+ tokens to the context
|
||||
- After ~50 tool uses, the context window fills up (~200k tokens)
|
||||
- You're forced to start a new session, losing conversational continuity
|
||||
|
||||
Worse, Claude **re-synthesizes all previous tool outputs** on every response. This is O(N²) complexity - quadratically growing both in tokens and compute.
|
||||
|
||||
### How Endless Mode Works
|
||||
|
||||
Endless Mode applies a biomimetic memory architecture inspired by how human memory works:
|
||||
|
||||
**Two-Tier Memory System:**
|
||||
|
||||
```
|
||||
Working Memory (Context Window):
|
||||
→ Compressed observations only (~500 tokens each)
|
||||
→ Fast, efficient, manageable
|
||||
|
||||
Archive Memory (Transcript File):
|
||||
→ Full tool outputs preserved on disk
|
||||
→ Perfect recall, searchable
|
||||
```
|
||||
|
||||
**The Key Innovation**: After each tool use, Endless Mode:
|
||||
1. Waits for the worker to generate a compressed observation (blocking)
|
||||
2. Transforms the transcript file on disk
|
||||
3. Replaces the full tool output with the compressed observation
|
||||
4. Claude resumes with the compressed context
|
||||
|
||||
This transforms O(N²) scaling into O(N) - linear instead of quadratic.
|
||||
|
||||
### Expected Results
|
||||
|
||||
Based on analysis of real sessions:
|
||||
|
||||
- **Token savings**: ~95% reduction in context window usage
|
||||
- **Efficiency gain**: ~20x more tool uses before context exhaustion
|
||||
- **Quality preservation**: Observations cache the synthesis result, so no information is lost
|
||||
|
||||
### Caveats
|
||||
|
||||
Endless Mode is experimental:
|
||||
|
||||
- **Adds latency** - Blocking hooks wait for observation generation (60-90s per tool use)
|
||||
- **Requires working database** - Observations must save successfully for transformation
|
||||
- **New architecture** - Less battle-tested than standard mode
|
||||
|
||||
### When to Use Beta
|
||||
|
||||
Consider switching to beta if you:
|
||||
|
||||
- Frequently hit context window limits
|
||||
- Work on long, complex sessions with many tool uses
|
||||
- Want to help test and provide feedback on new features
|
||||
- Are comfortable with experimental software
|
||||
|
||||
### When to Stay on Stable
|
||||
|
||||
Stay on stable if you:
|
||||
|
||||
- Need maximum reliability for critical work
|
||||
- Prefer battle-tested, production-ready features
|
||||
- Don't frequently hit context limits
|
||||
- Want the smoothest, fastest experience
|
||||
|
||||
## Checking for Updates
|
||||
|
||||
While on beta (or stable), you can check for updates:
|
||||
|
||||
1. Open Settings in the viewer
|
||||
2. In the Version Channel section, click **Check for Updates**
|
||||
3. The plugin will pull the latest changes and restart
|
||||
|
||||
## Switching Back
|
||||
|
||||
If you encounter issues on beta:
|
||||
|
||||
1. Open Settings in the viewer
|
||||
2. Click **Switch to Stable**
|
||||
3. Wait for the worker to restart
|
||||
|
||||
Your memory data is preserved, and you'll be back on the stable release.
|
||||
|
||||
## Providing Feedback
|
||||
|
||||
If you encounter bugs or have feedback about beta features:
|
||||
|
||||
- Open an issue at [GitHub Issues](https://github.com/thedotmack/claude-mem/issues)
|
||||
- Include your branch (`beta/7.0` etc.) in the report
|
||||
- Describe what you expected vs. what happened
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Configuration](configuration) - Customize other Claude-Mem settings
|
||||
- [Troubleshooting](troubleshooting) - Common issues and solutions
|
||||
- [Architecture Overview](architecture/overview) - Understand how Claude-Mem works
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 MiB |
@@ -0,0 +1,453 @@
|
||||
---
|
||||
title: "Configuration"
|
||||
description: "Environment variables and settings for Claude-Mem"
|
||||
---
|
||||
|
||||
# Configuration
|
||||
|
||||
## Settings File
|
||||
|
||||
Settings are managed in `~/.claude-mem/settings.json`. The file is auto-created with defaults on first run.
|
||||
|
||||
### Core Settings
|
||||
|
||||
| Setting | Default | Description |
|
||||
|-------------------------------|---------------------------------|---------------------------------------|
|
||||
| `CLAUDE_MEM_MODEL` | `haiku` | AI model for processing observations |
|
||||
| `CLAUDE_MEM_CONTEXT_OBSERVATIONS` | `50` | Number of observations to inject |
|
||||
| `CLAUDE_MEM_WORKER_PORT` | `37777` | Worker service port |
|
||||
| `CLAUDE_MEM_SKIP_TOOLS` | `ListMcpResourcesTool,SlashCommand,Skill,TodoWrite,AskUserQuestion` | Comma-separated tools to exclude from observations |
|
||||
|
||||
### System Configuration
|
||||
|
||||
| Setting | Default | Description |
|
||||
|-------------------------------|---------------------------------|---------------------------------------|
|
||||
| `CLAUDE_MEM_DATA_DIR` | `~/.claude-mem` | Data directory location |
|
||||
| `CLAUDE_MEM_LOG_LEVEL` | `INFO` | Log verbosity (DEBUG, INFO, WARN, ERROR, SILENT) |
|
||||
| `CLAUDE_MEM_PYTHON_VERSION` | `3.13` | Python version for chroma-mcp |
|
||||
| `CLAUDE_CODE_PATH` | _(auto-detect)_ | Path to Claude Code CLI (for Windows) |
|
||||
|
||||
## Model Configuration
|
||||
|
||||
Configure which AI model processes your observations.
|
||||
|
||||
### Available Models
|
||||
|
||||
Shorthand model names automatically forward to the latest version:
|
||||
|
||||
- `haiku` - Fast, cost-efficient (default)
|
||||
- `sonnet` - Balanced
|
||||
- `opus` - Most capable
|
||||
|
||||
### Using the Interactive Script
|
||||
|
||||
```bash
|
||||
./claude-mem-settings.sh
|
||||
```
|
||||
|
||||
This script manages settings in `~/.claude-mem/settings.json`.
|
||||
|
||||
### Manual Configuration
|
||||
|
||||
Edit `~/.claude-mem/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_MODEL": "haiku"
|
||||
}
|
||||
```
|
||||
|
||||
## Files and Directories
|
||||
|
||||
### Data Directory Structure
|
||||
|
||||
The data directory location depends on the environment:
|
||||
- **Production (installed plugin)**: `~/.claude-mem/` (always, regardless of CLAUDE_PLUGIN_ROOT)
|
||||
- **Development**: Can be overridden with `CLAUDE_MEM_DATA_DIR`
|
||||
|
||||
```
|
||||
~/.claude-mem/
|
||||
├── claude-mem.db # SQLite database
|
||||
├── .install-version # Cached version for smart installer
|
||||
├── worker.port # Current worker port file
|
||||
└── logs/
|
||||
├── worker-out.log # Worker stdout logs
|
||||
└── worker-error.log # Worker stderr logs
|
||||
```
|
||||
|
||||
### Plugin Directory Structure
|
||||
|
||||
```
|
||||
${CLAUDE_PLUGIN_ROOT}/
|
||||
├── .claude-plugin/
|
||||
│ └── plugin.json # Plugin metadata
|
||||
├── .mcp.json # MCP server configuration
|
||||
├── hooks/
|
||||
│ └── hooks.json # Hook configuration
|
||||
├── scripts/ # Built executables
|
||||
│ ├── smart-install.js # Smart installer script
|
||||
│ ├── context-hook.js # Context injection hook
|
||||
│ ├── new-hook.js # Session creation hook
|
||||
│ ├── save-hook.js # Observation capture hook
|
||||
│ ├── summary-hook.js # Summary generation hook
|
||||
│ ├── cleanup-hook.js # Session cleanup hook
|
||||
│ ├── worker-service.cjs # Worker service (CJS)
|
||||
│ └── mcp-server.cjs # MCP search server (CJS)
|
||||
└── ui/
|
||||
└── viewer.html # Web viewer UI bundle
|
||||
```
|
||||
|
||||
## Plugin Configuration
|
||||
|
||||
### Hooks Configuration
|
||||
|
||||
Hooks are configured in `plugin/hooks/hooks.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"description": "Claude-mem memory system hooks",
|
||||
"hooks": {
|
||||
"SessionStart": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/smart-install.js && node ${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}],
|
||||
"UserPromptSubmit": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/new-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}],
|
||||
"PostToolUse": [{
|
||||
"matcher": "*",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}],
|
||||
"Stop": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/summary-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}],
|
||||
"SessionEnd": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Search Configuration (v5.4.0+)
|
||||
|
||||
**Migration Note**: As of v5.4.0, Claude-Mem uses skill-based search instead of MCP tools. As of v5.5.0, the skill was renamed to "mem-search" for better scope differentiation.
|
||||
|
||||
**Previous (v5.3.x and earlier)**: MCP search server with 9 tools (~2,500 tokens per session)
|
||||
**Current (v5.4.0+)**: mem-search skill with HTTP API (~250 tokens per session)
|
||||
|
||||
**No configuration required** - the mem-search skill is automatically available in Claude Code sessions.
|
||||
|
||||
Search operations are now provided via:
|
||||
- **Skill**: `plugin/skills/mem-search/SKILL.md` (auto-invoked when users ask about past work)
|
||||
- **HTTP API**: 10 endpoints on worker service port 37777
|
||||
- **Progressive Disclosure**: Full instructions loaded on-demand only when needed
|
||||
|
||||
## Version Channel
|
||||
|
||||
Claude-Mem supports switching between stable and beta versions via the web viewer UI.
|
||||
|
||||
### Accessing Version Channel
|
||||
|
||||
1. Open the viewer at http://localhost:37777
|
||||
2. Click the Settings gear icon
|
||||
3. Find the **Version Channel** section
|
||||
|
||||
### Switching Versions
|
||||
|
||||
- **Try Beta**: Click "Try Beta (Endless Mode)" to switch to the beta branch with experimental features
|
||||
- **Switch to Stable**: Click "Switch to Stable" to return to the production release
|
||||
- **Check for Updates**: Pull the latest changes for your current branch
|
||||
|
||||
**Your memory data is preserved** when switching versions. Only the plugin code changes.
|
||||
|
||||
See [Beta Features](beta-features) for details on what's available in beta.
|
||||
|
||||
## Worker Service Management
|
||||
|
||||
Worker service is managed by Bun as a background process. The worker auto-starts on first session and runs continuously in the background.
|
||||
|
||||
## Context Injection Configuration
|
||||
|
||||
Claude-Mem injects past observations into each new session, giving Claude awareness of recent work. You can configure exactly what gets injected using the **Context Settings Modal**.
|
||||
|
||||
### Context Settings Modal
|
||||
|
||||
Access the settings modal from the web viewer at http://localhost:37777:
|
||||
|
||||
1. Click the **gear icon** in the header
|
||||
2. Adjust settings in the right panel
|
||||
3. See changes reflected live in the **Terminal Preview** on the left
|
||||
4. Settings auto-save as you change them
|
||||
|
||||
The Terminal Preview shows exactly what will be injected at the start of your next Claude Code session for the selected project.
|
||||
|
||||
### Loading Settings
|
||||
|
||||
Control how many observations are injected:
|
||||
|
||||
| Setting | Default | Range | Description |
|
||||
|---------|---------|-------|-------------|
|
||||
| **Observations** | 50 | 1-200 | Total number of recent observations to include |
|
||||
| **Sessions** | 10 | 1-50 | Number of recent sessions to pull observations from |
|
||||
|
||||
**Considerations**:
|
||||
- **Higher values** = More context but slower SessionStart and more tokens used
|
||||
- **Lower values** = Faster SessionStart but less historical awareness
|
||||
- Default of 50 observations from 10 sessions balances context richness with performance
|
||||
|
||||
### Filter Settings
|
||||
|
||||
Control which observation types and concepts are included:
|
||||
|
||||
**Types** (select any combination):
|
||||
- `bugfix` - Bug fixes and error resolutions
|
||||
- `feature` - New functionality additions
|
||||
- `refactor` - Code restructuring
|
||||
- `discovery` - Learnings about how code works
|
||||
- `decision` - Architectural or design decisions
|
||||
- `change` - General code changes
|
||||
|
||||
**Concepts** (select any combination):
|
||||
- `how-it-works` - System behavior explanations
|
||||
- `why-it-exists` - Rationale for code/design
|
||||
- `what-changed` - Change summaries
|
||||
- `problem-solution` - Problem/solution pairs
|
||||
- `gotcha` - Edge cases and pitfalls
|
||||
- `pattern` - Recurring patterns
|
||||
- `trade-off` - Design trade-offs
|
||||
|
||||
Use "All" or "None" buttons to quickly select/deselect all options.
|
||||
|
||||
### Display Settings
|
||||
|
||||
Control how observations appear in the context:
|
||||
|
||||
**Full Observations**:
|
||||
| Setting | Default | Options | Description |
|
||||
|---------|---------|---------|-------------|
|
||||
| **Count** | 5 | 0-20 | How many observations show expanded details |
|
||||
| **Field** | narrative | narrative, facts | Which field to expand |
|
||||
|
||||
The most recent N observations (set by Count) show their full narrative or facts. Remaining observations show only title, type, and token counts in a compact table format.
|
||||
|
||||
**Token Economics** (toggles):
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| **Read cost** | true | Show tokens to read each observation |
|
||||
| **Work investment** | true | Show tokens spent creating the observation |
|
||||
| **Savings** | true | Show total tokens saved by reusing context |
|
||||
|
||||
Token economics help you understand the value of cached observations vs. re-reading files.
|
||||
|
||||
### Advanced Settings
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---------|---------|-------------|
|
||||
| **Model** | haiku | AI model for generating observations |
|
||||
| **Worker Port** | 37777 | Port for background worker service |
|
||||
| **MCP search server** | true | Enable Model Context Protocol search tools |
|
||||
| **Include last summary** | false | Add previous session's summary to context |
|
||||
| **Include last message** | false | Add previous session's final message |
|
||||
|
||||
### Manual Configuration
|
||||
|
||||
Settings are stored in `~/.claude-mem/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_CONTEXT_OBSERVATIONS": "100",
|
||||
"CLAUDE_MEM_CONTEXT_SESSION_COUNT": "20",
|
||||
"CLAUDE_MEM_CONTEXT_OBSERVATION_TYPES": "bugfix,decision,discovery",
|
||||
"CLAUDE_MEM_CONTEXT_OBSERVATION_CONCEPTS": "how-it-works,gotcha",
|
||||
"CLAUDE_MEM_CONTEXT_FULL_COUNT": "10",
|
||||
"CLAUDE_MEM_CONTEXT_FULL_FIELD": "narrative",
|
||||
"CLAUDE_MEM_CONTEXT_SHOW_READ_TOKENS": "true",
|
||||
"CLAUDE_MEM_CONTEXT_SHOW_WORK_TOKENS": "true",
|
||||
"CLAUDE_MEM_CONTEXT_SHOW_SAVINGS_AMOUNT": "true",
|
||||
"CLAUDE_MEM_CONTEXT_SHOW_LAST_SUMMARY": "false",
|
||||
"CLAUDE_MEM_CONTEXT_SHOW_LAST_MESSAGE": "false"
|
||||
}
|
||||
```
|
||||
|
||||
**Note**: The Context Settings Modal (at http://localhost:37777) is the recommended way to configure these settings, as it provides live preview of changes.
|
||||
|
||||
## Customization
|
||||
|
||||
Settings can be customized in `~/.claude-mem/settings.json`.
|
||||
|
||||
### Custom Data Directory
|
||||
|
||||
Edit `~/.claude-mem/settings.json`:
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_DATA_DIR": "/custom/path"
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Worker Port
|
||||
|
||||
Edit `~/.claude-mem/settings.json`:
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_WORKER_PORT": "38000"
|
||||
}
|
||||
```
|
||||
|
||||
Then restart the worker:
|
||||
```bash
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
### Custom Model
|
||||
|
||||
Edit `~/.claude-mem/settings.json`:
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_MODEL": "opus"
|
||||
}
|
||||
```
|
||||
|
||||
Then restart the worker:
|
||||
```bash
|
||||
export CLAUDE_MEM_MODEL=opus
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
### Custom Skip Tools
|
||||
|
||||
Control which tools are excluded from observations. Edit `~/.claude-mem/settings.json`:
|
||||
```json
|
||||
{
|
||||
"CLAUDE_MEM_SKIP_TOOLS": "ListMcpResourcesTool,SlashCommand,Skill"
|
||||
}
|
||||
```
|
||||
|
||||
**Default excluded tools:**
|
||||
- `ListMcpResourcesTool`
|
||||
- `SlashCommand`
|
||||
- `Skill`
|
||||
- `TodoWrite`
|
||||
- `AskUserQuestion`
|
||||
|
||||
**Common customizations:**
|
||||
- Include TodoWrite: Remove from skip list to track task planning
|
||||
- Include AskUserQuestion: Remove to capture decision-making conversations
|
||||
- Skip additional tools: Add tool names to reduce observation noise
|
||||
|
||||
Changes take effect on the next tool execution (no worker restart needed).
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Hook Timeouts
|
||||
|
||||
Modify timeouts in `plugin/hooks/hooks.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"timeout": 120 // Default: 120 seconds
|
||||
}
|
||||
```
|
||||
|
||||
Recommended values:
|
||||
- SessionStart: 120s (needs time for smart install check and context retrieval)
|
||||
- UserPromptSubmit: 60s
|
||||
- PostToolUse: 120s (can process many observations)
|
||||
- Stop: 60s
|
||||
- SessionEnd: 60s
|
||||
|
||||
**Note**: With smart install caching (v5.0.3+), SessionStart is typically very fast (10ms) unless dependencies need installation.
|
||||
|
||||
### Worker Memory Limit
|
||||
|
||||
The worker service is managed by Bun and will automatically restart if it encounters issues. Memory usage is typically low (~100-200MB).
|
||||
|
||||
### Logging Verbosity
|
||||
|
||||
Enable debug logging:
|
||||
|
||||
```bash
|
||||
export DEBUG=claude-mem:*
|
||||
npm run worker:restart
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
## Configuration Best Practices
|
||||
|
||||
1. **Use defaults**: Default configuration works for most use cases
|
||||
2. **Override selectively**: Only change what you need
|
||||
3. **Document changes**: Keep track of custom configurations
|
||||
4. **Test after changes**: Verify worker restarts successfully
|
||||
5. **Monitor logs**: Check worker logs after configuration changes
|
||||
|
||||
## Troubleshooting Configuration
|
||||
|
||||
### Configuration Not Applied
|
||||
|
||||
1. Restart worker after changes:
|
||||
```bash
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
2. Verify environment variables:
|
||||
```bash
|
||||
echo $CLAUDE_MEM_MODEL
|
||||
echo $CLAUDE_MEM_WORKER_PORT
|
||||
```
|
||||
|
||||
3. Check worker logs:
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
### Invalid Model Name
|
||||
|
||||
If you specify an invalid model name, the worker will fall back to `haiku` and log a warning.
|
||||
|
||||
Valid shorthand models (forward to latest version):
|
||||
- haiku
|
||||
- sonnet
|
||||
- opus
|
||||
|
||||
### Port Already in Use
|
||||
|
||||
If port 37777 is already in use:
|
||||
|
||||
1. Set custom port:
|
||||
```bash
|
||||
export CLAUDE_MEM_WORKER_PORT=38000
|
||||
```
|
||||
|
||||
2. Restart worker:
|
||||
```bash
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
3. Verify new port:
|
||||
```bash
|
||||
cat ~/.claude-mem/worker.port
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Architecture Overview](architecture/overview) - Understand the system
|
||||
- [Troubleshooting](troubleshooting) - Common issues
|
||||
- [Development](development) - Building from source
|
||||
@@ -0,0 +1,227 @@
|
||||
---
|
||||
title: "Context Engineering"
|
||||
description: "Best practices for curating optimal token sets for AI agents"
|
||||
---
|
||||
|
||||
# Context Engineering for AI Agents
|
||||
|
||||
## Core Principle
|
||||
**Find the smallest possible set of high-signal tokens that maximize the likelihood of your desired outcome.**
|
||||
|
||||
---
|
||||
|
||||
## Context Engineering vs Prompt Engineering
|
||||
|
||||
**Prompt Engineering**: Writing and organizing LLM instructions for optimal outcomes (one-time task)
|
||||
|
||||
**Context Engineering**: Curating and maintaining the optimal set of tokens during inference across multiple turns (iterative process)
|
||||
|
||||
Context engineering manages:
|
||||
- System instructions
|
||||
- Tools
|
||||
- Model Context Protocol (MCP)
|
||||
- External data
|
||||
- Message history
|
||||
- Runtime data retrieval
|
||||
|
||||
---
|
||||
|
||||
## The Problem: Context Rot
|
||||
|
||||
**Key Insight**: LLMs have an "attention budget" that gets depleted as context grows
|
||||
|
||||
- Every token attends to every other token (n² relationships)
|
||||
- As context length increases, model accuracy decreases
|
||||
- Models have less training experience with longer sequences
|
||||
- Context must be treated as a finite resource with diminishing marginal returns
|
||||
|
||||
---
|
||||
|
||||
## System Prompts: Find the "Right Altitude"
|
||||
|
||||
### The Goldilocks Zone
|
||||
|
||||
**Too Prescriptive** ❌
|
||||
- Hardcoded if-else logic
|
||||
- Brittle and fragile
|
||||
- High maintenance complexity
|
||||
|
||||
**Too Vague** ❌
|
||||
- High-level guidance without concrete signals
|
||||
- Falsely assumes shared context
|
||||
- Lacks actionable direction
|
||||
|
||||
**Just Right** ✅
|
||||
- Specific enough to guide behavior effectively
|
||||
- Flexible enough to provide strong heuristics
|
||||
- Minimal set of information that fully outlines expected behavior
|
||||
|
||||
### Best Practices
|
||||
- Use simple, direct language
|
||||
- Organize into distinct sections (`<background_information>`, `<instructions>`, `## Tool guidance`, etc.)
|
||||
- Use XML tags or Markdown headers for structure
|
||||
- Start with minimal prompt, add based on failure modes
|
||||
- Note: Minimal ≠ short (provide sufficient information upfront)
|
||||
|
||||
---
|
||||
|
||||
## Tools: Minimal and Clear
|
||||
|
||||
### Design Principles
|
||||
- **Self-contained**: Each tool has a single, clear purpose
|
||||
- **Robust to error**: Handle edge cases gracefully
|
||||
- **Extremely clear**: Intended use is unambiguous
|
||||
- **Token-efficient**: Returns relevant information without bloat
|
||||
- **Descriptive parameters**: Unambiguous input names (e.g., `user_id` not `user`)
|
||||
|
||||
### Critical Rule
|
||||
**If a human engineer can't definitively say which tool to use in a given situation, an AI agent can't be expected to do better.**
|
||||
|
||||
### Common Failure Modes to Avoid
|
||||
- Bloated tool sets covering too much functionality
|
||||
- Tools with overlapping purposes
|
||||
- Ambiguous decision points about which tool to use
|
||||
|
||||
---
|
||||
|
||||
## Examples: Diverse, Not Exhaustive
|
||||
|
||||
**Do** ✅
|
||||
- Curate a set of diverse, canonical examples
|
||||
- Show expected behavior effectively
|
||||
- Think "pictures worth a thousand words"
|
||||
|
||||
**Don't** ❌
|
||||
- Stuff in a laundry list of edge cases
|
||||
- Try to articulate every possible rule
|
||||
- Overwhelm with exhaustive scenarios
|
||||
|
||||
---
|
||||
|
||||
## Context Retrieval Strategies
|
||||
|
||||
### Just-In-Time Context (Recommended for Agents)
|
||||
**Approach**: Maintain lightweight identifiers (file paths, queries, links) and dynamically load data at runtime
|
||||
|
||||
**Benefits**:
|
||||
- Avoids context pollution
|
||||
- Enables progressive disclosure
|
||||
- Mirrors human cognition (we don't memorize everything)
|
||||
- Leverages metadata (file names, folder structure, timestamps)
|
||||
- Agents discover context incrementally
|
||||
|
||||
**Trade-offs**:
|
||||
- Slower than pre-computed retrieval
|
||||
- Requires proper tool guidance to avoid dead-ends
|
||||
|
||||
### Pre-Inference Retrieval (Traditional RAG)
|
||||
**Approach**: Use embedding-based retrieval to surface context before inference
|
||||
|
||||
**When to Use**: Static content that won't change during interaction
|
||||
|
||||
### Hybrid Strategy (Best of Both)
|
||||
**Approach**: Retrieve some data upfront, enable autonomous exploration as needed
|
||||
|
||||
**Example**: Claude Code loads CLAUDE.md files upfront, uses glob/grep for just-in-time retrieval
|
||||
|
||||
**Rule of Thumb**: "Do the simplest thing that works"
|
||||
|
||||
---
|
||||
|
||||
## Long-Horizon Tasks: Three Techniques
|
||||
|
||||
### 1. Compaction
|
||||
**What**: Summarize conversation nearing context limit, reinitiate with summary
|
||||
|
||||
**Implementation**:
|
||||
- Pass message history to model for compression
|
||||
- Preserve critical details (architectural decisions, bugs, implementation)
|
||||
- Discard redundant outputs
|
||||
- Continue with compressed context + recently accessed files
|
||||
|
||||
**Tuning Process**:
|
||||
1. **First**: Maximize recall (capture all relevant information)
|
||||
2. **Then**: Improve precision (eliminate superfluous content)
|
||||
|
||||
**Low-Hanging Fruit**: Clear old tool calls and results
|
||||
|
||||
**Best For**: Tasks requiring extensive back-and-forth
|
||||
|
||||
### 2. Structured Note-Taking (Agentic Memory)
|
||||
**What**: Agent writes notes persisted outside context window, retrieved later
|
||||
|
||||
**Examples**:
|
||||
- To-do lists
|
||||
- NOTES.md files
|
||||
- Game state tracking (Pokémon example: tracking 1,234 steps of training)
|
||||
- Project progress logs
|
||||
|
||||
**Benefits**:
|
||||
- Persistent memory with minimal overhead
|
||||
- Maintains critical context across tool calls
|
||||
- Enables multi-hour coherent strategies
|
||||
|
||||
**Best For**: Iterative development with clear milestones
|
||||
|
||||
### 3. Sub-Agent Architectures
|
||||
**What**: Specialized sub-agents handle focused tasks with clean context windows
|
||||
|
||||
**How It Works**:
|
||||
- Main agent coordinates high-level plan
|
||||
- Sub-agents perform deep technical work
|
||||
- Sub-agents explore extensively (tens of thousands of tokens)
|
||||
- Return condensed summaries (1,000-2,000 tokens)
|
||||
|
||||
**Benefits**:
|
||||
- Clear separation of concerns
|
||||
- Parallel exploration
|
||||
- Detailed context remains isolated
|
||||
|
||||
**Best For**: Complex research and analysis tasks
|
||||
|
||||
---
|
||||
|
||||
## Quick Decision Framework
|
||||
|
||||
| Scenario | Recommended Approach |
|
||||
|----------|---------------------|
|
||||
| Static content | Pre-inference retrieval or hybrid |
|
||||
| Dynamic exploration needed | Just-in-time context |
|
||||
| Extended back-and-forth | Compaction |
|
||||
| Iterative development | Structured note-taking |
|
||||
| Complex research | Sub-agent architectures |
|
||||
| Rapid model improvement | "Do the simplest thing that works" |
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Context is finite**: Treat it as a precious resource with an attention budget
|
||||
2. **Think holistically**: Consider the entire state available to the LLM
|
||||
3. **Stay minimal**: More context isn't always better
|
||||
4. **Be iterative**: Context curation happens each time you pass to the model
|
||||
5. **Design for autonomy**: As models improve, let them act intelligently
|
||||
6. **Start simple**: Test with minimal setup, add based on failure modes
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
- ❌ Cramming everything into prompts
|
||||
- ❌ Creating brittle if-else logic
|
||||
- ❌ Building bloated tool sets
|
||||
- ❌ Stuffing exhaustive edge cases as examples
|
||||
- ❌ Assuming larger context windows solve everything
|
||||
- ❌ Ignoring context pollution over long interactions
|
||||
|
||||
---
|
||||
|
||||
## Remember
|
||||
|
||||
> "Even as models continue to improve, the challenge of maintaining coherence across extended interactions will remain central to building more effective agents."
|
||||
|
||||
Context engineering will evolve, but the core principle stays the same: **optimize signal-to-noise ratio in your token budget**.
|
||||
|
||||
---
|
||||
|
||||
*Based on Anthropic's "Effective context engineering for AI agents" (September 2025)*
|
||||
@@ -0,0 +1,671 @@
|
||||
---
|
||||
title: "Development"
|
||||
description: "Build from source, run tests, and contribute to Claude-Mem"
|
||||
---
|
||||
|
||||
# Development Guide
|
||||
|
||||
## Building from Source
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Node.js 18.0.0 or higher
|
||||
- npm (comes with Node.js)
|
||||
- Git
|
||||
|
||||
### Clone and Build
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/thedotmack/claude-mem.git
|
||||
cd claude-mem
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Build all components
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Build Process
|
||||
|
||||
The build process uses esbuild to compile TypeScript:
|
||||
|
||||
1. Compiles TypeScript to JavaScript
|
||||
2. Creates standalone executables for each hook in `plugin/scripts/`
|
||||
3. Bundles MCP search server to `plugin/scripts/mcp-server.cjs`
|
||||
4. Bundles worker service to `plugin/scripts/worker-service.cjs`
|
||||
5. Bundles web viewer UI to `plugin/ui/viewer.html`
|
||||
|
||||
**Build Output**:
|
||||
- Hook executables: `*-hook.js` (ESM format)
|
||||
- Smart installer: `smart-install.js` (ESM format)
|
||||
- Worker service: `worker-service.cjs` (CJS format)
|
||||
- MCP server: `mcp-server.cjs` (CJS format)
|
||||
- Viewer UI: `viewer.html` (self-contained HTML bundle)
|
||||
|
||||
### Build Scripts
|
||||
|
||||
```bash
|
||||
# Build everything
|
||||
npm run build
|
||||
|
||||
# Build only hooks
|
||||
npm run build:hooks
|
||||
|
||||
# The build script is defined in scripts/build-hooks.js
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### 1. Make Changes
|
||||
|
||||
Edit TypeScript source files in `src/`:
|
||||
|
||||
```
|
||||
src/
|
||||
├── hooks/ # Hook implementations (entry points + logic)
|
||||
├── services/ # Worker service and database
|
||||
├── servers/ # MCP search server
|
||||
├── sdk/ # Claude Agent SDK integration
|
||||
├── shared/ # Shared utilities
|
||||
├── ui/
|
||||
│ └── viewer/ # React web viewer UI components
|
||||
└── utils/ # General utilities
|
||||
```
|
||||
|
||||
### 2. Build
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### 3. Test
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
npm test
|
||||
|
||||
# Test specific file
|
||||
node --test tests/session-lifecycle.test.ts
|
||||
|
||||
# Test context injection
|
||||
npm run test:context
|
||||
|
||||
# Verbose context test
|
||||
npm run test:context:verbose
|
||||
```
|
||||
|
||||
### 4. Manual Testing
|
||||
|
||||
```bash
|
||||
# Start worker manually
|
||||
npm run worker:start
|
||||
|
||||
# Check worker status
|
||||
npm run worker:status
|
||||
|
||||
# View logs
|
||||
npm run worker:logs
|
||||
|
||||
# Test hooks manually
|
||||
echo '{"session_id":"test-123","cwd":"'$(pwd)'","source":"startup"}' | node plugin/scripts/context-hook.js
|
||||
```
|
||||
|
||||
### 5. Iterate
|
||||
|
||||
Repeat steps 1-4 until your changes work as expected.
|
||||
|
||||
## Viewer UI Development
|
||||
|
||||
### Working with the React Viewer
|
||||
|
||||
The web viewer UI is a React application built into a self-contained HTML bundle.
|
||||
|
||||
**Location**: `src/ui/viewer/`
|
||||
|
||||
**Structure**:
|
||||
```
|
||||
src/ui/viewer/
|
||||
├── index.tsx # Entry point
|
||||
├── App.tsx # Main application component
|
||||
├── components/ # React components
|
||||
│ ├── Header.tsx # Header with logo and actions
|
||||
│ ├── Sidebar.tsx # Project filter sidebar
|
||||
│ ├── Feed.tsx # Main feed with infinite scroll
|
||||
│ ├── cards/ # Card components
|
||||
│ │ ├── ObservationCard.tsx
|
||||
│ │ ├── PromptCard.tsx
|
||||
│ │ ├── SummaryCard.tsx
|
||||
│ │ └── SkeletonCard.tsx
|
||||
├── hooks/ # Custom React hooks
|
||||
│ ├── useSSE.ts # Server-Sent Events connection
|
||||
│ ├── usePagination.ts # Infinite scroll pagination
|
||||
│ ├── useSettings.ts # Settings persistence
|
||||
│ └── useStats.ts # Database statistics
|
||||
├── utils/ # Utilities
|
||||
│ ├── constants.ts # Constants (API URLs, etc.)
|
||||
│ ├── formatters.ts # Date/time formatting
|
||||
│ └── merge.ts # Data merging and deduplication
|
||||
└── assets/ # Static assets (fonts, logos)
|
||||
```
|
||||
|
||||
### Building Viewer UI
|
||||
|
||||
```bash
|
||||
# Build everything including viewer
|
||||
npm run build
|
||||
|
||||
# The viewer is built to plugin/ui/viewer.html
|
||||
# It's a self-contained HTML file with inlined JS and CSS
|
||||
```
|
||||
|
||||
### Testing Viewer Changes
|
||||
|
||||
1. Make changes to React components in `src/ui/viewer/`
|
||||
2. Build: `npm run build`
|
||||
3. Sync to installed plugin: `npm run sync-marketplace`
|
||||
4. Restart worker: `npm run worker:restart`
|
||||
5. Refresh browser at http://localhost:37777
|
||||
|
||||
**Hot Reload**: Not currently supported. Full rebuild + restart required for changes.
|
||||
|
||||
### Adding New Viewer Features
|
||||
|
||||
**Example: Adding a new card type**
|
||||
|
||||
1. Create component in `src/ui/viewer/components/cards/YourCard.tsx`:
|
||||
|
||||
```tsx
|
||||
import React from 'react';
|
||||
|
||||
export interface YourCardProps {
|
||||
// Your data structure
|
||||
}
|
||||
|
||||
export const YourCard: React.FC<YourCardProps> = ({ ... }) => {
|
||||
return (
|
||||
<div className="card">
|
||||
{/* Your UI */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
2. Import and use in `Feed.tsx`:
|
||||
|
||||
```tsx
|
||||
import { YourCard } from './cards/YourCard';
|
||||
|
||||
// In render logic:
|
||||
{item.type === 'your_type' && <YourCard {...item} />}
|
||||
```
|
||||
|
||||
3. Update types if needed in `src/ui/viewer/types.ts`
|
||||
|
||||
4. Rebuild and test
|
||||
|
||||
### Viewer UI Architecture
|
||||
|
||||
**Data Flow**:
|
||||
1. Worker service exposes HTTP + SSE endpoints
|
||||
2. React app fetches initial data via HTTP (paginated)
|
||||
3. SSE connection provides real-time updates
|
||||
4. Custom hooks handle state management and data merging
|
||||
5. Components render cards based on item type
|
||||
|
||||
**Key Patterns**:
|
||||
- **Infinite Scroll**: `usePagination` hook with Intersection Observer
|
||||
- **Real-Time Updates**: `useSSE` hook with auto-reconnection
|
||||
- **Deduplication**: `merge.ts` utilities prevent duplicate items
|
||||
- **Settings Persistence**: `useSettings` hook with localStorage
|
||||
- **Theme Support**: CSS variables with light/dark/system themes
|
||||
|
||||
## Adding New Features
|
||||
|
||||
### Adding a New Hook
|
||||
|
||||
1. Create hook implementation in `src/hooks/your-hook.ts`:
|
||||
|
||||
```typescript
|
||||
#!/usr/bin/env node
|
||||
import { readStdin } from '../shared/stdin';
|
||||
|
||||
async function main() {
|
||||
const input = await readStdin();
|
||||
|
||||
// Hook implementation
|
||||
const result = {
|
||||
hookSpecificOutput: 'Optional output'
|
||||
};
|
||||
|
||||
console.log(JSON.stringify(result));
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
```
|
||||
|
||||
**Note**: As of v4.3.1, hooks are self-contained files. The shebang will be added automatically by esbuild during the build process.
|
||||
|
||||
2. Add to `plugin/hooks/hooks.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"YourHook": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/your-hook.js",
|
||||
"timeout": 120
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
4. Rebuild:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Modifying Database Schema
|
||||
|
||||
1. Add migration to `src/services/sqlite/migrations.ts`:
|
||||
|
||||
```typescript
|
||||
export const migration011: Migration = {
|
||||
version: 11,
|
||||
up: (db: Database) => {
|
||||
db.run(`
|
||||
ALTER TABLE observations ADD COLUMN new_field TEXT;
|
||||
`);
|
||||
},
|
||||
down: (db: Database) => {
|
||||
// Optional: define rollback
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
2. Update types in `src/services/sqlite/types.ts`:
|
||||
|
||||
```typescript
|
||||
export interface Observation {
|
||||
// ... existing fields
|
||||
new_field?: string;
|
||||
}
|
||||
```
|
||||
|
||||
3. Update database methods in `src/services/sqlite/SessionStore.ts`:
|
||||
|
||||
```typescript
|
||||
createObservation(obs: Observation) {
|
||||
// Include new_field in INSERT
|
||||
}
|
||||
```
|
||||
|
||||
4. Test migration:
|
||||
|
||||
```bash
|
||||
# Backup database first!
|
||||
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup
|
||||
|
||||
# Run tests
|
||||
npm test
|
||||
```
|
||||
|
||||
### Extending SDK Prompts
|
||||
|
||||
1. Modify prompts in `src/sdk/prompts.ts`:
|
||||
|
||||
```typescript
|
||||
export function buildObservationPrompt(observation: Observation): string {
|
||||
return `
|
||||
<observation>
|
||||
<!-- Add new XML structure -->
|
||||
</observation>
|
||||
`;
|
||||
}
|
||||
```
|
||||
|
||||
2. Update parser in `src/sdk/parser.ts`:
|
||||
|
||||
```typescript
|
||||
export function parseObservation(xml: string): ParsedObservation {
|
||||
// Parse new XML fields
|
||||
}
|
||||
```
|
||||
|
||||
3. Test:
|
||||
|
||||
```bash
|
||||
npm test
|
||||
```
|
||||
|
||||
### Adding MCP Search Tools
|
||||
|
||||
1. Add tool definition in `src/servers/mcp-server.ts`:
|
||||
|
||||
```typescript
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
if (request.params.name === 'your_new_tool') {
|
||||
// Implement tool logic
|
||||
const results = await search.yourNewSearch(params);
|
||||
return formatResults(results);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
2. Add search method in `src/services/sqlite/SessionSearch.ts`:
|
||||
|
||||
```typescript
|
||||
yourNewSearch(params: YourParams): SearchResult[] {
|
||||
// Implement FTS5 search
|
||||
}
|
||||
```
|
||||
|
||||
3. Rebuild and test:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm test
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# All tests
|
||||
npm test
|
||||
|
||||
# Specific test file
|
||||
node --test tests/your-test.test.ts
|
||||
|
||||
# With coverage (if configured)
|
||||
npm test -- --coverage
|
||||
```
|
||||
|
||||
### Writing Tests
|
||||
|
||||
Create test files in `tests/`:
|
||||
|
||||
```typescript
|
||||
import { describe, it } from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
|
||||
describe('YourFeature', () => {
|
||||
it('should do something', () => {
|
||||
// Test implementation
|
||||
assert.strictEqual(result, expected);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Test Database
|
||||
|
||||
Use a separate test database:
|
||||
|
||||
```typescript
|
||||
import { SessionStore } from '../src/services/sqlite/SessionStore';
|
||||
|
||||
const store = new SessionStore(':memory:'); // In-memory database
|
||||
```
|
||||
|
||||
## Code Style
|
||||
|
||||
### TypeScript Guidelines
|
||||
|
||||
- Use TypeScript strict mode
|
||||
- Define interfaces for all data structures
|
||||
- Use async/await for asynchronous code
|
||||
- Handle errors explicitly
|
||||
- Add JSDoc comments for public APIs
|
||||
|
||||
### Formatting
|
||||
|
||||
- Follow existing code formatting
|
||||
- Use 2-space indentation
|
||||
- Use single quotes for strings
|
||||
- Add trailing commas in objects/arrays
|
||||
|
||||
### Example
|
||||
|
||||
```typescript
|
||||
/**
|
||||
* Create a new observation in the database
|
||||
*/
|
||||
export async function createObservation(
|
||||
obs: Observation
|
||||
): Promise<number> {
|
||||
try {
|
||||
const result = await db.insert('observations', {
|
||||
session_id: obs.session_id,
|
||||
tool_name: obs.tool_name,
|
||||
// ...
|
||||
});
|
||||
return result.id;
|
||||
} catch (error) {
|
||||
logger.error('Failed to create observation', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Debug Logging
|
||||
|
||||
```bash
|
||||
export DEBUG=claude-mem:*
|
||||
npm run worker:restart
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
### Inspect Database
|
||||
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db
|
||||
|
||||
# View schema
|
||||
.schema observations
|
||||
|
||||
# Query data
|
||||
SELECT * FROM observations LIMIT 10;
|
||||
```
|
||||
|
||||
### Trace Observations
|
||||
|
||||
Use correlation IDs to trace observations through the pipeline:
|
||||
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db
|
||||
SELECT correlation_id, tool_name, created_at
|
||||
FROM observations
|
||||
WHERE session_id = 'YOUR_SESSION_ID'
|
||||
ORDER BY created_at;
|
||||
```
|
||||
|
||||
### Debug Hooks
|
||||
|
||||
Run hooks manually with test input:
|
||||
|
||||
```bash
|
||||
# Test context hook
|
||||
echo '{"session_id":"test-123","cwd":"'$(pwd)'","source":"startup"}' | node plugin/scripts/context-hook.js
|
||||
|
||||
# Test new hook
|
||||
echo '{"session_id":"test-123","cwd":"'$(pwd)'","prompt":"test"}' | node plugin/scripts/new-hook.js
|
||||
```
|
||||
|
||||
## Publishing
|
||||
|
||||
### NPM Publishing
|
||||
|
||||
```bash
|
||||
# Update version in package.json
|
||||
npm version patch # or minor, or major
|
||||
|
||||
# Build
|
||||
npm run build
|
||||
|
||||
# Publish to NPM
|
||||
npm run release
|
||||
```
|
||||
|
||||
The `release` script:
|
||||
1. Runs tests
|
||||
2. Builds all components
|
||||
3. Publishes to NPM registry
|
||||
|
||||
### Creating a Release
|
||||
|
||||
1. Update version in `package.json`
|
||||
2. Update `CHANGELOG.md`
|
||||
3. Commit changes
|
||||
4. Create git tag
|
||||
5. Push to GitHub
|
||||
6. Publish to NPM
|
||||
|
||||
```bash
|
||||
# Manual version bump:
|
||||
# 1. Update version in package.json
|
||||
# 2. Update version in plugin/.claude-plugin/plugin.json
|
||||
# 3. Update version at top of CLAUDE.md
|
||||
# 4. Update version badge in README.md
|
||||
# 5. Run: npm run build && npm run sync-marketplace
|
||||
|
||||
# Or use npm version command:
|
||||
npm version 4.3.2
|
||||
|
||||
# Update changelog
|
||||
# Edit CHANGELOG.md manually
|
||||
|
||||
# Commit
|
||||
git add .
|
||||
git commit -m "chore: Release v4.3.2"
|
||||
|
||||
# Tag
|
||||
git tag v4.3.2
|
||||
|
||||
# Push
|
||||
git push origin main --tags
|
||||
|
||||
# Publish to NPM
|
||||
npm run release
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
### Contribution Workflow
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Make your changes
|
||||
4. Write tests
|
||||
5. Update documentation
|
||||
6. Commit your changes (`git commit -m 'Add amazing feature'`)
|
||||
7. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
8. Open a Pull Request
|
||||
|
||||
### Pull Request Guidelines
|
||||
|
||||
- **Clear title**: Describe what the PR does
|
||||
- **Description**: Explain why the change is needed
|
||||
- **Tests**: Include tests for new features
|
||||
- **Documentation**: Update docs as needed
|
||||
- **Changelog**: Add entry to CHANGELOG.md
|
||||
- **Commits**: Use clear, descriptive commit messages
|
||||
|
||||
### Code Review Process
|
||||
|
||||
1. Automated tests must pass
|
||||
2. Code review by maintainer
|
||||
3. Address feedback
|
||||
4. Final approval
|
||||
5. Merge to main
|
||||
|
||||
## Development Tools
|
||||
|
||||
### Recommended VSCode Extensions
|
||||
|
||||
- TypeScript
|
||||
- ESLint
|
||||
- Prettier
|
||||
- SQLite Viewer
|
||||
|
||||
### Useful Commands
|
||||
|
||||
```bash
|
||||
# Check TypeScript types
|
||||
npx tsc --noEmit
|
||||
|
||||
# Lint code (if configured)
|
||||
npm run lint
|
||||
|
||||
# Format code (if configured)
|
||||
npm run format
|
||||
|
||||
# Clean build artifacts
|
||||
rm -rf plugin/scripts/*.js plugin/scripts/*.cjs
|
||||
```
|
||||
|
||||
## Troubleshooting Development
|
||||
|
||||
### Build Fails
|
||||
|
||||
1. Clean node_modules:
|
||||
```bash
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Check Node.js version:
|
||||
```bash
|
||||
node --version # Should be >= 18.0.0
|
||||
```
|
||||
|
||||
3. Check for syntax errors:
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
### Tests Fail
|
||||
|
||||
1. Check database:
|
||||
```bash
|
||||
rm ~/.claude-mem/claude-mem.db
|
||||
npm test
|
||||
```
|
||||
|
||||
2. Check worker status:
|
||||
```bash
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
3. View logs:
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
### Worker Won't Start
|
||||
|
||||
1. Kill existing process:
|
||||
```bash
|
||||
npm run worker:stop
|
||||
```
|
||||
|
||||
2. Check port:
|
||||
```bash
|
||||
lsof -i :37777
|
||||
```
|
||||
|
||||
3. Try custom port:
|
||||
```bash
|
||||
export CLAUDE_MEM_WORKER_PORT=38000
|
||||
npm run worker:start
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Architecture Overview](architecture/overview) - Understand the system
|
||||
- [Configuration](configuration) - Customize Claude-Mem
|
||||
- [Troubleshooting](troubleshooting) - Common issues
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"$schema": "https://mintlify.com/schema.json",
|
||||
"name": "Claude-Mem",
|
||||
"description": "Persistent memory compression system that preserves context across Claude Code sessions",
|
||||
"theme": "mint",
|
||||
"favicon": "/claude-mem-logomark.webp",
|
||||
"logo": {
|
||||
"light": "/claude-mem-logo-for-light-mode.webp",
|
||||
"dark": "/claude-mem-logo-for-dark-mode.webp",
|
||||
"href": "https://github.com/thedotmack/claude-mem"
|
||||
},
|
||||
"colors": {
|
||||
"primary": "#3B82F6",
|
||||
"light": "#EFF6FF",
|
||||
"dark": "#1E40AF"
|
||||
},
|
||||
"navbar": {
|
||||
"links": [
|
||||
{
|
||||
"label": "GitHub",
|
||||
"href": "https://github.com/thedotmack/claude-mem"
|
||||
}
|
||||
],
|
||||
"primary": {
|
||||
"type": "button",
|
||||
"label": "Install",
|
||||
"href": "https://github.com/thedotmack/claude-mem#quick-start"
|
||||
}
|
||||
},
|
||||
"navigation": {
|
||||
"groups": [
|
||||
{
|
||||
"group": "Get Started",
|
||||
"icon": "rocket",
|
||||
"pages": [
|
||||
"introduction",
|
||||
"installation",
|
||||
"usage/getting-started",
|
||||
"usage/search-tools",
|
||||
"usage/claude-desktop",
|
||||
"usage/private-tags",
|
||||
"beta-features"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Best Practices",
|
||||
"icon": "lightbulb",
|
||||
"pages": [
|
||||
"context-engineering",
|
||||
"progressive-disclosure"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Configuration & Development",
|
||||
"icon": "gear",
|
||||
"pages": [
|
||||
"configuration",
|
||||
"development",
|
||||
"troubleshooting",
|
||||
"platform-integration"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Architecture",
|
||||
"icon": "diagram-project",
|
||||
"pages": [
|
||||
"architecture/overview",
|
||||
"architecture-evolution",
|
||||
"hooks-architecture",
|
||||
"architecture/hooks",
|
||||
"architecture/worker-service",
|
||||
"architecture/database",
|
||||
"architecture/search-architecture",
|
||||
"architecture/pm2-to-bun-migration"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"footer": {
|
||||
"socials": {
|
||||
"github": "https://github.com/thedotmack/claude-mem"
|
||||
},
|
||||
"links": [
|
||||
{
|
||||
"header": "Resources",
|
||||
"items": [
|
||||
{
|
||||
"label": "Documentation",
|
||||
"href": "https://github.com/thedotmack/claude-mem"
|
||||
},
|
||||
{
|
||||
"label": "Issues",
|
||||
"href": "https://github.com/thedotmack/claude-mem/issues"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"header": "Legal",
|
||||
"items": [
|
||||
{
|
||||
"label": "License (AGPL-3.0)",
|
||||
"href": "https://github.com/thedotmack/claude-mem/blob/main/LICENSE"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"seo": {
|
||||
"indexing": "all",
|
||||
"metatags": {
|
||||
"og:type": "website",
|
||||
"og:site_name": "Claude-Mem Documentation",
|
||||
"og:description": "Persistent memory compression system that preserves context across Claude Code sessions"
|
||||
}
|
||||
},
|
||||
"contextual": {
|
||||
"options": [
|
||||
"copy",
|
||||
"view",
|
||||
"chatgpt",
|
||||
"claude",
|
||||
"cursor"
|
||||
]
|
||||
},
|
||||
"integrations": {
|
||||
"telemetry": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,852 @@
|
||||
# How Claude-Mem Uses Hooks: A Lifecycle-Driven Architecture
|
||||
|
||||
## Core Principle
|
||||
**Observe the main Claude Code session from the outside, process observations in the background, inject context at the right time.**
|
||||
|
||||
---
|
||||
|
||||
## The Big Picture
|
||||
|
||||
Claude-Mem is fundamentally a **hook-driven system**. Every piece of functionality happens in response to lifecycle events:
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ CLAUDE CODE SESSION │
|
||||
│ (Main session - user interacting with Claude) │
|
||||
│ │
|
||||
│ SessionStart → UserPromptSubmit → Tool Use → Stop │
|
||||
│ ↓ ↓ ↓ ↓ ↓ ↓ │
|
||||
│ [3 Hooks] [Hook] [Hook] [Hook] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
↓ ↓ ↓ ↓ ↓ ↓
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ CLAUDE-MEM SYSTEM │
|
||||
│ │
|
||||
│ Smart Context User New Obs │
|
||||
│ Install Inject Message Session Capture │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Key insight:** Claude-Mem doesn't interrupt or modify Claude Code's behavior. It observes from the outside and provides value through lifecycle hooks.
|
||||
|
||||
---
|
||||
|
||||
## Why Hooks?
|
||||
|
||||
### The Non-Invasive Requirement
|
||||
|
||||
Claude-Mem had several architectural constraints:
|
||||
|
||||
1. **Can't modify Claude Code**: It's a closed-source binary
|
||||
2. **Must be fast**: Can't slow down the main session
|
||||
3. **Must be reliable**: Can't break Claude Code if it fails
|
||||
4. **Must be portable**: Works on any project without configuration
|
||||
|
||||
**Solution:** External command hooks configured via settings.json
|
||||
|
||||
### The Hook System Advantage
|
||||
|
||||
Claude Code's hook system provides exactly what we need:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Lifecycle Events" icon="clock">
|
||||
SessionStart, UserPromptSubmit, PostToolUse, Stop
|
||||
</Card>
|
||||
|
||||
<Card title="Non-Blocking" icon="forward">
|
||||
Hooks run in parallel, don't wait for completion
|
||||
</Card>
|
||||
|
||||
<Card title="Context Injection" icon="upload">
|
||||
SessionStart and UserPromptSubmit can add context
|
||||
</Card>
|
||||
|
||||
<Card title="Tool Observation" icon="eye">
|
||||
PostToolUse sees all tool inputs and outputs
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
---
|
||||
|
||||
## The Six Hook Scripts + Pre-Hook
|
||||
|
||||
Claude-Mem uses 6 lifecycle hook scripts across 5 lifecycle events, plus 1 pre-hook script for dependency management. SessionStart runs 2 hooks in sequence (after the pre-hook script).
|
||||
|
||||
### Pre-Hook: Smart Install (Before SessionStart)
|
||||
|
||||
**Purpose:** Intelligently manage dependencies and start worker service
|
||||
|
||||
**Note:** This is NOT a lifecycle hook - it's a pre-hook script executed via command chaining before context-hook runs.
|
||||
|
||||
**When:** Claude Code starts (startup, clear, or compact)
|
||||
|
||||
**What it does:**
|
||||
1. Checks if dependencies need installation (version marker)
|
||||
2. Only runs `npm install` when necessary:
|
||||
- First-time installation
|
||||
- Version changed in package.json
|
||||
3. Provides Windows-specific error messages
|
||||
4. Starts Bun worker service
|
||||
|
||||
**Configuration:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [{
|
||||
"matcher": "startup|clear|compact",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node \"${CLAUDE_PLUGIN_ROOT}/../scripts/smart-install.js\" && node ${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js",
|
||||
"timeout": 300
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- ✅ Version caching (`.install-version` file)
|
||||
- ✅ Fast when already installed (~10ms vs 2-5 seconds)
|
||||
- ✅ Cross-platform compatible
|
||||
- ✅ Helpful Windows error messages for build tools
|
||||
|
||||
**v5.0.3 Enhancement:** Smart caching eliminates redundant installs
|
||||
|
||||
**Source:** `scripts/smart-install.js`
|
||||
|
||||
---
|
||||
|
||||
### Hook 1: SessionStart - Context Injection
|
||||
|
||||
**Purpose:** Inject relevant context from previous sessions
|
||||
|
||||
**When:** Claude Code starts (runs after smart-install pre-hook)
|
||||
|
||||
**What it does:**
|
||||
1. Extracts project name from current working directory
|
||||
2. Queries SQLite for recent session summaries (last 10)
|
||||
3. Queries SQLite for recent observations (configurable, default 50)
|
||||
4. Formats as progressive disclosure index
|
||||
5. Outputs to stdout (automatically injected into context)
|
||||
|
||||
**Key decisions:**
|
||||
- ✅ Runs on startup, clear, and compact
|
||||
- ✅ 300-second timeout (allows for npm install if needed)
|
||||
- ✅ Progressive disclosure format (index, not full details)
|
||||
- ✅ Configurable observation count via `CLAUDE_MEM_CONTEXT_OBSERVATIONS`
|
||||
|
||||
**Output format:**
|
||||
```markdown
|
||||
# [claude-mem] recent context
|
||||
|
||||
**Legend:** 🎯 session-request | 🔴 gotcha | 🟡 problem-solution ...
|
||||
|
||||
### Oct 26, 2025
|
||||
|
||||
**General**
|
||||
| ID | Time | T | Title | Tokens |
|
||||
|----|------|---|-------|--------|
|
||||
| #2586 | 12:58 AM | 🔵 | Context hook file empty | ~51 |
|
||||
|
||||
*Use mem-search skill to access full details*
|
||||
```
|
||||
|
||||
**Source:** `src/hooks/context-hook.ts` → `plugin/scripts/context-hook.js`
|
||||
|
||||
---
|
||||
|
||||
### Hook 2: SessionStart - User Message
|
||||
|
||||
**Purpose:** Display helpful user messages during first-time setup
|
||||
|
||||
**When:** Claude Code starts (runs after context-hook)
|
||||
|
||||
**What it does:**
|
||||
1. Checks if dependencies are installed
|
||||
2. Shows first-time setup message if needed
|
||||
3. Displays formatted context information with colors
|
||||
4. Shows link to viewer UI (http://localhost:37777)
|
||||
5. Exits with code 3 (informational, not error)
|
||||
|
||||
**Configuration:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [{
|
||||
"matcher": "startup|clear|compact",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "node ${CLAUDE_PLUGIN_ROOT}/scripts/user-message-hook.js",
|
||||
"timeout": 10
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```
|
||||
📝 Claude-Mem Context Loaded
|
||||
ℹ️ Note: This appears as stderr but is informational only
|
||||
|
||||
[Context details with colors...]
|
||||
|
||||
📺 Watch live in browser http://localhost:37777/ (New! v5.1)
|
||||
```
|
||||
|
||||
**Key Features:**
|
||||
- ✅ User-friendly first-time experience
|
||||
- ✅ Visual context display
|
||||
- ✅ Links to viewer UI
|
||||
- ✅ Non-intrusive (exit code 3)
|
||||
|
||||
**Source:** `plugin/scripts/user-message-hook.js` (minified)
|
||||
|
||||
---
|
||||
|
||||
### Hook 3: UserPromptSubmit (New Session Hook)
|
||||
|
||||
**Purpose:** Initialize session tracking when user submits a prompt
|
||||
|
||||
**When:** Before Claude processes the user's message
|
||||
|
||||
**What it does:**
|
||||
1. Reads user prompt and session ID from stdin
|
||||
2. Creates new session record in SQLite
|
||||
3. Saves raw user prompt for full-text search (v4.2.0+)
|
||||
4. Starts Bun worker service if not running
|
||||
5. Returns immediately (non-blocking)
|
||||
|
||||
**Configuration:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/new-hook.js"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key decisions:**
|
||||
- ✅ No matcher (runs for all prompts)
|
||||
- ✅ Creates session record immediately
|
||||
- ✅ Stores raw prompts for search (privacy note: local SQLite only)
|
||||
- ✅ Auto-starts worker service
|
||||
- ✅ Suppresses output (`suppressOutput: true`)
|
||||
|
||||
**Database operations:**
|
||||
```sql
|
||||
INSERT INTO sdk_sessions (claude_session_id, project, user_prompt, ...)
|
||||
VALUES (?, ?, ?, ...)
|
||||
|
||||
INSERT INTO user_prompts (session_id, prompt, prompt_number, ...)
|
||||
VALUES (?, ?, ?, ...)
|
||||
```
|
||||
|
||||
**Source:** `src/hooks/new-hook.ts` → `plugin/scripts/new-hook.js`
|
||||
|
||||
---
|
||||
|
||||
### Hook 4: PostToolUse (Save Observation Hook)
|
||||
|
||||
**Purpose:** Capture tool execution observations for later processing
|
||||
|
||||
**When:** Immediately after any tool completes successfully
|
||||
|
||||
**What it does:**
|
||||
1. Receives tool name, input, output from stdin
|
||||
2. Finds active session for current project
|
||||
3. Enqueues observation in observation_queue table
|
||||
4. Returns immediately (processing happens in worker)
|
||||
|
||||
**Configuration:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PostToolUse": [{
|
||||
"matcher": "*",
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key decisions:**
|
||||
- ✅ Matcher: `*` (captures all tools)
|
||||
- ✅ Non-blocking (just enqueues, doesn't process)
|
||||
- ✅ Worker processes observations asynchronously
|
||||
- ✅ Parallel execution safe (each hook gets own stdin)
|
||||
|
||||
**Database operations:**
|
||||
```sql
|
||||
INSERT INTO observation_queue (session_id, tool_name, tool_input, tool_output, ...)
|
||||
VALUES (?, ?, ?, ?, ...)
|
||||
```
|
||||
|
||||
**What gets queued:**
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"tool_name": "Edit",
|
||||
"tool_input": {
|
||||
"file_path": "/path/to/file.ts",
|
||||
"old_string": "...",
|
||||
"new_string": "..."
|
||||
},
|
||||
"tool_output": {
|
||||
"success": true,
|
||||
"linesChanged": 5
|
||||
},
|
||||
"created_at_epoch": 1698765432
|
||||
}
|
||||
```
|
||||
|
||||
**Source:** `src/hooks/save-hook.ts` → `plugin/scripts/save-hook.js`
|
||||
|
||||
---
|
||||
|
||||
### Hook 5: Stop Hook (Summary Generation)
|
||||
|
||||
**Purpose:** Generate AI-powered session summaries during the session
|
||||
|
||||
**When:** When Claude stops (triggered by Stop lifecycle event)
|
||||
|
||||
**What it does:**
|
||||
1. Gathers session observations from database
|
||||
2. Sends to Claude Agent SDK for summarization
|
||||
3. Processes response and extracts structured summary
|
||||
4. Stores in session_summaries table
|
||||
|
||||
**Configuration:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"Stop": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/summary-hook.js"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key decisions:**
|
||||
- ✅ Triggered by Stop lifecycle event
|
||||
- ✅ Multiple summaries per session (v4.2.0+)
|
||||
- ✅ Summaries are checkpoints, not endings
|
||||
- ✅ Uses Claude Agent SDK for AI compression
|
||||
|
||||
**Summary structure:**
|
||||
```xml
|
||||
<summary>
|
||||
<request>User's original request</request>
|
||||
<investigated>What was examined</investigated>
|
||||
<learned>Key discoveries</learned>
|
||||
<completed>Work finished</completed>
|
||||
<next_steps>Remaining tasks</next_steps>
|
||||
<files_read>
|
||||
<file>path/to/file1.ts</file>
|
||||
<file>path/to/file2.ts</file>
|
||||
</files_read>
|
||||
<files_modified>
|
||||
<file>path/to/file3.ts</file>
|
||||
</files_modified>
|
||||
<notes>Additional context</notes>
|
||||
</summary>
|
||||
```
|
||||
|
||||
**Source:** `src/hooks/summary-hook.ts` → `plugin/scripts/summary-hook.js`
|
||||
|
||||
---
|
||||
|
||||
### Hook 6: SessionEnd (Cleanup Hook)
|
||||
|
||||
**Purpose:** Mark sessions as completed when they end
|
||||
|
||||
**When:** Claude Code session ends (not on `/clear`)
|
||||
|
||||
**What it does:**
|
||||
1. Marks session as completed in database
|
||||
2. Allows worker to finish processing
|
||||
3. Performs graceful cleanup
|
||||
|
||||
**Configuration:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"SessionEnd": [{
|
||||
"hooks": [{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key decisions:**
|
||||
- ✅ Graceful completion (v4.1.0+)
|
||||
- ✅ No longer sends DELETE to workers
|
||||
- ✅ Skips cleanup on `/clear` commands
|
||||
- ✅ Preserves ongoing sessions
|
||||
|
||||
**Why graceful cleanup?**
|
||||
|
||||
**Old approach (v3):**
|
||||
```typescript
|
||||
// ❌ Aggressive cleanup
|
||||
SessionEnd → DELETE /worker/session → Worker stops immediately
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- Interrupted summary generation
|
||||
- Lost pending observations
|
||||
- Race conditions
|
||||
|
||||
**New approach (v4.1.0+):**
|
||||
```typescript
|
||||
// ✅ Graceful completion
|
||||
SessionEnd → UPDATE sessions SET completed_at = NOW()
|
||||
Worker sees completion → Finishes processing → Exits naturally
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Worker finishes important operations
|
||||
- Summaries complete successfully
|
||||
- Clean state transitions
|
||||
|
||||
**Source:** `src/hooks/cleanup-hook.ts` → `plugin/scripts/cleanup-hook.js`
|
||||
|
||||
---
|
||||
|
||||
## Hook Execution Flow
|
||||
|
||||
### Session Lifecycle
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant User
|
||||
participant Claude
|
||||
participant Hooks
|
||||
participant Worker
|
||||
participant DB
|
||||
|
||||
User->>Claude: Start Claude Code
|
||||
Claude->>Hooks: SessionStart hook
|
||||
Hooks->>DB: Query recent context
|
||||
DB-->>Hooks: Session summaries + observations
|
||||
Hooks-->>Claude: Inject context
|
||||
Note over Claude: Context available for session
|
||||
|
||||
User->>Claude: Submit prompt
|
||||
Claude->>Hooks: UserPromptSubmit hook
|
||||
Hooks->>DB: Create session record
|
||||
Hooks->>Worker: Start worker (if not running)
|
||||
Worker-->>DB: Ready to process
|
||||
|
||||
Claude->>Claude: Execute tools
|
||||
Claude->>Hooks: PostToolUse (multiple times)
|
||||
Hooks->>DB: Queue observations
|
||||
Note over Worker: Polls queue, processes observations
|
||||
|
||||
Worker->>Worker: AI compression
|
||||
Worker->>DB: Store compressed observations
|
||||
Worker->>Hooks: Trigger summary hook
|
||||
Hooks->>DB: Store session summary
|
||||
|
||||
User->>Claude: Finish
|
||||
Claude->>Hooks: SessionEnd hook
|
||||
Hooks->>DB: Mark session complete
|
||||
Worker->>DB: Check completion
|
||||
Worker->>Worker: Finish processing
|
||||
Worker->>Worker: Exit gracefully
|
||||
```
|
||||
|
||||
### Hook Timing
|
||||
|
||||
| Event | Timing | Blocking | Timeout | Output Handling |
|
||||
|-------|--------|----------|---------|-----------------|
|
||||
| **SessionStart (smart-install)** | Before session | No | 300s | stderr (info) |
|
||||
| **SessionStart (context)** | Before session | No | 300s | stdout → context |
|
||||
| **SessionStart (user-message)** | Before session | No | 10s | stderr (info) |
|
||||
| **UserPromptSubmit** | Before processing | No | 120s | stdout → context |
|
||||
| **PostToolUse** | After tool | No | 120s | Transcript only |
|
||||
| **Summary** | Worker triggered | No | 120s | Database |
|
||||
| **SessionEnd** | On exit | No | 120s | Log only |
|
||||
|
||||
---
|
||||
|
||||
## The Worker Service Architecture
|
||||
|
||||
### Why a Background Worker?
|
||||
|
||||
**Problem:** Hooks must be fast (< 1 second)
|
||||
|
||||
**Reality:** AI compression takes 5-30 seconds per observation
|
||||
|
||||
**Solution:** Hooks enqueue observations, worker processes async
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ HOOK (Fast) │
|
||||
│ 1. Read stdin (< 1ms) │
|
||||
│ 2. Insert into queue (< 10ms) │
|
||||
│ 3. Return success (< 20ms total) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
↓ (queue)
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ WORKER (Slow) │
|
||||
│ 1. Poll queue every 1s │
|
||||
│ 2. Process observation via Claude SDK (5-30s) │
|
||||
│ 3. Parse and store results │
|
||||
│ 4. Mark observation processed │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Bun Process Management
|
||||
|
||||
**Technology:** Bun (JavaScript runtime and process manager)
|
||||
|
||||
**Why Bun:**
|
||||
- Auto-restart on failure
|
||||
- Fast startup and low memory footprint
|
||||
- Built-in TypeScript support
|
||||
- Cross-platform (works on macOS, Linux, Windows)
|
||||
- No separate process manager needed
|
||||
|
||||
**Worker lifecycle:**
|
||||
```bash
|
||||
# Started by hooks automatically (if not running)
|
||||
npm run worker:start
|
||||
|
||||
# Status check
|
||||
npm run worker:status
|
||||
|
||||
# View logs
|
||||
npm run worker:logs
|
||||
|
||||
# Restart
|
||||
npm run worker:restart
|
||||
|
||||
# Stop
|
||||
npm run worker:stop
|
||||
```
|
||||
|
||||
### Worker HTTP API
|
||||
|
||||
**Technology:** Express.js REST API on port 37777
|
||||
|
||||
**Endpoints:**
|
||||
|
||||
| Endpoint | Method | Purpose |
|
||||
|----------|--------|---------|
|
||||
| `/health` | GET | Health check |
|
||||
| `/sessions` | POST | Create session |
|
||||
| `/sessions/:id` | GET | Get session status |
|
||||
| `/sessions/:id` | PATCH | Update session |
|
||||
| `/observations` | POST | Enqueue observation |
|
||||
| `/observations/:id` | GET | Get observation |
|
||||
|
||||
**Why HTTP API?**
|
||||
- Language-agnostic (hooks can be any language)
|
||||
- Easy debugging (curl commands)
|
||||
- Standard error handling
|
||||
- Proper async handling
|
||||
|
||||
---
|
||||
|
||||
## Design Patterns
|
||||
|
||||
### Pattern 1: Fire-and-Forget Hooks
|
||||
|
||||
**Principle:** Hooks should return immediately, not wait for completion
|
||||
|
||||
```typescript
|
||||
// ❌ Bad: Hook waits for processing
|
||||
export async function saveHook(stdin: HookInput) {
|
||||
const observation = parseInput(stdin);
|
||||
await processObservation(observation); // BLOCKS!
|
||||
return success();
|
||||
}
|
||||
|
||||
// ✅ Good: Hook enqueues and returns
|
||||
export async function saveHook(stdin: HookInput) {
|
||||
const observation = parseInput(stdin);
|
||||
await enqueueObservation(observation); // Fast
|
||||
return success(); // Immediate
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 2: Queue-Based Processing
|
||||
|
||||
**Principle:** Decouple capture from processing
|
||||
|
||||
```
|
||||
Hook (capture) → Queue (buffer) → Worker (process)
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Parallel hook execution safe
|
||||
- Worker failure doesn't affect hooks
|
||||
- Retry logic centralized
|
||||
- Backpressure handling
|
||||
|
||||
### Pattern 3: Graceful Degradation
|
||||
|
||||
**Principle:** Memory system failure shouldn't break Claude Code
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await captureObservation();
|
||||
} catch (error) {
|
||||
// Log error, but don't throw
|
||||
console.error('Memory capture failed:', error);
|
||||
return { continue: true, suppressOutput: true };
|
||||
}
|
||||
```
|
||||
|
||||
**Failure modes:**
|
||||
- Database locked → Skip observation, log error
|
||||
- Worker crashed → Auto-restart via Bun
|
||||
- Network issue → Retry with exponential backoff
|
||||
- Disk full → Warn user, disable memory
|
||||
|
||||
### Pattern 4: Progressive Enhancement
|
||||
|
||||
**Principle:** Core functionality works without memory, memory enhances it
|
||||
|
||||
```
|
||||
Without memory: Claude Code works normally
|
||||
With memory: Claude Code + context from past sessions
|
||||
Memory broken: Falls back to working normally
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hook Debugging
|
||||
|
||||
### Debug Mode
|
||||
|
||||
Enable detailed hook execution logs:
|
||||
|
||||
```bash
|
||||
claude --debug
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```
|
||||
[DEBUG] Executing hooks for PostToolUse:Write
|
||||
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
|
||||
[DEBUG] Found 1 hook matchers in settings
|
||||
[DEBUG] Matched 1 hooks for query "Write"
|
||||
[DEBUG] Found 1 hook commands to execute
|
||||
[DEBUG] Executing hook command: ${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js with timeout 60000ms
|
||||
[DEBUG] Hook command completed with status 0: {"continue":true,"suppressOutput":true}
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Hook not executing">
|
||||
**Symptoms:** Hook command never runs
|
||||
|
||||
**Debugging:**
|
||||
1. Check `/hooks` menu - is hook registered?
|
||||
2. Verify matcher pattern (case-sensitive!)
|
||||
3. Test command manually: `echo '{}' | node save-hook.js`
|
||||
4. Check file permissions (executable?)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Hook times out">
|
||||
**Symptoms:** Hook execution exceeds timeout
|
||||
|
||||
**Debugging:**
|
||||
1. Check timeout setting (default 60s)
|
||||
2. Identify slow operation (database? network?)
|
||||
3. Move slow operation to worker
|
||||
4. Increase timeout if necessary
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Context not injecting">
|
||||
**Symptoms:** SessionStart hook runs but context missing
|
||||
|
||||
**Debugging:**
|
||||
1. Check stdout (must be valid JSON or plain text)
|
||||
2. Verify no stderr output (pollutes JSON)
|
||||
3. Check exit code (must be 0)
|
||||
4. Look for npm install output (v4.3.1 fix)
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Observations not captured">
|
||||
**Symptoms:** PostToolUse hook runs but observations missing
|
||||
|
||||
**Debugging:**
|
||||
1. Check database: `sqlite3 ~/.claude-mem/claude-mem.db "SELECT * FROM observation_queue"`
|
||||
2. Verify session exists: `SELECT * FROM sdk_sessions`
|
||||
3. Check worker status: `npm run worker:status`
|
||||
4. View worker logs: `npm run worker:logs`
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
### Testing Hooks Manually
|
||||
|
||||
```bash
|
||||
# Test context hook
|
||||
echo '{
|
||||
"session_id": "test123",
|
||||
"cwd": "/Users/alex/projects/my-app",
|
||||
"hook_event_name": "SessionStart",
|
||||
"source": "startup"
|
||||
}' | node plugin/scripts/context-hook.js
|
||||
|
||||
# Test save hook
|
||||
echo '{
|
||||
"session_id": "test123",
|
||||
"tool_name": "Edit",
|
||||
"tool_input": {"file_path": "test.ts"},
|
||||
"tool_output": {"success": true}
|
||||
}' | node plugin/scripts/save-hook.js
|
||||
|
||||
# Test with actual Claude Code
|
||||
claude --debug
|
||||
/hooks # View registered hooks
|
||||
# Submit prompt and watch debug output
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Hook Execution Time
|
||||
|
||||
**Target:** < 100ms per hook
|
||||
|
||||
**Actual measurements:**
|
||||
|
||||
| Hook | Average | p95 | p99 |
|
||||
|------|---------|-----|-----|
|
||||
| SessionStart (smart-install, cached) | 10ms | 20ms | 40ms |
|
||||
| SessionStart (smart-install, first run) | 2500ms | 5000ms | 8000ms |
|
||||
| SessionStart (context) | 45ms | 120ms | 250ms |
|
||||
| SessionStart (user-message) | 5ms | 10ms | 15ms |
|
||||
| UserPromptSubmit | 12ms | 25ms | 50ms |
|
||||
| PostToolUse | 8ms | 15ms | 30ms |
|
||||
| SessionEnd | 5ms | 10ms | 20ms |
|
||||
|
||||
**Why smart-install is sometimes slow:**
|
||||
- First-time: Full npm install (2-5 seconds)
|
||||
- Cached: Version check only (~10ms)
|
||||
- Version change: Full npm install + worker restart
|
||||
|
||||
**Optimization (v5.0.3):**
|
||||
- Version caching with `.install-version` marker
|
||||
- Only install on version change or missing deps
|
||||
- Windows-specific error messages with build tool help
|
||||
|
||||
### Database Performance
|
||||
|
||||
**Schema optimizations:**
|
||||
- Indexes on `project`, `created_at_epoch`, `claude_session_id`
|
||||
- FTS5 virtual tables for full-text search
|
||||
- WAL mode for concurrent reads/writes
|
||||
|
||||
**Query patterns:**
|
||||
```sql
|
||||
-- Fast: Uses index on (project, created_at_epoch)
|
||||
SELECT * FROM session_summaries
|
||||
WHERE project = ?
|
||||
ORDER BY created_at_epoch DESC
|
||||
LIMIT 10
|
||||
|
||||
-- Fast: Uses index on claude_session_id
|
||||
SELECT * FROM sdk_sessions
|
||||
WHERE claude_session_id = ?
|
||||
LIMIT 1
|
||||
|
||||
-- Fast: FTS5 full-text search
|
||||
SELECT * FROM observations_fts
|
||||
WHERE observations_fts MATCH ?
|
||||
ORDER BY rank
|
||||
LIMIT 20
|
||||
```
|
||||
|
||||
### Worker Throughput
|
||||
|
||||
**Bottleneck:** Claude API latency (5-30s per observation)
|
||||
|
||||
**Mitigation:**
|
||||
- Process observations sequentially (simpler, more predictable)
|
||||
- Skip low-value observations (TodoWrite, ListMcpResourcesTool)
|
||||
- Batch summaries (generate every N observations, not every observation)
|
||||
|
||||
**Future optimization:**
|
||||
- Parallel processing (multiple workers)
|
||||
- Smart batching (combine related observations)
|
||||
- Lazy summarization (summarize only when needed)
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Hook Command Safety
|
||||
|
||||
**Risk:** Hooks execute arbitrary commands with user permissions
|
||||
|
||||
**Mitigations:**
|
||||
1. **Frozen at startup:** Hook configuration captured at start, changes require review
|
||||
2. **User review required:** `/hooks` menu shows changes, requires approval
|
||||
3. **Plugin isolation:** `${CLAUDE_PLUGIN_ROOT}` prevents path traversal
|
||||
4. **Input validation:** Hooks validate stdin schema before processing
|
||||
|
||||
### Data Privacy
|
||||
|
||||
**What gets stored:**
|
||||
- User prompts (raw text) - v4.2.0+
|
||||
- Tool inputs and outputs
|
||||
- File paths read/modified
|
||||
- Session summaries
|
||||
|
||||
**Privacy guarantees:**
|
||||
- All data stored locally in `~/.claude-mem/claude-mem.db`
|
||||
- No cloud uploads (API calls only for AI compression)
|
||||
- SQLite file permissions: user-only read/write
|
||||
- No analytics or telemetry
|
||||
|
||||
### API Key Protection
|
||||
|
||||
**Configuration:**
|
||||
- Anthropic API key in `~/.anthropic/api_key` or `ANTHROPIC_API_KEY` env var
|
||||
- Worker inherits environment from Claude Code
|
||||
- Never logged or stored in database
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Hooks are interfaces**: They define clean boundaries between systems
|
||||
2. **Non-blocking is critical**: Hooks must return fast, workers do the heavy lifting
|
||||
3. **Graceful degradation**: Memory system can fail without breaking Claude Code
|
||||
4. **Queue-based decoupling**: Capture and processing happen independently
|
||||
5. **Progressive disclosure**: Context injection uses index-first approach
|
||||
6. **Lifecycle alignment**: Each hook has a clear, single purpose
|
||||
|
||||
---
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Claude Code Hooks Reference](https://docs.claude.com/claude-code/hooks) - Official documentation
|
||||
- [Progressive Disclosure](progressive-disclosure) - Context priming philosophy
|
||||
- [Architecture Evolution](architecture-evolution) - v3 to v4 journey
|
||||
- [Worker Service Design](architecture/worker-service) - Background processing details
|
||||
|
||||
---
|
||||
|
||||
*The hook-driven architecture enables Claude-Mem to be both powerful and invisible. Users never notice the memory system working - it just makes Claude smarter over time.*
|
||||
@@ -0,0 +1,112 @@
|
||||
---
|
||||
title: "Installation"
|
||||
description: "Install Claude-Mem plugin for persistent memory across sessions"
|
||||
---
|
||||
|
||||
# Installation Guide
|
||||
|
||||
## Quick Start
|
||||
|
||||
Install Claude-Mem directly from the plugin marketplace:
|
||||
|
||||
```bash
|
||||
/plugin marketplace add thedotmack/claude-mem
|
||||
/plugin install claude-mem
|
||||
```
|
||||
|
||||
That's it! The plugin will automatically:
|
||||
- Download prebuilt binaries (no compilation needed)
|
||||
- Install all dependencies (including SQLite binaries)
|
||||
- Configure hooks for session lifecycle management
|
||||
- Auto-start the worker service on first session
|
||||
|
||||
Start a new Claude Code session and you'll see context from previous sessions automatically loaded.
|
||||
|
||||
## System Requirements
|
||||
|
||||
- **Node.js**: 18.0.0 or higher
|
||||
- **Claude Code**: Latest version with plugin support
|
||||
- **Bun**: JavaScript runtime and process manager (auto-installed if missing)
|
||||
- **SQLite 3**: For persistent storage (bundled)
|
||||
|
||||
## Advanced Installation
|
||||
|
||||
For development or testing, you can clone and build from source:
|
||||
|
||||
### Clone and Build
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/thedotmack/claude-mem.git
|
||||
cd claude-mem
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Build hooks and worker service
|
||||
npm run build
|
||||
|
||||
# Worker service will auto-start on first Claude Code session
|
||||
# Or manually start with:
|
||||
npm run worker:start
|
||||
|
||||
# Verify worker is running
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
### Post-Installation Verification
|
||||
|
||||
#### 1. Automatic Dependency Installation
|
||||
|
||||
Dependencies are installed automatically during plugin installation. The SessionStart hook also ensures dependencies are up-to-date on each session start (this is fast and idempotent). Works cross-platform on Windows, macOS, and Linux.
|
||||
|
||||
#### 2. Verify Plugin Installation
|
||||
|
||||
Check that hooks are configured in Claude Code:
|
||||
```bash
|
||||
cat plugin/hooks/hooks.json
|
||||
```
|
||||
|
||||
#### 3. Data Directory Location
|
||||
|
||||
Data is stored in `~/.claude-mem/`:
|
||||
- Database: `~/.claude-mem/claude-mem.db`
|
||||
- PID file: `~/.claude-mem/.worker.pid`
|
||||
- Port file: `~/.claude-mem/.worker.port`
|
||||
- Logs: `~/.claude-mem/logs/worker-YYYY-MM-DD.log`
|
||||
- Settings: `~/.claude-mem/settings.json`
|
||||
|
||||
Override with environment variable:
|
||||
```bash
|
||||
export CLAUDE_MEM_DATA_DIR=/custom/path
|
||||
```
|
||||
|
||||
#### 4. Check Worker Logs
|
||||
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
#### 5. Test Context Retrieval
|
||||
|
||||
```bash
|
||||
npm run test:context
|
||||
```
|
||||
|
||||
## Upgrading
|
||||
|
||||
Upgrades are automatic when updating via the plugin marketplace. Key changes in recent versions:
|
||||
|
||||
**v7.1.0**: PM2 replaced with native Bun process management. Migration is automatic on first hook trigger.
|
||||
|
||||
**v7.0.0+**: 11 configuration settings, dual-tag privacy system.
|
||||
|
||||
**v5.4.0+**: Skill-based search replaces MCP tools, saving ~2,250 tokens per session.
|
||||
|
||||
See [CHANGELOG](https://github.com/thedotmack/claude-mem/blob/main/CHANGELOG.md) for complete version history.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Getting Started Guide](usage/getting-started) - Learn how Claude-Mem works automatically
|
||||
- [MCP Search Tools](usage/search-tools) - Query your project history
|
||||
- [Configuration](configuration) - Customize Claude-Mem behavior
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: "Introduction"
|
||||
description: "Persistent memory compression system for Claude Code"
|
||||
---
|
||||
|
||||
# Claude-Mem
|
||||
|
||||
**Persistent memory compression system for Claude Code**
|
||||
|
||||
Claude-Mem seamlessly preserves context across sessions by automatically capturing tool usage observations, generating semantic summaries, and making them available to future sessions. This enables Claude to maintain continuity of knowledge about projects even after sessions end or reconnect.
|
||||
|
||||
## Quick Start
|
||||
|
||||
Start a new Claude Code session in the terminal and enter the following commands:
|
||||
|
||||
```bash
|
||||
/plugin marketplace add thedotmack/claude-mem
|
||||
/plugin install claude-mem
|
||||
```
|
||||
|
||||
Restart Claude Code. Context from previous sessions will automatically appear in new sessions.
|
||||
|
||||
## Key Features
|
||||
|
||||
- 🧠 **Persistent Memory** - Context survives across sessions
|
||||
- 🔍 **mem-search Skill** - Query your project history with natural language (~2,250 token savings)
|
||||
- 🌐 **Web Viewer UI** - Real-time memory stream visualization at http://localhost:37777
|
||||
- 🔒 **Privacy Control** - Use `<private>` tags to exclude sensitive content from storage
|
||||
- ⚙️ **Context Configuration** - Fine-grained control over what context gets injected
|
||||
- 🤖 **Automatic Operation** - No manual intervention required
|
||||
- 📊 **FTS5 Search** - Fast full-text search across observations
|
||||
- 🔗 **Citations** - Reference past decisions with `claude-mem://` URIs
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Session Start → Inject context from last 10 sessions │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ User Prompts → Create session, save user prompts │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Tool Executions → Capture observations (Read, Write, etc.) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Worker Processes → Extract learnings via Claude Agent SDK │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
↓
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Session Ends → Generate summary, ready for next session │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Core Components:**
|
||||
1. **5 Lifecycle Hooks** - SessionStart, UserPromptSubmit, PostToolUse, Stop, SessionEnd (6 hook scripts)
|
||||
2. **Smart Install** - Cached dependency checker (pre-hook script)
|
||||
3. **Worker Service** - HTTP API on port 37777 managed by Bun
|
||||
4. **SQLite Database** - Stores sessions, observations, summaries with FTS5 search
|
||||
5. **mem-search Skill** - Query historical context with natural language
|
||||
6. **Web Viewer UI** - Real-time visualization with SSE and infinite scroll
|
||||
|
||||
See [Architecture Overview](architecture/overview) for details.
|
||||
|
||||
## System Requirements
|
||||
|
||||
- **Node.js**: 18.0.0 or higher
|
||||
- **Claude Code**: Latest version with plugin support
|
||||
- **Bun**: JavaScript runtime and process manager (auto-installed if missing)
|
||||
- **SQLite 3**: For persistent storage (bundled)
|
||||
|
||||
## What's New
|
||||
|
||||
**v7.1.0 - Bun Migration:**
|
||||
- Replaced PM2 with native Bun process management
|
||||
- Switched from better-sqlite3 to bun:sqlite for faster database access
|
||||
- Automatic one-time migration on first hook trigger
|
||||
- Simplified cross-platform support
|
||||
|
||||
**v7.0.0 - Context Configuration:**
|
||||
- 11 settings for fine-grained control over context injection
|
||||
- Dual-tag privacy system (`<private>` tags)
|
||||
|
||||
**Previous Highlights:**
|
||||
- **v5.5.0**: mem-search skill with 100% effectiveness rate
|
||||
- **v5.4.0**: Skill-based search (~2,250 tokens saved per session)
|
||||
- **v5.1.0**: Web viewer UI at http://localhost:37777
|
||||
|
||||
## Next Steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Installation" icon="download" href="/installation">
|
||||
Quick start & advanced installation
|
||||
</Card>
|
||||
<Card title="Getting Started" icon="rocket" href="/usage/getting-started">
|
||||
Learn how Claude-Mem works automatically
|
||||
</Card>
|
||||
<Card title="Architecture" icon="sitemap" href="/architecture/overview">
|
||||
System components & data flow
|
||||
</Card>
|
||||
<Card title="Search Tools" icon="magnifying-glass" href="/usage/search-tools">
|
||||
Query your project history
|
||||
</Card>
|
||||
</CardGroup>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,655 @@
|
||||
# Progressive Disclosure: Claude-Mem's Context Priming Philosophy
|
||||
|
||||
## Core Principle
|
||||
**Show what exists and its retrieval cost first. Let the agent decide what to fetch based on relevance and need.**
|
||||
|
||||
---
|
||||
|
||||
## What is Progressive Disclosure?
|
||||
|
||||
Progressive disclosure is an information architecture pattern where you reveal complexity gradually rather than all at once. In the context of AI agents, it means:
|
||||
|
||||
1. **Layer 1 (Index)**: Show lightweight metadata (titles, dates, types, token counts)
|
||||
2. **Layer 2 (Details)**: Fetch full content only when needed
|
||||
3. **Layer 3 (Deep Dive)**: Read original source files if required
|
||||
|
||||
This mirrors how humans work: We scan headlines before reading articles, review table of contents before diving into chapters, and check file names before opening files.
|
||||
|
||||
---
|
||||
|
||||
## The Problem: Context Pollution
|
||||
|
||||
Traditional RAG (Retrieval-Augmented Generation) systems fetch everything upfront:
|
||||
|
||||
```
|
||||
❌ Traditional Approach:
|
||||
┌─────────────────────────────────────┐
|
||||
│ Session Start │
|
||||
│ │
|
||||
│ [15,000 tokens of past sessions] │
|
||||
│ [8,000 tokens of observations] │
|
||||
│ [12,000 tokens of file summaries] │
|
||||
│ │
|
||||
│ Total: 35,000 tokens │
|
||||
│ Relevant: ~2,000 tokens (6%) │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Problems:**
|
||||
- Wastes 94% of attention budget on irrelevant context
|
||||
- User prompt gets buried under mountain of history
|
||||
- Agent must process everything before understanding task
|
||||
- No way to know what's actually useful until after reading
|
||||
|
||||
---
|
||||
|
||||
## Claude-Mem's Solution: Progressive Disclosure
|
||||
|
||||
```
|
||||
✅ Progressive Disclosure Approach:
|
||||
┌─────────────────────────────────────┐
|
||||
│ Session Start │
|
||||
│ │
|
||||
│ Index of 50 observations: ~800 tokens│
|
||||
│ ↓ │
|
||||
│ Agent sees: "🔴 Hook timeout issue" │
|
||||
│ Agent decides: "Relevant!" │
|
||||
│ ↓ │
|
||||
│ Fetch observation #2543: ~120 tokens│
|
||||
│ │
|
||||
│ Total: 920 tokens │
|
||||
│ Relevant: 920 tokens (100%) │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Agent controls its own context consumption
|
||||
- Directly relevant to current task
|
||||
- Can fetch more if needed
|
||||
- Can skip everything if not relevant
|
||||
- Clear cost/benefit for each retrieval decision
|
||||
|
||||
---
|
||||
|
||||
## How It Works in Claude-Mem
|
||||
|
||||
### The Index Format
|
||||
|
||||
Every SessionStart hook provides a compact index:
|
||||
|
||||
```markdown
|
||||
### Oct 26, 2025
|
||||
|
||||
**General**
|
||||
| ID | Time | T | Title | Tokens |
|
||||
|----|------|---|-------|--------|
|
||||
| #2586 | 12:58 AM | 🔵 | Context hook file exists but is empty | ~51 |
|
||||
| #2587 | ″ | 🔵 | Context hook script file is empty | ~46 |
|
||||
| #2589 | ″ | 🟡 | Investigated hook debug output docs | ~105 |
|
||||
|
||||
**src/hooks/context-hook.ts**
|
||||
| ID | Time | T | Title | Tokens |
|
||||
|----|------|---|-------|--------|
|
||||
| #2591 | 1:15 AM | ⚖️ | Stderr messaging abandoned | ~155 |
|
||||
| #2592 | 1:16 AM | ⚖️ | Web UI strategy redesigned | ~193 |
|
||||
```
|
||||
|
||||
**What the agent sees:**
|
||||
- **What exists**: Observation titles give semantic meaning
|
||||
- **When it happened**: Timestamps for temporal context
|
||||
- **What type**: Icons indicate observation category
|
||||
- **Retrieval cost**: Token counts for informed decisions
|
||||
- **Where to get it**: MCP search tools referenced at bottom
|
||||
|
||||
### The Legend System
|
||||
|
||||
```
|
||||
🎯 session-request - User's original goal
|
||||
🔴 gotcha - Critical edge case or pitfall
|
||||
🟡 problem-solution - Bug fix or workaround
|
||||
🔵 how-it-works - Technical explanation
|
||||
🟢 what-changed - Code/architecture change
|
||||
🟣 discovery - Learning or insight
|
||||
🟠 why-it-exists - Design rationale
|
||||
🟤 decision - Architecture decision
|
||||
⚖️ trade-off - Deliberate compromise
|
||||
```
|
||||
|
||||
**Purpose:**
|
||||
- Visual scanning (humans and AI both benefit)
|
||||
- Semantic categorization
|
||||
- Priority signaling (🔴 gotchas are more critical)
|
||||
- Pattern recognition across sessions
|
||||
|
||||
### Progressive Disclosure Instructions
|
||||
|
||||
The index includes usage guidance:
|
||||
|
||||
```markdown
|
||||
💡 **Progressive Disclosure:** This index shows WHAT exists and retrieval COST.
|
||||
- Use MCP search tools to fetch full observation details on-demand
|
||||
- Prefer searching observations over re-reading code for past decisions
|
||||
- Critical types (🔴 gotcha, 🟤 decision, ⚖️ trade-off) often worth fetching immediately
|
||||
```
|
||||
|
||||
**What this does:**
|
||||
- Teaches the agent the pattern
|
||||
- Suggests when to fetch (critical types)
|
||||
- Recommends search over code re-reading (efficiency)
|
||||
- Makes the system self-documenting
|
||||
|
||||
---
|
||||
|
||||
## The Philosophy: Context as Currency
|
||||
|
||||
### Mental Model: Token Budget as Money
|
||||
|
||||
Think of context window as a bank account:
|
||||
|
||||
| Approach | Metaphor | Outcome |
|
||||
|----------|----------|---------|
|
||||
| **Dump everything** | Spending your entire paycheck on groceries you might need someday | Waste, clutter, can't afford what you actually need |
|
||||
| **Fetch nothing** | Refusing to spend any money | Starvation, can't accomplish tasks |
|
||||
| **Progressive disclosure** | Check your pantry, make a shopping list, buy only what you need | Efficiency, room for unexpected needs |
|
||||
|
||||
### The Attention Budget
|
||||
|
||||
LLMs have finite attention:
|
||||
- Every token attends to every other token (n² relationships)
|
||||
- 100,000 token window ≠ 100,000 tokens of useful attention
|
||||
- Context "rot" happens as window fills
|
||||
- Later tokens get less attention than earlier ones
|
||||
|
||||
**Claude-Mem's approach:**
|
||||
- Start with ~1,000 tokens of index
|
||||
- Agent has 99,000 tokens free for task
|
||||
- Agent fetches ~200 tokens when needed
|
||||
- Final budget: ~98,000 tokens for actual work
|
||||
|
||||
### Design for Autonomy
|
||||
|
||||
> "As models improve, let them act intelligently"
|
||||
|
||||
Progressive disclosure treats the agent as an **intelligent information forager**, not a passive recipient of pre-selected context.
|
||||
|
||||
**Traditional RAG:**
|
||||
```
|
||||
System → [Decides relevance] → Agent
|
||||
↑
|
||||
Hope this helps!
|
||||
```
|
||||
|
||||
**Progressive Disclosure:**
|
||||
```
|
||||
System → [Shows index] → Agent → [Decides relevance] → [Fetches details]
|
||||
↑
|
||||
You know best!
|
||||
```
|
||||
|
||||
The agent knows:
|
||||
- The current task context
|
||||
- What information would help
|
||||
- How much budget to spend
|
||||
- When to stop searching
|
||||
|
||||
We don't.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Principles
|
||||
|
||||
### 1. Make Costs Visible
|
||||
|
||||
Every item in the index shows token count:
|
||||
|
||||
```
|
||||
| #2591 | 1:15 AM | ⚖️ | Stderr messaging abandoned | ~155 |
|
||||
^^^^
|
||||
Retrieval cost
|
||||
```
|
||||
|
||||
**Why:**
|
||||
- Agent can make informed ROI decisions
|
||||
- Small observations (~50 tokens) are "cheap" to fetch
|
||||
- Large observations (~500 tokens) require stronger justification
|
||||
- Matches how humans think about effort
|
||||
|
||||
### 2. Use Semantic Compression
|
||||
|
||||
Titles compress full observations into ~10 words:
|
||||
|
||||
**Bad title:**
|
||||
```
|
||||
Observation about a thing
|
||||
```
|
||||
|
||||
**Good title:**
|
||||
```
|
||||
🔴 Hook timeout issue: 60s default too short for npm install
|
||||
```
|
||||
|
||||
**What makes a good title:**
|
||||
- Specific: Identifies exact issue
|
||||
- Actionable: Clear what to do
|
||||
- Self-contained: Doesn't require reading observation
|
||||
- Searchable: Contains key terms (hook, timeout, npm)
|
||||
- Categorized: Icon indicates type
|
||||
|
||||
### 3. Group by Context
|
||||
|
||||
Observations are grouped by:
|
||||
- **Date**: Temporal context
|
||||
- **File path**: Spatial context (work on specific files)
|
||||
- **Project**: Logical context
|
||||
|
||||
```markdown
|
||||
**src/hooks/context-hook.ts**
|
||||
| ID | Time | T | Title | Tokens |
|
||||
|----|------|---|-------|--------|
|
||||
| #2591 | 1:15 AM | ⚖️ | Stderr messaging abandoned | ~155 |
|
||||
| #2594 | 1:17 AM | 🟠 | Removed stderr section from docs | ~93 |
|
||||
```
|
||||
|
||||
**Benefit:** If agent is working on `src/hooks/context-hook.ts`, related observations are already grouped together.
|
||||
|
||||
### 4. Provide Retrieval Tools
|
||||
|
||||
The index is useless without retrieval mechanisms:
|
||||
|
||||
```markdown
|
||||
*Use claude-mem MCP search to access records with the given ID*
|
||||
```
|
||||
|
||||
**Available tools:**
|
||||
- `search_observations` - Full-text search
|
||||
- `find_by_concept` - Concept-based retrieval
|
||||
- `find_by_file` - File-based retrieval
|
||||
- `find_by_type` - Type-based retrieval
|
||||
- `get_recent_context` - Recent session summaries
|
||||
|
||||
Each tool supports `format: "index"` (default) and `format: "full"`.
|
||||
|
||||
---
|
||||
|
||||
## Real-World Example
|
||||
|
||||
### Scenario: Agent asked to fix a bug in hooks
|
||||
|
||||
**Without progressive disclosure:**
|
||||
```
|
||||
SessionStart injects 25,000 tokens of past context
|
||||
Agent reads everything
|
||||
Agent finds 1 relevant observation (buried in middle)
|
||||
Total tokens consumed: 25,000
|
||||
Relevant tokens: ~200
|
||||
Efficiency: 0.8%
|
||||
```
|
||||
|
||||
**With progressive disclosure:**
|
||||
```
|
||||
SessionStart shows index: ~800 tokens
|
||||
Agent sees title: "🔴 Hook timeout issue: 60s too short"
|
||||
Agent thinks: "This looks relevant to my bug!"
|
||||
Agent fetches observation #2543: ~155 tokens
|
||||
Total tokens consumed: 955
|
||||
Relevant tokens: 955
|
||||
Efficiency: 100%
|
||||
```
|
||||
|
||||
### The Index Entry
|
||||
|
||||
```markdown
|
||||
| #2543 | 2:14 PM | 🔴 | Hook timeout: 60s too short for npm install | ~155 |
|
||||
```
|
||||
|
||||
**What the agent learns WITHOUT fetching:**
|
||||
- There's a known gotcha (🔴) about hook timeouts
|
||||
- It's related to npm install taking too long
|
||||
- Full details are ~155 tokens (cheap)
|
||||
- Happened at 2:14 PM (recent)
|
||||
|
||||
**Decision tree:**
|
||||
```
|
||||
Is my task related to hooks? → YES
|
||||
Is my task related to timeouts? → YES
|
||||
Is my task related to npm? → YES
|
||||
155 tokens is cheap → FETCH IT
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## The Two-Tier Search Strategy
|
||||
|
||||
Claude-Mem implements progressive disclosure in search results too:
|
||||
|
||||
### Tier 1: Index Format (Default)
|
||||
|
||||
```typescript
|
||||
search_observations({
|
||||
query: "hook timeout",
|
||||
format: "index" // Default
|
||||
})
|
||||
```
|
||||
|
||||
**Returns:**
|
||||
```
|
||||
Found 3 observations matching "hook timeout":
|
||||
|
||||
| ID | Date | Type | Title | Tokens |
|
||||
|----|------|------|-------|--------|
|
||||
| #2543 | Oct 26 | gotcha | Hook timeout: 60s too short | ~155 |
|
||||
| #2891 | Oct 25 | how-it-works | Hook timeout configuration | ~203 |
|
||||
| #2102 | Oct 20 | problem-solution | Fixed timeout in CI | ~89 |
|
||||
```
|
||||
|
||||
**Cost:** ~100 tokens for 3 results
|
||||
**Value:** Agent can scan and decide which to fetch
|
||||
|
||||
### Tier 2: Full Format (On-Demand)
|
||||
|
||||
```typescript
|
||||
search_observations({
|
||||
query: "hook timeout",
|
||||
format: "full",
|
||||
limit: 1 // Fetch just the most relevant
|
||||
})
|
||||
```
|
||||
|
||||
**Returns:**
|
||||
```
|
||||
#2543 🔴 Hook timeout: 60s too short for npm install
|
||||
─────────────────────────────────────────────────
|
||||
Date: Oct 26, 2025 2:14 PM
|
||||
Type: gotcha
|
||||
Project: claude-mem
|
||||
|
||||
Narrative:
|
||||
Discovered that the default 60-second hook timeout is insufficient
|
||||
for npm install operations, especially with large dependency trees
|
||||
or slow network conditions. This causes SessionStart hook to fail
|
||||
silently, preventing context injection.
|
||||
|
||||
Facts:
|
||||
- Default timeout: 60 seconds
|
||||
- npm install with cold cache: ~90 seconds
|
||||
- Configured timeout: 120 seconds in plugin/hooks/hooks.json:25
|
||||
|
||||
Files Modified:
|
||||
- plugin/hooks/hooks.json
|
||||
|
||||
Concepts: hooks, timeout, npm, configuration
|
||||
```
|
||||
|
||||
**Cost:** ~155 tokens for full details
|
||||
**Value:** Complete understanding of the issue
|
||||
|
||||
---
|
||||
|
||||
## Cognitive Load Theory
|
||||
|
||||
Progressive disclosure is grounded in **Cognitive Load Theory**:
|
||||
|
||||
### Intrinsic Load
|
||||
The inherent difficulty of the task itself.
|
||||
|
||||
**Example:** "Fix authentication bug"
|
||||
- Must understand auth system
|
||||
- Must understand the bug
|
||||
- Must write the fix
|
||||
|
||||
This load is unavoidable.
|
||||
|
||||
### Extraneous Load
|
||||
The cognitive burden of poorly presented information.
|
||||
|
||||
**Traditional RAG adds extraneous load:**
|
||||
- Scanning irrelevant observations
|
||||
- Filtering out noise
|
||||
- Remembering what to ignore
|
||||
- Re-contextualizing after each section
|
||||
|
||||
**Progressive disclosure minimizes extraneous load:**
|
||||
- Scan titles (low effort)
|
||||
- Fetch only relevant (targeted effort)
|
||||
- Full attention on current task
|
||||
|
||||
### Germane Load
|
||||
The effort of building mental models and schemas.
|
||||
|
||||
**Progressive disclosure supports germane load:**
|
||||
- Consistent structure (legend, grouping)
|
||||
- Clear categorization (types, icons)
|
||||
- Semantic compression (good titles)
|
||||
- Explicit costs (token counts)
|
||||
|
||||
---
|
||||
|
||||
## Anti-Patterns to Avoid
|
||||
|
||||
### ❌ Verbose Titles
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
| #2543 | 2:14 PM | 🔴 | Investigation into the issue where hooks time out | ~155 |
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```
|
||||
| #2543 | 2:14 PM | 🔴 | Hook timeout: 60s too short for npm install | ~155 |
|
||||
```
|
||||
|
||||
### ❌ Hiding Costs
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
| #2543 | 2:14 PM | 🔴 | Hook timeout issue |
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```
|
||||
| #2543 | 2:14 PM | 🔴 | Hook timeout issue | ~155 |
|
||||
```
|
||||
|
||||
### ❌ No Retrieval Path
|
||||
|
||||
**Bad:**
|
||||
```
|
||||
Here are 10 observations. [No instructions on how to get full details]
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```
|
||||
Here are 10 observations.
|
||||
*Use MCP search tools to fetch full observation details on-demand*
|
||||
```
|
||||
|
||||
### ❌ Defaulting to Full Format
|
||||
|
||||
**Bad:**
|
||||
```typescript
|
||||
search_observations({
|
||||
query: "hooks",
|
||||
format: "full" // Fetches everything
|
||||
})
|
||||
```
|
||||
|
||||
**Good:**
|
||||
```typescript
|
||||
search_observations({
|
||||
query: "hooks",
|
||||
format: "index", // Scan first
|
||||
limit: 20
|
||||
})
|
||||
|
||||
// Then, if needed:
|
||||
search_observations({
|
||||
query: "hooks",
|
||||
format: "full",
|
||||
limit: 1 // Just the most relevant
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Design Decisions
|
||||
|
||||
### Why Token Counts?
|
||||
|
||||
**Decision:** Show approximate token counts (~155, ~203) rather than exact counts.
|
||||
|
||||
**Rationale:**
|
||||
- Communicates scale (50 vs 500) without false precision
|
||||
- Maps to human intuition (small/medium/large)
|
||||
- Allows agent to budget attention
|
||||
- Encourages cost-conscious retrieval
|
||||
|
||||
### Why Icons Instead of Text Labels?
|
||||
|
||||
**Decision:** Use emoji icons (🔴, 🟡, 🔵) rather than text (GOTCHA, PROBLEM, HOWTO).
|
||||
|
||||
**Rationale:**
|
||||
- Visual scanning (pattern recognition)
|
||||
- Token efficient (1 char vs 10 chars)
|
||||
- Language-agnostic
|
||||
- Aesthetically distinct
|
||||
- Works for both humans and AI
|
||||
|
||||
### Why Index-First, Not Smart Pre-Fetch?
|
||||
|
||||
**Decision:** Always show index first, even if we "know" what's relevant.
|
||||
|
||||
**Rationale:**
|
||||
- We can't know what's relevant better than the agent
|
||||
- Pre-fetching assumes we understand the task
|
||||
- Agent knows current context, we don't
|
||||
- Respects agent autonomy
|
||||
- Fails gracefully (can always fetch more)
|
||||
|
||||
### Why Group by File Path?
|
||||
|
||||
**Decision:** Group observations by file path in addition to date.
|
||||
|
||||
**Rationale:**
|
||||
- Spatial locality: Work on file X likely needs context about file X
|
||||
- Reduces scanning effort
|
||||
- Matches how developers think
|
||||
- Clear semantic boundaries
|
||||
|
||||
---
|
||||
|
||||
## Measuring Success
|
||||
|
||||
Progressive disclosure is working when:
|
||||
|
||||
### ✅ Low Waste Ratio
|
||||
```
|
||||
Relevant Tokens / Total Context Tokens > 80%
|
||||
```
|
||||
|
||||
Most of the context consumed is actually useful.
|
||||
|
||||
### ✅ Selective Fetching
|
||||
```
|
||||
Index Shown: 50 observations
|
||||
Details Fetched: 2-3 observations
|
||||
```
|
||||
|
||||
Agent is being selective, not fetching everything.
|
||||
|
||||
### ✅ Fast Task Completion
|
||||
```
|
||||
Session with index: 30 seconds to find relevant context
|
||||
Session without: 90 seconds scanning all context
|
||||
```
|
||||
|
||||
Time-to-relevant-information is faster.
|
||||
|
||||
### ✅ Appropriate Depth
|
||||
```
|
||||
Simple task: Only index needed
|
||||
Medium task: 1-2 observations fetched
|
||||
Complex task: 5-10 observations + code reads
|
||||
```
|
||||
|
||||
Depth scales with task complexity.
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Adaptive Index Size
|
||||
|
||||
```typescript
|
||||
// Vary index size based on session type
|
||||
SessionStart({ source: "startup" }):
|
||||
→ Show last 10 sessions (small index)
|
||||
|
||||
SessionStart({ source: "resume" }):
|
||||
→ Show only current session (micro index)
|
||||
|
||||
SessionStart({ source: "compact" }):
|
||||
→ Show last 20 sessions (larger index)
|
||||
```
|
||||
|
||||
### Relevance Scoring
|
||||
|
||||
```typescript
|
||||
// Use embeddings to pre-sort index by relevance
|
||||
search_observations({
|
||||
query: "authentication bug",
|
||||
format: "index",
|
||||
sort: "relevance" // Based on semantic similarity
|
||||
})
|
||||
```
|
||||
|
||||
### Cost Forecasting
|
||||
|
||||
```markdown
|
||||
💡 **Budget Estimate:**
|
||||
- Fetching all 🔴 gotchas: ~450 tokens
|
||||
- Fetching all file-related: ~1,200 tokens
|
||||
- Fetching everything: ~8,500 tokens
|
||||
```
|
||||
|
||||
### Progressive Detail Levels
|
||||
|
||||
```
|
||||
Layer 1: Index (titles only)
|
||||
Layer 2: Summaries (2-3 sentences)
|
||||
Layer 3: Full details (complete observation)
|
||||
Layer 4: Source files (referenced code)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Show, don't tell**: Index reveals what exists without forcing consumption
|
||||
2. **Cost-conscious**: Make retrieval costs visible for informed decisions
|
||||
3. **Agent autonomy**: Let the agent decide what's relevant
|
||||
4. **Semantic compression**: Good titles make or break the system
|
||||
5. **Consistent structure**: Patterns reduce cognitive load
|
||||
6. **Two-tier everything**: Index first, details on-demand
|
||||
7. **Context as currency**: Spend wisely on high-value information
|
||||
|
||||
---
|
||||
|
||||
## Remember
|
||||
|
||||
> "The best interface is one that disappears when not needed, and appears exactly when it is."
|
||||
|
||||
Progressive disclosure respects the agent's intelligence and autonomy. We provide the map; the agent chooses the path.
|
||||
|
||||
---
|
||||
|
||||
## Further Reading
|
||||
|
||||
- [Context Engineering for AI Agents](context-engineering) - Foundational principles
|
||||
- [Claude-Mem Architecture](architecture/overview) - How it all fits together
|
||||
- Cognitive Load Theory (Sweller, 1988)
|
||||
- Information Foraging Theory (Pirolli & Card, 1999)
|
||||
- Progressive Disclosure (Nielsen Norman Group)
|
||||
|
||||
---
|
||||
|
||||
*This philosophy emerged from real-world usage of Claude-Mem across hundreds of coding sessions. The pattern works because it aligns with both human cognition and LLM attention mechanics.*
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 250 53" width="250" height="55" data-date-format="longDate">
|
||||
<rect xmlns="http://www.w3.org/2000/svg" stroke="#b5a0d9" stroke-width="1" fill="#1a1a1a" x="0.5" y="0.5" width="249" height="53" rx="10"/>
|
||||
<foreignObject width="198" height="17" style="font-size: 9px;color: rgb(200, 180, 230);font-family: Arial;font-weight: 400;text-align: center;letter-spacing: 0em;line-height: 1.5;" x="6" y="10" selection="true">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">GITHUB TRENDING</div>
|
||||
</foreignObject>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Слой_1" viewBox="0 0 80 80" width="48" height="45" x="10" y="8">
|
||||
<path fill="#b5a0d9" d="M70.71,40.31C75.74,44.3,80,37.86,80,37.86s-5.64-2.17-8.55,0.61c0.59-1.62,1.02-3.31,1.28-5.01 c4.08,2.16,6.44-2.95,6.44-2.95s-4.41-0.97-6.26,1.4c0.08-0.91,0.12-1.82,0.1-2.73c-0.01-0.36-0.02-0.73-0.05-1.09 c2.96-3.68-1.73-6.99-1.73-6.99s-2.14,5.09,0.98,7.09c0.02,0.33,0.03,0.66,0.03,1c0.01,0.76-0.03,1.52-0.1,2.27 c-0.85-2.69-4.91-3.69-4.91-3.69s-0.13,5.78,4.68,5.48c-0.28,1.69-0.73,3.35-1.34,4.95c-0.19-4.03-5.79-6.33-5.79-6.33 s-1.33,7.55,5.01,8.16c-0.38,0.8-0.8,1.57-1.25,2.32c-0.56,0.95-1.21,1.84-1.89,2.71c0.97-3.99-3.96-7.72-3.96-7.72 s-3.18,6.94,2.73,9.15c-0.38,0.43-0.8,0.81-1.2,1.21c-0.21,0.2-0.43,0.38-0.64,0.58l-0.32,0.29c-0.11,0.09-0.22,0.18-0.33,0.27 l-0.67,0.54l-0.7,0.51c-0.08,0.05-0.16,0.11-0.23,0.16c1.62-3.42-2.07-7.77-2.07-7.77s-4.21,5.55,0.49,8.78 c-1.34,0.79-2.74,1.45-4.2,1.98c1.91-2.59-0.23-6.89-0.23-6.89s-4.66,3.77-1.52,7.46c-1.15,0.33-2.33,0.57-3.51,0.74 c1.46-1.68,0.55-4.83,0.55-4.83s-3.7,2.03-2.18,5c-0.52,0.03-1.05,0.07-1.57,0.06c-0.29,0-0.57,0.01-0.86,0l-0.86-0.04 c-0.85-0.06-1.7-0.15-2.54-0.28l0.68-0.27l0.42-0.17l0.41-0.19l0.82-0.38c0,0,0.01,0,0.01,0c0.39-0.18,0.55-0.65,0.37-1.03 c-0.18-0.39-0.65-0.55-1.03-0.37l-0.04,0.02l-0.77,0.37l-0.39,0.18l-0.39,0.16l-0.79,0.33l-0.8,0.29l-0.4,0.14l-0.41,0.12L40,53.6 l-0.51-0.15l-0.41-0.12l-0.4-0.14l-0.8-0.29l-0.79-0.33l-0.39-0.16l-0.39-0.18l-0.77-0.37l-0.04-0.02c0,0,0,0-0.01,0 c-0.39-0.18-0.85-0.01-1.03,0.38c-0.18,0.39-0.01,0.85,0.38,1.03l0.82,0.38l0.41,0.19l0.42,0.17l0.68,0.27 c-0.84,0.14-1.69,0.22-2.54,0.28l-0.86,0.04c-0.29,0.01-0.57,0-0.86,0c-0.53,0.01-1.05-0.03-1.57-0.06c1.51-2.98-2.18-5-2.18-5 s-0.92,3.15,0.55,4.83c-1.19-0.16-2.36-0.41-3.51-0.74c3.15-3.7-1.52-7.46-1.52-7.46s-2.14,4.31-0.23,6.89 c-1.46-0.53-2.86-1.19-4.2-1.98c4.7-3.22,0.49-8.78,0.49-8.78s-3.69,4.34-2.07,7.77c-0.08-0.05-0.16-0.1-0.23-0.16l-0.7-0.51 l-0.67-0.54c-0.11-0.09-0.23-0.18-0.33-0.27l-0.32-0.29c-0.21-0.19-0.43-0.38-0.64-0.58c-0.4-0.4-0.82-0.79-1.2-1.21 c5.91-2.21,2.73-9.15,2.73-9.15s-4.93,3.73-3.96,7.72c-0.68-0.86-1.33-1.76-1.89-2.71c-0.46-0.75-0.87-1.53-1.25-2.32 c6.33-0.61,5.01-8.16,5.01-8.16s-5.6,2.31-5.79,6.33c-0.61-1.6-1.06-3.26-1.34-4.95c4.81,0.3,4.68-5.48,4.68-5.48 s-4.05,0.99-4.91,3.69c-0.07-0.76-0.1-1.51-0.1-2.27c0-0.33,0.01-0.66,0.03-1c3.11-2.01,0.98-7.09,0.98-7.09s-4.69,3.31-1.73,6.99 C7,28.46,6.99,28.82,6.98,29.18c-0.02,0.91,0.01,1.82,0.1,2.73c-1.84-2.38-6.26-1.4-6.26-1.4s2.37,5.11,6.44,2.95 c0.26,1.71,0.69,3.39,1.28,5.01C5.64,35.69,0,37.86,0,37.86s4.26,6.43,9.29,2.45c0.39,0.87,0.83,1.72,1.31,2.54 c0.47,0.83,1.01,1.63,1.58,2.4C8.71,43.7,4.11,47,4.11,47s5.7,5.1,9.56,0.08c0.04,0.04,0.07,0.08,0.11,0.12 c0.39,0.45,0.82,0.87,1.24,1.3c0.21,0.21,0.44,0.41,0.66,0.61l0.33,0.3c0.11,0.1,0.23,0.19,0.34,0.29l0.69,0.57l0.23,0.17 c-3.34-0.34-6.58,3.29-6.58,3.29s6.19,3.47,8.69-1.83c1.2,0.75,2.47,1.41,3.78,1.96c-2.76,0.6-4.62,4.13-4.62,4.13 s5.89,1.62,6.98-3.26c1.03,0.32,2.07,0.58,3.13,0.78c-1.63,0.99-2.39,3.38-2.39,3.38s4.31,0.39,4.61-3.07 c0.07,0.01,0.14,0.02,0.21,0.02c0.6,0.04,1.2,0.1,1.8,0.09c0.3,0,0.6,0.02,0.9,0.01l0.9-0.03c1.2-0.07,2.41-0.18,3.59-0.42 l0.45-0.08c0.15-0.03,0.29-0.07,0.44-0.1L40,55.13l0.81,0.19c0.15,0.03,0.29,0.07,0.44,0.1l0.45,0.08c1.18,0.23,2.39,0.35,3.59,0.42 l0.9,0.03c0.3,0.01,0.6-0.01,0.9-0.01c0.6,0,1.2-0.06,1.8-0.09c0.07-0.01,0.14-0.02,0.21-0.02c0.31,3.45,4.61,3.07,4.61,3.07 s-0.76-2.39-2.39-3.38c1.06-0.2,2.11-0.46,3.13-0.78c1.09,4.88,6.98,3.26,6.98,3.26s-1.86-3.52-4.62-4.13 c1.31-0.55,2.57-1.21,3.78-1.96c2.5,5.3,8.69,1.83,8.69,1.83s-3.24-3.63-6.58-3.29l0.23-0.17l0.69-0.57 c0.11-0.1,0.23-0.19,0.34-0.29l0.33-0.3c0.22-0.2,0.45-0.4,0.66-0.61c0.42-0.43,0.85-0.84,1.24-1.3c0.03-0.04,0.07-0.08,0.11-0.12 C70.19,52.1,75.89,47,75.89,47s-4.6-3.31-8.08-1.75c0.57-0.77,1.11-1.56,1.58-2.4C69.88,42.03,70.31,41.18,70.71,40.31z"/>
|
||||
</svg>
|
||||
<foreignObject width="230" height="35" style="font-size: 14px;color: rgb(200, 180, 230);font-family: Arial;font-weight: 700;text-align: left;letter-spacing: 0em;line-height: 1.5;" x="64" y="24">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">#1 Repository Of The Day</div>
|
||||
</foreignObject>
|
||||
<foreignObject width="141" height="36" style="font-size: 18px;color: rgb(180, 160, 217);font-family: Arial;font-weight: 400;text-align: center;letter-spacing: 0em;line-height: 1.5;" x="-36" y="9">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">1</div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 250 53" width="250" height="55" data-date-format="longDate">
|
||||
<rect xmlns="http://www.w3.org/2000/svg" stroke="#4a0e99" stroke-width="1" fill="#FFFFFF" x="0.5" y="0.5" width="249" height="53" rx="10"/>
|
||||
<foreignObject width="198" height="17" style="font-size: 9px;color: rgb(67, 39, 135);font-family: Arial;font-weight: 400;text-align: center;letter-spacing: 0em;line-height: 1.5;" x="6" y="10" selection="true">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">GITHUB TRENDING</div>
|
||||
</foreignObject>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Слой_1" viewBox="0 0 80 80" width="48" height="45" x="10" y="8">
|
||||
<path fill="#49278e" d="M70.71,40.31C75.74,44.3,80,37.86,80,37.86s-5.64-2.17-8.55,0.61c0.59-1.62,1.02-3.31,1.28-5.01 c4.08,2.16,6.44-2.95,6.44-2.95s-4.41-0.97-6.26,1.4c0.08-0.91,0.12-1.82,0.1-2.73c-0.01-0.36-0.02-0.73-0.05-1.09 c2.96-3.68-1.73-6.99-1.73-6.99s-2.14,5.09,0.98,7.09c0.02,0.33,0.03,0.66,0.03,1c0.01,0.76-0.03,1.52-0.1,2.27 c-0.85-2.69-4.91-3.69-4.91-3.69s-0.13,5.78,4.68,5.48c-0.28,1.69-0.73,3.35-1.34,4.95c-0.19-4.03-5.79-6.33-5.79-6.33 s-1.33,7.55,5.01,8.16c-0.38,0.8-0.8,1.57-1.25,2.32c-0.56,0.95-1.21,1.84-1.89,2.71c0.97-3.99-3.96-7.72-3.96-7.72 s-3.18,6.94,2.73,9.15c-0.38,0.43-0.8,0.81-1.2,1.21c-0.21,0.2-0.43,0.38-0.64,0.58l-0.32,0.29c-0.11,0.09-0.22,0.18-0.33,0.27 l-0.67,0.54l-0.7,0.51c-0.08,0.05-0.16,0.11-0.23,0.16c1.62-3.42-2.07-7.77-2.07-7.77s-4.21,5.55,0.49,8.78 c-1.34,0.79-2.74,1.45-4.2,1.98c1.91-2.59-0.23-6.89-0.23-6.89s-4.66,3.77-1.52,7.46c-1.15,0.33-2.33,0.57-3.51,0.74 c1.46-1.68,0.55-4.83,0.55-4.83s-3.7,2.03-2.18,5c-0.52,0.03-1.05,0.07-1.57,0.06c-0.29,0-0.57,0.01-0.86,0l-0.86-0.04 c-0.85-0.06-1.7-0.15-2.54-0.28l0.68-0.27l0.42-0.17l0.41-0.19l0.82-0.38c0,0,0.01,0,0.01,0c0.39-0.18,0.55-0.65,0.37-1.03 c-0.18-0.39-0.65-0.55-1.03-0.37l-0.04,0.02l-0.77,0.37l-0.39,0.18l-0.39,0.16l-0.79,0.33l-0.8,0.29l-0.4,0.14l-0.41,0.12L40,53.6 l-0.51-0.15l-0.41-0.12l-0.4-0.14l-0.8-0.29l-0.79-0.33l-0.39-0.16l-0.39-0.18l-0.77-0.37l-0.04-0.02c0,0,0,0-0.01,0 c-0.39-0.18-0.85-0.01-1.03,0.38c-0.18,0.39-0.01,0.85,0.38,1.03l0.82,0.38l0.41,0.19l0.42,0.17l0.68,0.27 c-0.84,0.14-1.69,0.22-2.54,0.28l-0.86,0.04c-0.29,0.01-0.57,0-0.86,0c-0.53,0.01-1.05-0.03-1.57-0.06c1.51-2.98-2.18-5-2.18-5 s-0.92,3.15,0.55,4.83c-1.19-0.16-2.36-0.41-3.51-0.74c3.15-3.7-1.52-7.46-1.52-7.46s-2.14,4.31-0.23,6.89 c-1.46-0.53-2.86-1.19-4.2-1.98c4.7-3.22,0.49-8.78,0.49-8.78s-3.69,4.34-2.07,7.77c-0.08-0.05-0.16-0.1-0.23-0.16l-0.7-0.51 l-0.67-0.54c-0.11-0.09-0.23-0.18-0.33-0.27l-0.32-0.29c-0.21-0.19-0.43-0.38-0.64-0.58c-0.4-0.4-0.82-0.79-1.2-1.21 c5.91-2.21,2.73-9.15,2.73-9.15s-4.93,3.73-3.96,7.72c-0.68-0.86-1.33-1.76-1.89-2.71c-0.46-0.75-0.87-1.53-1.25-2.32 c6.33-0.61,5.01-8.16,5.01-8.16s-5.6,2.31-5.79,6.33c-0.61-1.6-1.06-3.26-1.34-4.95c4.81,0.3,4.68-5.48,4.68-5.48 s-4.05,0.99-4.91,3.69c-0.07-0.76-0.1-1.51-0.1-2.27c0-0.33,0.01-0.66,0.03-1c3.11-2.01,0.98-7.09,0.98-7.09s-4.69,3.31-1.73,6.99 C7,28.46,6.99,28.82,6.98,29.18c-0.02,0.91,0.01,1.82,0.1,2.73c-1.84-2.38-6.26-1.4-6.26-1.4s2.37,5.11,6.44,2.95 c0.26,1.71,0.69,3.39,1.28,5.01C5.64,35.69,0,37.86,0,37.86s4.26,6.43,9.29,2.45c0.39,0.87,0.83,1.72,1.31,2.54 c0.47,0.83,1.01,1.63,1.58,2.4C8.71,43.7,4.11,47,4.11,47s5.7,5.1,9.56,0.08c0.04,0.04,0.07,0.08,0.11,0.12 c0.39,0.45,0.82,0.87,1.24,1.3c0.21,0.21,0.44,0.41,0.66,0.61l0.33,0.3c0.11,0.1,0.23,0.19,0.34,0.29l0.69,0.57l0.23,0.17 c-3.34-0.34-6.58,3.29-6.58,3.29s6.19,3.47,8.69-1.83c1.2,0.75,2.47,1.41,3.78,1.96c-2.76,0.6-4.62,4.13-4.62,4.13 s5.89,1.62,6.98-3.26c1.03,0.32,2.07,0.58,3.13,0.78c-1.63,0.99-2.39,3.38-2.39,3.38s4.31,0.39,4.61-3.07 c0.07,0.01,0.14,0.02,0.21,0.02c0.6,0.04,1.2,0.1,1.8,0.09c0.3,0,0.6,0.02,0.9,0.01l0.9-0.03c1.2-0.07,2.41-0.18,3.59-0.42 l0.45-0.08c0.15-0.03,0.29-0.07,0.44-0.1L40,55.13l0.81,0.19c0.15,0.03,0.29,0.07,0.44,0.1l0.45,0.08c1.18,0.23,2.39,0.35,3.59,0.42 l0.9,0.03c0.3,0.01,0.6-0.01,0.9-0.01c0.6,0,1.2-0.06,1.8-0.09c0.07-0.01,0.14-0.02,0.21-0.02c0.31,3.45,4.61,3.07,4.61,3.07 s-0.76-2.39-2.39-3.38c1.06-0.2,2.11-0.46,3.13-0.78c1.09,4.88,6.98,3.26,6.98,3.26s-1.86-3.52-4.62-4.13 c1.31-0.55,2.57-1.21,3.78-1.96c2.5,5.3,8.69,1.83,8.69,1.83s-3.24-3.63-6.58-3.29l0.23-0.17l0.69-0.57 c0.11-0.1,0.23-0.19,0.34-0.29l0.33-0.3c0.22-0.2,0.45-0.4,0.66-0.61c0.42-0.43,0.85-0.84,1.24-1.3c0.03-0.04,0.07-0.08,0.11-0.12 C70.19,52.1,75.89,47,75.89,47s-4.6-3.31-8.08-1.75c0.57-0.77,1.11-1.56,1.58-2.4C69.88,42.03,70.31,41.18,70.71,40.31z"/>
|
||||
</svg>
|
||||
<foreignObject width="230" height="35" style="font-size: 14px;color: rgb(67, 39, 135);font-family: Arial;font-weight: 700;text-align: left;letter-spacing: 0em;line-height: 1.5;" x="64" y="24">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">#1 Repository Of The Day</div>
|
||||
</foreignObject>
|
||||
<foreignObject width="141" height="36" style="font-size: 18px;color: rgb(74, 14, 153);font-family: Arial;font-weight: 400;text-align: center;letter-spacing: 0em;line-height: 1.5;" x="-36" y="9">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">1</div>
|
||||
</foreignObject>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.1 KiB |
@@ -0,0 +1,830 @@
|
||||
---
|
||||
title: "Troubleshooting"
|
||||
description: "Common issues and solutions for Claude-Mem"
|
||||
---
|
||||
|
||||
# Troubleshooting Guide
|
||||
|
||||
## Quick Diagnostic Tool
|
||||
|
||||
Describe any issues you're experiencing to Claude, and the troubleshoot skill will automatically activate to provide diagnosis and fixes.
|
||||
|
||||
The troubleshoot skill will:
|
||||
- ✅ Check worker status and health
|
||||
- ✅ Verify database existence and integrity
|
||||
- ✅ Test worker service connectivity
|
||||
- ✅ Validate dependencies installation
|
||||
- ✅ Check port configuration and availability
|
||||
- ✅ Provide automated fixes for common issues
|
||||
|
||||
The skill includes comprehensive diagnostics, automated repair sequences, and detailed troubleshooting workflows for all common issues. Simply describe the problem naturally to invoke it.
|
||||
|
||||
---
|
||||
|
||||
## v5.x Specific Issues
|
||||
|
||||
### Viewer UI Not Loading
|
||||
|
||||
**Symptoms**: Cannot access http://localhost:37777, page doesn't load, or shows connection error.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check if worker is running on port 37777:
|
||||
```bash
|
||||
lsof -i :37777
|
||||
# or
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
2. Verify worker is healthy:
|
||||
```bash
|
||||
curl http://localhost:37777/health
|
||||
```
|
||||
|
||||
3. Check worker logs for errors:
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
4. Restart worker service:
|
||||
```bash
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
5. Check for port conflicts:
|
||||
```bash
|
||||
# If port 37777 is in use by another service
|
||||
export CLAUDE_MEM_WORKER_PORT=38000
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
### Theme Toggle Not Persisting
|
||||
|
||||
**Symptoms**: Theme preference (light/dark mode) resets after browser refresh.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check browser localStorage is enabled:
|
||||
```javascript
|
||||
// In browser console
|
||||
localStorage.getItem('claude-mem-settings')
|
||||
```
|
||||
|
||||
2. Verify settings endpoint is working:
|
||||
```bash
|
||||
curl http://localhost:37777/api/settings
|
||||
```
|
||||
|
||||
3. Clear localStorage and try again:
|
||||
```javascript
|
||||
// In browser console
|
||||
localStorage.removeItem('claude-mem-settings')
|
||||
```
|
||||
|
||||
4. Check for browser privacy mode (blocks localStorage)
|
||||
|
||||
### SSE Connection Issues
|
||||
|
||||
**Symptoms**: Viewer shows "Disconnected" status, updates not appearing in real-time.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check SSE endpoint is accessible:
|
||||
```bash
|
||||
curl -N http://localhost:37777/stream
|
||||
```
|
||||
|
||||
2. Check browser console for errors:
|
||||
- Open DevTools (F12)
|
||||
- Look for EventSource errors
|
||||
- Check Network tab for failed /stream requests
|
||||
|
||||
3. Verify worker is running:
|
||||
```bash
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
4. Check for network/proxy issues blocking SSE
|
||||
- Corporate firewalls may block SSE
|
||||
- Try disabling VPN temporarily
|
||||
|
||||
5. Restart worker and refresh browser:
|
||||
```bash
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
### Chroma/Python Dependency Issues (v5.0.0+)
|
||||
|
||||
**Symptoms**: Installation fails with chromadb or Python-related errors.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Verify Python 3.8+ is installed:
|
||||
```bash
|
||||
python --version
|
||||
# or
|
||||
python3 --version
|
||||
```
|
||||
|
||||
2. Install chromadb manually:
|
||||
```bash
|
||||
cd ~/.claude/plugins/marketplaces/thedotmack
|
||||
npm install chromadb
|
||||
```
|
||||
|
||||
3. Check chromadb health:
|
||||
```bash
|
||||
npm run chroma:health
|
||||
```
|
||||
|
||||
4. Windows-specific: Ensure Python is in PATH:
|
||||
```bash
|
||||
where python
|
||||
# Should show Python installation path
|
||||
```
|
||||
|
||||
5. If Chroma continues to fail, hybrid search will gracefully degrade to SQLite FTS5 only
|
||||
|
||||
### Smart Install Caching Issues (v5.0.3+)
|
||||
|
||||
**Symptoms**: Dependencies not updating after plugin update, stale version marker.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Clear install cache:
|
||||
```bash
|
||||
rm ~/.claude/plugins/marketplaces/thedotmack/.install-version
|
||||
```
|
||||
|
||||
2. Force reinstall:
|
||||
```bash
|
||||
cd ~/.claude/plugins/marketplaces/thedotmack
|
||||
npm install --force
|
||||
```
|
||||
|
||||
3. Check version marker:
|
||||
```bash
|
||||
cat ~/.claude/plugins/marketplaces/thedotmack/.install-version
|
||||
cat ~/.claude/plugins/marketplaces/thedotmack/package.json | grep version
|
||||
```
|
||||
|
||||
4. Restart Claude Code after manual install
|
||||
|
||||
|
||||
## Worker Service Issues
|
||||
|
||||
### Worker Service Not Starting
|
||||
|
||||
**Symptoms**: Worker doesn't start, or worker status shows it's not running.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check worker status:
|
||||
```bash
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
2. Try starting manually:
|
||||
```bash
|
||||
npm run worker:start
|
||||
```
|
||||
|
||||
3. Check worker logs for errors:
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
4. Full reset:
|
||||
```bash
|
||||
npm run worker:stop
|
||||
npm run worker:start
|
||||
```
|
||||
|
||||
5. Verify Bun is installed:
|
||||
```bash
|
||||
which bun
|
||||
bun --version
|
||||
```
|
||||
|
||||
### Port Allocation Failed
|
||||
|
||||
**Symptoms**: Worker fails to start with "port already in use" error.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check if port 37777 is in use:
|
||||
```bash
|
||||
lsof -i :37777
|
||||
```
|
||||
|
||||
2. Kill process using the port:
|
||||
```bash
|
||||
kill -9 $(lsof -t -i:37777)
|
||||
```
|
||||
|
||||
3. Or use a different port:
|
||||
```bash
|
||||
export CLAUDE_MEM_WORKER_PORT=38000
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
4. Verify new port:
|
||||
```bash
|
||||
cat ~/.claude-mem/worker.port
|
||||
```
|
||||
|
||||
### Worker Keeps Crashing
|
||||
|
||||
**Symptoms**: Worker restarts repeatedly or fails to stay running.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check error logs:
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
2. Check worker status:
|
||||
```bash
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
3. Check database for corruption:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"
|
||||
```
|
||||
|
||||
4. Verify Bun installation:
|
||||
```bash
|
||||
bun --version
|
||||
```
|
||||
|
||||
### Worker Not Processing Observations
|
||||
|
||||
**Symptoms**: Observations saved but not processed, no summaries generated.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check worker is running:
|
||||
```bash
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
2. Check worker logs:
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
3. Verify database has observations:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations;"
|
||||
```
|
||||
|
||||
4. Restart worker:
|
||||
```bash
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
## Hook Issues
|
||||
|
||||
### Hooks Not Firing
|
||||
|
||||
**Symptoms**: No context appears, observations not saved.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Verify hooks are configured:
|
||||
```bash
|
||||
cat plugin/hooks/hooks.json
|
||||
```
|
||||
|
||||
2. Test hooks manually:
|
||||
```bash
|
||||
# Test context hook
|
||||
echo '{"session_id":"test-123","cwd":"'$(pwd)'","source":"startup"}' | node plugin/scripts/context-hook.js
|
||||
```
|
||||
|
||||
3. Check hook permissions:
|
||||
```bash
|
||||
ls -la plugin/scripts/*.js
|
||||
```
|
||||
|
||||
4. Verify hooks.json is valid JSON:
|
||||
```bash
|
||||
cat plugin/hooks/hooks.json | jq .
|
||||
```
|
||||
|
||||
### Context Not Appearing
|
||||
|
||||
**Symptoms**: No session context when Claude starts.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check if summaries exist:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM session_summaries;"
|
||||
```
|
||||
|
||||
2. View recent sessions:
|
||||
```bash
|
||||
npm run test:context:verbose
|
||||
```
|
||||
|
||||
3. Check database integrity:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"
|
||||
```
|
||||
|
||||
4. Manually test context hook:
|
||||
```bash
|
||||
npm run test:context
|
||||
```
|
||||
|
||||
### Hooks Timeout
|
||||
|
||||
**Symptoms**: Hook execution times out, errors in Claude Code.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Increase timeout in `plugin/hooks/hooks.json`:
|
||||
```json
|
||||
{
|
||||
"timeout": 180 // Increase from 120
|
||||
}
|
||||
```
|
||||
|
||||
2. Check worker is running (prevents timeout waiting for worker):
|
||||
```bash
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
3. Check database size (large database = slow queries):
|
||||
```bash
|
||||
ls -lh ~/.claude-mem/claude-mem.db
|
||||
```
|
||||
|
||||
4. Optimize database:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "VACUUM;"
|
||||
```
|
||||
|
||||
### Dependencies Not Installing
|
||||
|
||||
**Symptoms**: SessionStart hook fails with "module not found" errors.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Manually install dependencies:
|
||||
```bash
|
||||
cd ~/.claude/plugins/marketplaces/thedotmack
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Check npm is available:
|
||||
```bash
|
||||
which npm
|
||||
npm --version
|
||||
```
|
||||
|
||||
3. Check package.json exists:
|
||||
```bash
|
||||
ls -la ~/.claude/plugins/marketplaces/thedotmack/package.json
|
||||
```
|
||||
|
||||
## Database Issues
|
||||
|
||||
### Database Locked
|
||||
|
||||
**Symptoms**: "database is locked" errors in logs.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Close all connections:
|
||||
```bash
|
||||
npm run worker:stop
|
||||
```
|
||||
|
||||
2. Check for stale locks:
|
||||
```bash
|
||||
lsof ~/.claude-mem/claude-mem.db
|
||||
```
|
||||
|
||||
3. Kill processes holding locks:
|
||||
```bash
|
||||
kill -9 <PID>
|
||||
```
|
||||
|
||||
4. Restart worker:
|
||||
```bash
|
||||
npm run worker:start
|
||||
```
|
||||
|
||||
### Database Corruption
|
||||
|
||||
**Symptoms**: Integrity check fails, weird errors.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check database integrity:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "PRAGMA integrity_check;"
|
||||
```
|
||||
|
||||
2. Backup database:
|
||||
```bash
|
||||
cp ~/.claude-mem/claude-mem.db ~/.claude-mem/claude-mem.db.backup
|
||||
```
|
||||
|
||||
3. Try to repair:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "VACUUM;"
|
||||
```
|
||||
|
||||
4. Nuclear option - recreate database:
|
||||
```bash
|
||||
rm ~/.claude-mem/claude-mem.db
|
||||
npm run worker:start # Will recreate schema
|
||||
```
|
||||
|
||||
### FTS5 Search Not Working
|
||||
|
||||
**Symptoms**: Search returns no results, FTS5 errors.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check FTS5 tables exist:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT name FROM sqlite_master WHERE type='table' AND name LIKE '%_fts';"
|
||||
```
|
||||
|
||||
2. Rebuild FTS5 tables:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "
|
||||
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
||||
INSERT INTO session_summaries_fts(session_summaries_fts) VALUES('rebuild');
|
||||
INSERT INTO user_prompts_fts(user_prompts_fts) VALUES('rebuild');
|
||||
"
|
||||
```
|
||||
|
||||
3. Check triggers exist:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT name FROM sqlite_master WHERE type='trigger';"
|
||||
```
|
||||
|
||||
### Database Too Large
|
||||
|
||||
**Symptoms**: Slow performance, large database file.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check database size:
|
||||
```bash
|
||||
ls -lh ~/.claude-mem/claude-mem.db
|
||||
```
|
||||
|
||||
2. Vacuum database:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "VACUUM;"
|
||||
```
|
||||
|
||||
3. Delete old sessions:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "
|
||||
DELETE FROM observations WHERE created_at_epoch < $(date -v-30d +%s);
|
||||
DELETE FROM session_summaries WHERE created_at_epoch < $(date -v-30d +%s);
|
||||
DELETE FROM sdk_sessions WHERE created_at_epoch < $(date -v-30d +%s);
|
||||
"
|
||||
```
|
||||
|
||||
4. Rebuild FTS5 after deletion:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "
|
||||
INSERT INTO observations_fts(observations_fts) VALUES('rebuild');
|
||||
INSERT INTO session_summaries_fts(session_summaries_fts) VALUES('rebuild');
|
||||
"
|
||||
```
|
||||
|
||||
## MCP Search Issues
|
||||
|
||||
### Search Tools Not Available
|
||||
|
||||
**Symptoms**: MCP search tools not visible in Claude Code.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check MCP configuration:
|
||||
```bash
|
||||
cat plugin/.mcp.json
|
||||
```
|
||||
|
||||
2. Verify search server is built:
|
||||
```bash
|
||||
ls -l plugin/scripts/mcp-server.cjs
|
||||
```
|
||||
|
||||
3. Rebuild if needed:
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
4. Restart Claude Code
|
||||
|
||||
### Search Returns No Results
|
||||
|
||||
**Symptoms**: Valid queries return empty results.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check database has data:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations;"
|
||||
```
|
||||
|
||||
2. Verify FTS5 tables populated:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations_fts;"
|
||||
```
|
||||
|
||||
3. Test simple query:
|
||||
```bash
|
||||
# In Claude Code
|
||||
search_observations with query="test"
|
||||
```
|
||||
|
||||
4. Check query syntax:
|
||||
```bash
|
||||
# Bad: Special characters
|
||||
search_observations with query="[test]"
|
||||
|
||||
# Good: Simple words
|
||||
search_observations with query="test"
|
||||
```
|
||||
|
||||
### Token Limit Errors
|
||||
|
||||
**Symptoms**: "exceeded token limit" errors from MCP.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Use index format:
|
||||
```bash
|
||||
search_observations with query="..." and format="index"
|
||||
```
|
||||
|
||||
2. Reduce limit:
|
||||
```bash
|
||||
search_observations with query="..." and limit=3
|
||||
```
|
||||
|
||||
3. Use filters to narrow results:
|
||||
```bash
|
||||
search_observations with query="..." and type="decision" and limit=5
|
||||
```
|
||||
|
||||
4. Paginate results:
|
||||
```bash
|
||||
# First page
|
||||
search_observations with query="..." and limit=5 and offset=0
|
||||
|
||||
# Second page
|
||||
search_observations with query="..." and limit=5 and offset=5
|
||||
```
|
||||
|
||||
## Performance Issues
|
||||
|
||||
### Slow Context Injection
|
||||
|
||||
**Symptoms**: SessionStart hook takes too long.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Reduce context sessions:
|
||||
```typescript
|
||||
// In src/hooks/context.ts
|
||||
const CONTEXT_SESSIONS = 5; // Reduce from 10
|
||||
```
|
||||
|
||||
2. Optimize database:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "
|
||||
ANALYZE;
|
||||
VACUUM;
|
||||
"
|
||||
```
|
||||
|
||||
3. Add indexes (if missing):
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "
|
||||
CREATE INDEX IF NOT EXISTS idx_sessions_project_created ON sdk_sessions(project, created_at_epoch DESC);
|
||||
"
|
||||
```
|
||||
|
||||
### Slow Search Queries
|
||||
|
||||
**Symptoms**: MCP search tools take too long.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Use more specific queries
|
||||
2. Add date range filters
|
||||
3. Add type/concept filters
|
||||
4. Reduce result limit
|
||||
5. Use index format instead of full format
|
||||
|
||||
### High Memory Usage
|
||||
|
||||
**Symptoms**: Worker uses too much memory.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Check current usage:
|
||||
```bash
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
2. Restart worker:
|
||||
```bash
|
||||
npm run worker:restart
|
||||
```
|
||||
|
||||
3. Clean up old data (see "Database Too Large" above)
|
||||
|
||||
## Installation Issues
|
||||
|
||||
### Plugin Not Found
|
||||
|
||||
**Symptoms**: `/plugin install claude-mem` fails.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Add marketplace first:
|
||||
```bash
|
||||
/plugin marketplace add thedotmack/claude-mem
|
||||
```
|
||||
|
||||
2. Then install:
|
||||
```bash
|
||||
/plugin install claude-mem
|
||||
```
|
||||
|
||||
3. Verify installation:
|
||||
```bash
|
||||
ls -la ~/.claude/plugins/marketplaces/thedotmack/
|
||||
```
|
||||
|
||||
### Build Failures
|
||||
|
||||
**Symptoms**: `npm run build` fails.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Clean and reinstall:
|
||||
```bash
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Check Node.js version:
|
||||
```bash
|
||||
node --version # Should be >= 18.0.0
|
||||
```
|
||||
|
||||
3. Check for TypeScript errors:
|
||||
```bash
|
||||
npx tsc --noEmit
|
||||
```
|
||||
|
||||
### Missing Dependencies
|
||||
|
||||
**Symptoms**: "Cannot find module" errors.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. Check package.json:
|
||||
```bash
|
||||
cat package.json
|
||||
```
|
||||
|
||||
3. Verify node_modules exists:
|
||||
```bash
|
||||
ls -la node_modules/
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
### Enable Verbose Logging
|
||||
|
||||
```bash
|
||||
export DEBUG=claude-mem:*
|
||||
npm run worker:restart
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
### Check Correlation IDs
|
||||
|
||||
Trace observations through the pipeline:
|
||||
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "
|
||||
SELECT correlation_id, tool_name, created_at
|
||||
FROM observations
|
||||
WHERE session_id = 'YOUR_SESSION_ID'
|
||||
ORDER BY created_at;
|
||||
"
|
||||
```
|
||||
|
||||
### Inspect Worker State
|
||||
|
||||
```bash
|
||||
# Check if worker is running
|
||||
npm run worker:status
|
||||
|
||||
# View logs
|
||||
npm run worker:logs
|
||||
|
||||
# Check port file
|
||||
cat ~/.claude-mem/worker.port
|
||||
|
||||
# Test worker health
|
||||
curl http://localhost:37777/health
|
||||
```
|
||||
|
||||
### Database Inspection
|
||||
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db
|
||||
|
||||
# View schema
|
||||
.schema
|
||||
|
||||
# Check table counts
|
||||
SELECT 'sessions', COUNT(*) FROM sdk_sessions
|
||||
UNION ALL
|
||||
SELECT 'observations', COUNT(*) FROM observations
|
||||
UNION ALL
|
||||
SELECT 'summaries', COUNT(*) FROM session_summaries
|
||||
UNION ALL
|
||||
SELECT 'prompts', COUNT(*) FROM user_prompts;
|
||||
|
||||
# View recent activity
|
||||
SELECT created_at, tool_name FROM observations ORDER BY created_at DESC LIMIT 10;
|
||||
```
|
||||
|
||||
## Common Error Messages
|
||||
|
||||
### "Worker service not responding"
|
||||
|
||||
**Cause**: Worker not running or port mismatch.
|
||||
|
||||
**Solution**: Restart worker with `npm run worker:restart`.
|
||||
|
||||
### "Database is locked"
|
||||
|
||||
**Cause**: Multiple processes accessing database.
|
||||
|
||||
**Solution**: Stop worker, kill stale processes, restart.
|
||||
|
||||
### "FTS5: syntax error"
|
||||
|
||||
**Cause**: Invalid search query syntax.
|
||||
|
||||
**Solution**: Use simpler query, avoid special characters.
|
||||
|
||||
### "SQLITE_CANTOPEN"
|
||||
|
||||
**Cause**: Database file permissions or missing directory.
|
||||
|
||||
**Solution**: Check `~/.claude-mem/` exists and is writable.
|
||||
|
||||
### "Module not found"
|
||||
|
||||
**Cause**: Missing dependencies.
|
||||
|
||||
**Solution**: Run `npm install`.
|
||||
|
||||
## Getting Help
|
||||
|
||||
If none of these solutions work:
|
||||
|
||||
1. **Check logs**:
|
||||
```bash
|
||||
npm run worker:logs
|
||||
```
|
||||
|
||||
2. **Create issue**: [GitHub Issues](https://github.com/thedotmack/claude-mem/issues)
|
||||
- Include error messages
|
||||
- Include relevant logs
|
||||
- Include steps to reproduce
|
||||
|
||||
3. **Check existing issues**: Someone may have already solved your problem
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Configuration](configuration) - Customize Claude-Mem
|
||||
- [Development](development) - Build from source
|
||||
- [Architecture](architecture/overview) - Understand the system
|
||||
@@ -0,0 +1,169 @@
|
||||
---
|
||||
title: Claude Desktop Skill
|
||||
description: Use claude-mem memory search in Claude Desktop with the mem-search skill
|
||||
icon: desktop
|
||||
---
|
||||
|
||||
<Note>
|
||||
**Availability:** The mem-search skill works with Claude Desktop on macOS and Windows.
|
||||
</Note>
|
||||
|
||||
## Overview
|
||||
|
||||
Claude Desktop can access your claude-mem memory database through the **mem-search** skill. This allows you to search past sessions, decisions, and observations directly from Claude Desktop conversations.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing the skill, ensure:
|
||||
|
||||
1. **claude-mem is installed** and the worker service is running
|
||||
2. **MCP server is configured** in Claude Desktop (the skill uses the `mem-search` MCP server)
|
||||
|
||||
### Verify Worker is Running
|
||||
|
||||
```bash
|
||||
curl http://localhost:37777/api/health
|
||||
# Should return: {"status":"ok"}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
### Step 1: Download the Skill
|
||||
|
||||
Download the skill package from the repository:
|
||||
|
||||
<Card title="mem-search.zip" icon="download" href="https://github.com/thedotmack/claude-mem/raw/main/desktop-skill/mem-search.zip">
|
||||
Download the mem-search skill for Claude Desktop
|
||||
</Card>
|
||||
|
||||
Or build from source:
|
||||
|
||||
```bash
|
||||
cd desktop-skill
|
||||
zip -r mem-search.zip Skill.md
|
||||
```
|
||||
|
||||
### Step 2: Install in Claude Desktop
|
||||
|
||||
1. Open **Claude Desktop**
|
||||
2. Go to **Settings** (gear icon)
|
||||
3. Navigate to **Skills**
|
||||
4. Click **Install Skill** or drag the `mem-search.zip` file
|
||||
5. Confirm installation
|
||||
|
||||
### Step 3: Configure MCP Server
|
||||
|
||||
The skill requires the `mem-search` MCP server. Add this to your Claude Desktop configuration:
|
||||
|
||||
<Tabs>
|
||||
<Tab title="macOS">
|
||||
Edit `~/Library/Application Support/Claude/claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem-search": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"/Users/YOUR_USERNAME/.claude/plugins/marketplaces/thedotmack/plugin/scripts/mcp-server.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Windows">
|
||||
Edit `%APPDATA%\Claude\claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mem-search": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"C:\\Users\\YOUR_USERNAME\\.claude\\plugins\\marketplaces\\thedotmack\\plugin\\scripts\\mcp-server.cjs"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
<Warning>
|
||||
Replace `YOUR_USERNAME` with your actual username. Restart Claude Desktop after editing the configuration.
|
||||
</Warning>
|
||||
|
||||
### Step 4: Restart Claude Desktop
|
||||
|
||||
Close and reopen Claude Desktop for the MCP server configuration to take effect.
|
||||
|
||||
## Usage
|
||||
|
||||
Once installed, the skill auto-activates when you ask about past work:
|
||||
|
||||
```
|
||||
"What did we do last session?"
|
||||
"Did we fix this bug before?"
|
||||
"How did we implement authentication?"
|
||||
"What decisions did we make about the API?"
|
||||
"Show me changes to worker-service.ts"
|
||||
```
|
||||
|
||||
## Available Search Tools
|
||||
|
||||
The skill provides access to these MCP tools:
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `search` | Unified search across all memory types |
|
||||
| `decisions` | Find architectural/design decisions |
|
||||
| `changes` | Find code changes and refactorings |
|
||||
| `timeline` | Get observations around a specific point in time |
|
||||
| `find_by_file` | Find observations for specific files |
|
||||
| `find_by_type` | Filter by type (decision, bugfix, feature, refactor, discovery, change) |
|
||||
| `find_by_concept` | Find by concept tags |
|
||||
| `how_it_works` | Understand system architecture and design patterns |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill Not Appearing
|
||||
|
||||
1. Verify the zip file was properly installed
|
||||
2. Check Claude Desktop's skill installation logs
|
||||
3. Restart Claude Desktop
|
||||
|
||||
### MCP Server Connection Failed
|
||||
|
||||
1. Verify the worker is running: `curl http://localhost:37777/api/health`
|
||||
2. Check the MCP server path in configuration
|
||||
3. Look for errors in Claude Desktop logs
|
||||
|
||||
<Tabs>
|
||||
<Tab title="macOS">
|
||||
```bash
|
||||
# View Claude Desktop logs
|
||||
tail -f ~/Library/Logs/Claude/claude.log
|
||||
```
|
||||
</Tab>
|
||||
<Tab title="Windows">
|
||||
Check `%APPDATA%\Claude\logs\`
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Search Returns No Results
|
||||
|
||||
1. Ensure claude-mem has recorded sessions (check http://localhost:37777)
|
||||
2. Verify the database exists: `ls ~/.claude-mem/claude-mem.db`
|
||||
3. Test the API directly: `curl "http://localhost:37777/api/search?query=test"`
|
||||
|
||||
## Related
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Search Tools" icon="magnifying-glass" href="/usage/search-tools">
|
||||
Complete search API reference
|
||||
</Card>
|
||||
<Card title="Platform Integration" icon="plug" href="/platform-integration">
|
||||
Build custom integrations
|
||||
</Card>
|
||||
</CardGroup>
|
||||
@@ -0,0 +1,215 @@
|
||||
---
|
||||
title: "Getting Started"
|
||||
description: "Learn how Claude-Mem works automatically in the background"
|
||||
---
|
||||
|
||||
# Getting Started with Claude-Mem
|
||||
|
||||
## Automatic Operation
|
||||
|
||||
Claude-Mem works automatically once installed. No manual intervention required!
|
||||
|
||||
### The Full Cycle
|
||||
|
||||
1. **Start Claude Code** - Context from last 10 sessions appears automatically
|
||||
2. **Work normally** - Every tool execution is captured
|
||||
3. **Claude finishes responding** - Stop hook automatically generates and saves a summary
|
||||
4. **Next session** - Previous work appears in context
|
||||
|
||||
### What Gets Captured
|
||||
|
||||
Every time Claude uses a tool, claude-mem captures it:
|
||||
|
||||
- **Read** - File reads and content access
|
||||
- **Write** - New file creation
|
||||
- **Edit** - File modifications
|
||||
- **Bash** - Command executions
|
||||
- **Glob** - File pattern searches
|
||||
- **Grep** - Content searches
|
||||
- And all other Claude Code tools
|
||||
|
||||
### What Gets Processed
|
||||
|
||||
The worker service processes tool observations and extracts:
|
||||
|
||||
- **Title** - Brief description of what happened
|
||||
- **Subtitle** - Additional context
|
||||
- **Narrative** - Detailed explanation
|
||||
- **Facts** - Key learnings as bullet points
|
||||
- **Concepts** - Relevant tags and categories
|
||||
- **Type** - Classification (decision, bugfix, feature, etc.)
|
||||
- **Files** - Which files were read or modified
|
||||
|
||||
### Session Summaries
|
||||
|
||||
When Claude finishes responding (triggering the Stop hook), a summary is automatically generated with:
|
||||
|
||||
- **Request** - What you asked for
|
||||
- **Investigated** - What Claude explored
|
||||
- **Learned** - Key discoveries and insights
|
||||
- **Completed** - What was accomplished
|
||||
- **Next Steps** - What to do next
|
||||
|
||||
### Context Injection
|
||||
|
||||
When you start a new Claude Code session, the SessionStart hook:
|
||||
|
||||
1. Queries the database for recent observations in your project (default: 50)
|
||||
2. Retrieves recent session summaries for context
|
||||
3. Displays observations in a chronological timeline with session markers
|
||||
4. Shows full summary details (Investigated, Learned, Completed, Next Steps) **only if the summary was generated after the last observation**
|
||||
5. Injects formatted context into Claude's initial context
|
||||
|
||||
**Summary Display Logic:**
|
||||
|
||||
The most recent summary's full details appear at the end of the context display **only when** the summary was generated after the most recent observation. This ensures you see summary details when they represent the latest state of your project, but not when new observations have been captured since the last summary.
|
||||
|
||||
For example:
|
||||
- ✅ **Shows summary**: Last observation at 2:00 PM, summary generated at 2:05 PM → Summary details appear
|
||||
- ❌ **Hides summary**: Summary generated at 2:00 PM, new observation at 2:05 PM → Summary details hidden (outdated)
|
||||
|
||||
This prevents showing stale summaries when new work has been captured but not yet summarized.
|
||||
|
||||
This means Claude "remembers" what happened in previous sessions!
|
||||
|
||||
## Manual Commands (Optional)
|
||||
|
||||
### Worker Management
|
||||
|
||||
v4.0+ auto-starts the worker on first session. Manual commands below are optional.
|
||||
|
||||
```bash
|
||||
# Start worker service (optional - auto-starts automatically)
|
||||
npm run worker:start
|
||||
|
||||
# Stop worker service
|
||||
npm run worker:stop
|
||||
|
||||
# Restart worker service
|
||||
npm run worker:restart
|
||||
|
||||
# View worker logs
|
||||
npm run worker:logs
|
||||
|
||||
# Check worker status
|
||||
npm run worker:status
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
npm test
|
||||
|
||||
# Test context injection
|
||||
npm run test:context
|
||||
|
||||
# Verbose context test
|
||||
npm run test:context:verbose
|
||||
```
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
# Build hooks and worker
|
||||
npm run build
|
||||
|
||||
# Build only hooks
|
||||
npm run build:hooks
|
||||
|
||||
# Publish to NPM (maintainers only)
|
||||
npm run publish:npm
|
||||
```
|
||||
|
||||
## Viewing Stored Context
|
||||
|
||||
Context is stored in SQLite database at `~/.claude-mem/claude-mem.db`.
|
||||
|
||||
Query the database directly:
|
||||
|
||||
```bash
|
||||
# Open database
|
||||
sqlite3 ~/.claude-mem/claude-mem.db
|
||||
|
||||
# View recent sessions
|
||||
SELECT session_id, project, created_at, status
|
||||
FROM sdk_sessions
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 10;
|
||||
|
||||
# View session summaries
|
||||
SELECT session_id, request, completed, learned
|
||||
FROM session_summaries
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 5;
|
||||
|
||||
# View observations for a session
|
||||
SELECT tool_name, created_at
|
||||
FROM observations
|
||||
WHERE session_id = 'YOUR_SESSION_ID';
|
||||
```
|
||||
|
||||
## Understanding Progressive Disclosure
|
||||
|
||||
Context injection uses progressive disclosure for efficient token usage:
|
||||
|
||||
### Layer 1: Index Display (Session Start)
|
||||
- Shows observation titles with token cost estimates
|
||||
- Displays session markers in chronological timeline
|
||||
- Groups observations by file for visual clarity
|
||||
- Shows full summary details **only if** generated after last observation
|
||||
- Token cost: ~50-200 tokens for index view
|
||||
|
||||
### Layer 2: On-Demand Details (mem-search Skill)
|
||||
- Ask naturally: "What bugs did we fix?" or "How did we implement X?"
|
||||
- Claude auto-invokes mem-search skill to fetch full details
|
||||
- Search by concept, file, type, or keyword
|
||||
- Timeline context around specific observations
|
||||
- Token cost: ~100-500 tokens per observation fetched
|
||||
- Skill uses HTTP API (v5.4.0+) for efficient retrieval
|
||||
|
||||
### Layer 3: Perfect Recall (Code Access)
|
||||
- Read source files directly when needed
|
||||
- Access original transcripts and raw data
|
||||
- Full context available on-demand
|
||||
|
||||
This ensures efficient token usage while maintaining access to complete history when needed.
|
||||
|
||||
## Multi-Prompt Sessions & `/clear` Behavior
|
||||
|
||||
Claude-Mem supports sessions that span multiple user prompts:
|
||||
|
||||
- **prompt_counter**: Tracks total prompts in a session
|
||||
- **prompt_number**: Identifies specific prompt within session
|
||||
- **Session continuity**: Observations and summaries link across prompts
|
||||
|
||||
### Important Note About `/clear`
|
||||
|
||||
When you use `/clear`, the session doesn't end - it continues with a new prompt number. This means:
|
||||
|
||||
- ✅ **Context is re-injected** from recent sessions (SessionStart hook fires with `source: "clear"`)
|
||||
- ✅ **Observations are still being captured** and added to the current session
|
||||
- ✅ **A summary will be generated** when Claude finishes responding (Stop hook fires)
|
||||
|
||||
The `/clear` command clears the conversation context visible to Claude AND re-injects fresh context from recent sessions, while the underlying session continues tracking observations.
|
||||
|
||||
## Searching Your History (v5.4.0+)
|
||||
|
||||
Claude-Mem uses the mem-search skill for querying your project history. Simply ask naturally:
|
||||
|
||||
```
|
||||
"What bugs did we fix last session?"
|
||||
"How did we implement authentication?"
|
||||
"What changes were made to worker-service.ts?"
|
||||
"Show me recent work on this project"
|
||||
```
|
||||
|
||||
Claude automatically recognizes your intent and invokes the mem-search skill, which uses HTTP API endpoints to query your memory efficiently.
|
||||
|
||||
**Token Savings**: ~2,250 tokens per session start vs previous MCP approach
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Skill-Based Search](/usage/search-tools) - Learn how to search your project history
|
||||
- [Architecture Overview](/architecture/overview) - Understand how it works
|
||||
- [Troubleshooting](/troubleshooting) - Common issues and solutions
|
||||
@@ -0,0 +1,195 @@
|
||||
---
|
||||
title: "Private Tags"
|
||||
description: "Control what gets stored in memory with privacy tags"
|
||||
---
|
||||
|
||||
# Private Tags
|
||||
|
||||
## Overview
|
||||
|
||||
Use `<private>` tags to mark content you don't want persisted in claude-mem's observation database. This gives you fine-grained control over what gets remembered across sessions.
|
||||
|
||||
## How It Works
|
||||
|
||||
Wrap any content in `<private>` tags:
|
||||
|
||||
```
|
||||
<private>
|
||||
This content will not be stored in memory
|
||||
</private>
|
||||
```
|
||||
|
||||
Claude can see and use this content during the current session, but it won't be saved as an observation.
|
||||
|
||||
## Use Cases
|
||||
|
||||
### 1. Sensitive Information
|
||||
|
||||
```
|
||||
Please analyze this error:
|
||||
|
||||
<private>
|
||||
Error: Database connection failed
|
||||
Host: internal-db-prod.company.com
|
||||
Port: 5432
|
||||
User: admin_user
|
||||
</private>
|
||||
|
||||
What might be causing this?
|
||||
```
|
||||
|
||||
Claude sees the full error but only the question gets stored.
|
||||
|
||||
### 2. Temporary Context
|
||||
|
||||
```
|
||||
<private>
|
||||
Here's some background context just for this session:
|
||||
- Project deadline is tomorrow
|
||||
- This is a hotfix for production
|
||||
- Manager asked for this specifically
|
||||
</private>
|
||||
|
||||
Help me fix this bug quickly.
|
||||
```
|
||||
|
||||
### 3. Debugging Information
|
||||
|
||||
```
|
||||
<private>
|
||||
Debug output from previous run:
|
||||
[... 500 lines of logs ...]
|
||||
</private>
|
||||
|
||||
Based on these logs, what's the root cause?
|
||||
```
|
||||
|
||||
### 4. Exploratory Prompts
|
||||
|
||||
```
|
||||
<private>
|
||||
I'm just brainstorming here, not making a final decision
|
||||
</private>
|
||||
|
||||
What are some wild approaches to solving this?
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Tag Behavior
|
||||
|
||||
- **Multiline support**: Tags can wrap multiple lines of content
|
||||
- **Multiple tags**: You can use multiple `<private>` sections in one message
|
||||
- **Nested tags**: Inner tags are included in outer tag removal
|
||||
- **Always active**: No configuration needed - works automatically
|
||||
|
||||
### What Gets Filtered
|
||||
|
||||
The `<private>` tag filters content from storage and memory:
|
||||
- **User prompt storage** - Tags are stripped before saving to the user_prompts table
|
||||
- **Tool inputs** - Parameters passed to tools are filtered before observation creation
|
||||
- **Tool responses** - Output from tools is filtered before observation creation
|
||||
- **All searchable content** - Private content never reaches the database or search indices
|
||||
|
||||
**Important**: Tags are stripped during storage, not from the live conversation. Claude sees the full content including `<private>` tags during the session, and they only disappear when content is persisted to the database.
|
||||
|
||||
### What Doesn't Get Filtered
|
||||
|
||||
- Session summaries (generated from non-private observations only)
|
||||
- Claude's responses (not captured by claude-mem)
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: API Keys
|
||||
|
||||
```
|
||||
<private>
|
||||
API_KEY=sk-proj-abc123xyz789
|
||||
</private>
|
||||
|
||||
Test this API connection for me
|
||||
```
|
||||
|
||||
The API key won't be stored, but Claude can use it during the session.
|
||||
|
||||
### Example 2: Personal Notes
|
||||
|
||||
```
|
||||
<private>
|
||||
Note to self: This is for the Smith project - the one we discussed
|
||||
last Tuesday. Don't confuse with the Jones project.
|
||||
</private>
|
||||
|
||||
Review the authentication implementation and suggest improvements.
|
||||
```
|
||||
|
||||
The personal context helps Claude understand your request without polluting your observation history.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Don't over-tag**: Only use `<private>` for content you genuinely don't want stored
|
||||
2. **Context matters**: Claude's understanding of your project comes from observations - excessive private tagging reduces future context quality
|
||||
3. **Secrets belong elsewhere**: While `<private>` prevents storage, sensitive data should still use proper secrets management
|
||||
4. **Test it works**: Check `~/.claude-mem/silent.log` if you're unsure whether tags are being stripped
|
||||
|
||||
## Verification
|
||||
|
||||
To verify tags are working:
|
||||
|
||||
1. Submit a prompt with `<private>` tags
|
||||
2. Check the database to ensure private content is not stored:
|
||||
```bash
|
||||
# Check user prompts
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT prompt_text FROM user_prompts ORDER BY created_at_epoch DESC LIMIT 1;"
|
||||
|
||||
# Check observations
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT narrative FROM observations ORDER BY created_at_epoch DESC LIMIT 1;"
|
||||
```
|
||||
3. The private content should NOT appear in either user_prompts or observations
|
||||
4. The `<private>` tags themselves should also be stripped
|
||||
|
||||
## Architecture
|
||||
|
||||
The `<private>` tag uses an **edge processing pattern**:
|
||||
|
||||
- Content is filtered at the hook layer before any storage
|
||||
- **UserPromptSubmit hook**: Strips tags from user prompts before saving to the user_prompts table (your typed prompts are cleaned before database storage)
|
||||
- **PostToolUse hook**: Strips tags from serialized tool_input and tool_response JSON before observation creation
|
||||
- Filtering happens before data reaches the worker service or database
|
||||
- This keeps the worker simple and follows a one-way data stream
|
||||
- Tags remain visible in the live conversation but are stripped from all persistent storage
|
||||
|
||||
**Tag Stripping Scope**: The implementation strips tags from the *serialized JSON representations* of tool inputs and tool responses, not from the original user prompt text in the conversation UI. The user prompt text you type is stored in a separate table (user_prompts) where tags are also stripped before storage.
|
||||
|
||||
This design ensures that private content never reaches the database, search indices, or memory agent, maintaining a clean separation between ephemeral and persistent data.
|
||||
|
||||
## Related Features
|
||||
|
||||
- [Search Tools](/usage/search-tools) - How to search past observations
|
||||
- [Getting Started](/usage/getting-started) - Basic usage guide
|
||||
- [Configuration](/configuration) - System settings and environment variables
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Tags Not Being Stripped
|
||||
|
||||
1. Verify correct syntax: `<private>content</private>`
|
||||
2. Check `~/.claude-mem/silent.log` for errors
|
||||
3. Ensure worker is running: `npm run worker:status`
|
||||
4. Restart worker: `npm run worker:restart`
|
||||
|
||||
### Partial Content Stored
|
||||
|
||||
If content appears partially in observations:
|
||||
- Ensure tags are properly closed
|
||||
- Check for typos in tag names
|
||||
- Verify content is inside tool executions (not just in your prompt text)
|
||||
|
||||
### Silent Log Shows Errors
|
||||
|
||||
If you see errors in `~/.claude-mem/silent.log`:
|
||||
```
|
||||
[save-hook] stripMemoryTags received non-string: { type: 'object' }
|
||||
```
|
||||
|
||||
This is usually harmless - it indicates defensive type checking is working. However, if you see these frequently, it may indicate a bug. Please report it at https://github.com/thedotmack/claude-mem/issues
|
||||
@@ -0,0 +1,404 @@
|
||||
---
|
||||
title: "mem-search Skill"
|
||||
description: "Query your project history with natural language"
|
||||
---
|
||||
|
||||
# mem-search Skill Usage
|
||||
|
||||
Once claude-mem is installed as a plugin, you can search your project history using natural language. Claude automatically invokes the mem-search skill when you ask about past work.
|
||||
|
||||
## How It Works
|
||||
|
||||
**v5.5.0 Enhancement**: The search skill was renamed to "mem-search" for better scope differentiation, with effectiveness increased from 67% to 100% and enhanced concrete triggers (85% vs 44%).
|
||||
|
||||
**v5.4.0 Architecture**: Claude-Mem uses a skill-based search architecture instead of MCP tools, saving ~2,250 tokens per session start through progressive disclosure.
|
||||
|
||||
**Simple Usage:**
|
||||
- Just ask naturally: *"What did we do last session?"*
|
||||
- Claude recognizes the intent and invokes the mem-search skill
|
||||
- The skill uses HTTP API endpoints to query your memory
|
||||
- Results are formatted and presented to you
|
||||
|
||||
**Benefits:**
|
||||
- **Token Efficient**: ~250 tokens (skill frontmatter) vs ~2,500 tokens (MCP tool definitions)
|
||||
- **Natural Language**: No need to learn specific tool syntax
|
||||
- **Progressive Disclosure**: Only loads detailed instructions when needed
|
||||
- **Auto-Invoked**: Claude knows when to search based on your questions
|
||||
- **Scope Differentiation**: "mem-search" clearly distinguishes from native conversation memory
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Operation | Purpose |
|
||||
|-------------------------|----------------------------------------------|
|
||||
| Search Observations | Full-text search across observations |
|
||||
| Search Sessions | Full-text search across session summaries |
|
||||
| Search Prompts | Full-text search across raw user prompts |
|
||||
| By Concept | Find observations tagged with concepts |
|
||||
| By File | Find observations referencing files |
|
||||
| By Type | Find observations by type |
|
||||
| Recent Context | Get recent session context |
|
||||
| Timeline | Get unified timeline around a specific point |
|
||||
| Timeline by Query | Search and get timeline context in one step |
|
||||
| API Help | Get search API documentation |
|
||||
|
||||
## Example Queries
|
||||
|
||||
### Natural Language Queries
|
||||
|
||||
**Search Observations:**
|
||||
```
|
||||
"What bugs did we fix related to authentication?"
|
||||
"Show me all decisions about the build system"
|
||||
"Find refactoring work on the database"
|
||||
```
|
||||
|
||||
**Search Sessions:**
|
||||
```
|
||||
"What did we learn about hooks?"
|
||||
"What was accomplished in the API implementation?"
|
||||
"Show me recent work on this project"
|
||||
```
|
||||
|
||||
**Search Prompts:**
|
||||
```
|
||||
"When did I ask about authentication features?"
|
||||
"Find all my requests about dark mode"
|
||||
```
|
||||
|
||||
**Note**: Claude automatically translates your natural language queries into the appropriate search operations.
|
||||
|
||||
### Search by File
|
||||
|
||||
```
|
||||
"Show me everything related to worker-service.ts"
|
||||
"What changes were made to migrations.ts?"
|
||||
"Find all work on the database file"
|
||||
```
|
||||
|
||||
### Search by Concept
|
||||
|
||||
```
|
||||
"Show observations tagged with architecture"
|
||||
"Find all security-related observations"
|
||||
"What patterns have we used?"
|
||||
```
|
||||
|
||||
### Search by Type
|
||||
|
||||
```
|
||||
"Find all feature implementations"
|
||||
"Show me all decisions and discoveries"
|
||||
"What bugs have we fixed?"
|
||||
```
|
||||
|
||||
### Recent Context
|
||||
|
||||
```
|
||||
"Show me what we've been working on"
|
||||
"Get context from the last 5 sessions"
|
||||
"What happened recently on this project?"
|
||||
```
|
||||
|
||||
### Timeline Queries
|
||||
|
||||
**Get timeline around a specific point:**
|
||||
```
|
||||
"What was happening when we implemented authentication?"
|
||||
"Show me the context around that bug fix"
|
||||
"What led to the decision to refactor the database?"
|
||||
```
|
||||
|
||||
**Timeline by query:**
|
||||
```
|
||||
"Find when we added the viewer UI and show what happened around that time"
|
||||
"Search for authentication work and show the timeline"
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- See the complete narrative arc around key events
|
||||
- All record types (observations, sessions, prompts) in chronological view
|
||||
- Understand what was happening before and after important changes
|
||||
|
||||
## Search Strategy
|
||||
|
||||
The mem-search skill uses a progressive disclosure pattern to efficiently retrieve information:
|
||||
|
||||
### 1. Ask Naturally
|
||||
|
||||
Start with a natural language question:
|
||||
```
|
||||
"What bugs did we fix related to authentication?"
|
||||
```
|
||||
|
||||
### 2. Claude Invokes mem-search Skill
|
||||
|
||||
Claude recognizes your intent and loads the mem-search skill (~250 tokens for skill frontmatter).
|
||||
|
||||
### 3. Skill Uses HTTP API
|
||||
|
||||
The skill calls the appropriate HTTP endpoint (e.g., `/api/search/observations`) with the query.
|
||||
|
||||
### 4. Results Formatted
|
||||
|
||||
Results are formatted and presented to you, usually starting with an index/summary format.
|
||||
|
||||
### 5. Deep Dive if Needed
|
||||
|
||||
If you need more details, ask follow-up questions:
|
||||
```
|
||||
"Tell me more about observation #123"
|
||||
"Show me the full details of that decision"
|
||||
```
|
||||
|
||||
**Benefits of This Approach:**
|
||||
- **Token Efficient**: Only loads what you need, when you need it
|
||||
- **Natural**: No syntax to learn
|
||||
- **Progressive**: Start with overview, drill down as needed
|
||||
- **Automatic**: Claude handles the search invocation
|
||||
|
||||
## Advanced Filtering
|
||||
|
||||
You can refine searches using natural language filters:
|
||||
|
||||
### Date Ranges
|
||||
|
||||
```
|
||||
"What bugs did we fix in October?"
|
||||
"Show me work from last week"
|
||||
"Find decisions made between October 1-31"
|
||||
```
|
||||
|
||||
### Multiple Types
|
||||
|
||||
```
|
||||
"Show me all decisions and features"
|
||||
"Find bugfixes and refactorings"
|
||||
```
|
||||
|
||||
### Concepts
|
||||
|
||||
```
|
||||
"Find database work related to architecture and performance"
|
||||
"Show security observations"
|
||||
```
|
||||
|
||||
### File-Specific
|
||||
|
||||
```
|
||||
"Show refactoring work that touched worker-service.ts"
|
||||
"Find changes to auth files"
|
||||
```
|
||||
|
||||
### Project Filtering
|
||||
|
||||
```
|
||||
"Show authentication work on my-app project"
|
||||
"What have we done on this codebase?"
|
||||
```
|
||||
|
||||
**Note**: Claude translates your natural language into the appropriate API filters automatically.
|
||||
|
||||
## Under the Hood: HTTP API
|
||||
|
||||
The mem-search skill uses HTTP endpoints on the worker service (port 37777):
|
||||
|
||||
- `GET /api/search/observations` - Full-text search observations
|
||||
- `GET /api/search/sessions` - Full-text search session summaries
|
||||
- `GET /api/search/prompts` - Full-text search user prompts
|
||||
- `GET /api/search/by-concept` - Find observations by concept tag
|
||||
- `GET /api/search/by-file` - Find work related to specific files
|
||||
- `GET /api/search/by-type` - Find observations by type
|
||||
- `GET /api/context/recent` - Get recent session context
|
||||
- `GET /api/context/timeline` - Get timeline around specific point
|
||||
- `GET /api/timeline/by-query` - Search + timeline in one call
|
||||
- `GET /api/search/help` - API documentation
|
||||
|
||||
These endpoints use FTS5 full-text search with support for:
|
||||
- Boolean operators (AND, OR, NOT)
|
||||
- Phrase searches
|
||||
- Column-specific searches
|
||||
- Date range filtering
|
||||
- Project filtering
|
||||
|
||||
## Result Metadata
|
||||
|
||||
All results include rich metadata:
|
||||
|
||||
```
|
||||
## JWT authentication decision
|
||||
|
||||
**Type**: decision
|
||||
**Date**: 2025-10-21 14:23:45
|
||||
**Concepts**: authentication, security, architecture
|
||||
**Files Read**: src/auth/middleware.ts, src/utils/jwt.ts
|
||||
**Files Modified**: src/auth/jwt-strategy.ts
|
||||
|
||||
**Narrative**:
|
||||
Decided to implement JWT-based authentication instead of session-based
|
||||
authentication for better scalability and stateless design...
|
||||
|
||||
**Facts**:
|
||||
• JWT tokens expire after 1 hour
|
||||
• Refresh tokens stored in httpOnly cookies
|
||||
• Token signing uses RS256 algorithm
|
||||
• Public keys rotated every 30 days
|
||||
```
|
||||
|
||||
## Citations
|
||||
|
||||
All search results include citations using the `claude-mem://` URI scheme:
|
||||
|
||||
- `claude-mem://observation/123` - Specific observation
|
||||
- `claude-mem://session/abc-456` - Specific session
|
||||
- `claude-mem://user-prompt/789` - Specific user prompt
|
||||
|
||||
These citations enable referencing specific historical context in your work.
|
||||
|
||||
## Token Management
|
||||
|
||||
### Token Efficiency Tips
|
||||
|
||||
1. **Start with index format**: ~50-100 tokens per result
|
||||
2. **Use small limits**: Start with 3-5 results
|
||||
3. **Apply filters**: Narrow results before searching
|
||||
4. **Paginate**: Use offset to browse results in batches
|
||||
|
||||
### Token Estimates
|
||||
|
||||
| Format | Tokens per Result |
|
||||
|--------|-------------------|
|
||||
| Index | 50-100 |
|
||||
| Full | 500-1000 |
|
||||
|
||||
**Example**:
|
||||
- 20 results in index format: ~1,000-2,000 tokens
|
||||
- 20 results in full format: ~10,000-20,000 tokens
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### 1. Debugging Issues
|
||||
|
||||
Find what went wrong:
|
||||
```
|
||||
search_observations with query="error database connection" and type="bugfix"
|
||||
```
|
||||
|
||||
### 2. Understanding Decisions
|
||||
|
||||
Review architectural choices:
|
||||
```
|
||||
find_by_type with type="decision" and format="index"
|
||||
```
|
||||
|
||||
Then deep dive on specific decisions:
|
||||
```
|
||||
search_observations with query="[DECISION TITLE]" and format="full"
|
||||
```
|
||||
|
||||
### 3. Code Archaeology
|
||||
|
||||
Find when a file was modified:
|
||||
```
|
||||
find_by_file with filePath="worker-service.ts"
|
||||
```
|
||||
|
||||
### 4. Feature History
|
||||
|
||||
Track feature development:
|
||||
```
|
||||
search_sessions with query="authentication feature"
|
||||
search_user_prompts with query="add authentication"
|
||||
```
|
||||
|
||||
### 5. Learning from Past Work
|
||||
|
||||
Review refactoring patterns:
|
||||
```
|
||||
find_by_type with type="refactor" and limit=10
|
||||
```
|
||||
|
||||
### 6. Context Recovery
|
||||
|
||||
Restore context after time away:
|
||||
```
|
||||
get_recent_context with limit=5
|
||||
search_sessions with query="[YOUR PROJECT NAME]" and orderBy="date_desc"
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Index first, full later**: Always start with index format
|
||||
2. **Small limits**: Start with 3-5 results to avoid token limits
|
||||
3. **Use filters**: Narrow results before searching
|
||||
4. **Specific queries**: More specific = better results
|
||||
5. **Review citations**: Use citations to reference past decisions
|
||||
6. **Date filtering**: Use date ranges for time-based searches
|
||||
7. **Type filtering**: Use types to categorize searches
|
||||
8. **Concept tags**: Use concepts for thematic searches
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Results Found
|
||||
|
||||
1. Check database has data:
|
||||
```bash
|
||||
sqlite3 ~/.claude-mem/claude-mem.db "SELECT COUNT(*) FROM observations;"
|
||||
```
|
||||
|
||||
2. Try broader natural language query:
|
||||
```
|
||||
"Show me anything about authentication" # Broader
|
||||
vs
|
||||
"Find exact JWT authentication implementation" # Too specific
|
||||
```
|
||||
|
||||
3. Ask without filters first:
|
||||
```
|
||||
"What do we have about auth?"
|
||||
# Then narrow down
|
||||
"Show me auth-related decisions"
|
||||
```
|
||||
|
||||
### Worker Service Not Running
|
||||
|
||||
If search isn't working, check the worker service:
|
||||
|
||||
```bash
|
||||
npm run worker:status # Check worker status
|
||||
npm run worker:restart # Restart if needed
|
||||
npm run worker:logs # View logs
|
||||
```
|
||||
|
||||
Or describe the issue to Claude and the troubleshoot skill will automatically activate to provide diagnosis.
|
||||
|
||||
### Performance Issues
|
||||
|
||||
If searches seem slow:
|
||||
1. Be more specific in your queries
|
||||
2. Ask for recent work (naturally filters by date)
|
||||
3. Specify the project you're interested in
|
||||
4. Ask for fewer results initially
|
||||
|
||||
## Technical Details
|
||||
|
||||
**Architecture Change (v5.4.0)**:
|
||||
- **Before**: 9 MCP tools (~2,500 tokens in tool definitions per session start)
|
||||
- **After**: 1 mem-search skill (~250 tokens in frontmatter, full instructions loaded on-demand)
|
||||
- **Savings**: ~2,250 tokens per session start
|
||||
- **Migration**: Transparent - users don't need to change how they ask questions
|
||||
|
||||
**v5.5.0 Enhancement**: Renamed from "search" to "mem-search" with improved effectiveness (67% → 100%) and enhanced triggers (44% → 85%).
|
||||
|
||||
**How the Skill Works:**
|
||||
1. User asks a question about past work
|
||||
2. Claude recognizes the intent matches the mem-search skill description
|
||||
3. Skill loads full instructions from `plugin/skills/mem-search/SKILL.md`
|
||||
4. Skill uses `curl` to call HTTP API endpoints
|
||||
5. Results formatted and returned to Claude
|
||||
6. Claude presents results to user
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Architecture Overview](/architecture/overview) - System components
|
||||
- [Database Schema](/architecture/database) - Understanding the data
|
||||
- [Getting Started](/usage/getting-started) - Automatic operation
|
||||
@@ -1,584 +0,0 @@
|
||||
Bun's bundler implements a `--compile` flag for generating a standalone binary from a TypeScript or JavaScript file.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```bash
|
||||
$ bun build ./cli.ts --compile --outfile mycli
|
||||
```
|
||||
|
||||
```ts#cli.ts
|
||||
console.log("Hello world!");
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
This bundles `cli.ts` into an executable that can be executed directly:
|
||||
|
||||
```
|
||||
$ ./mycli
|
||||
Hello world!
|
||||
```
|
||||
|
||||
All imported files and packages are bundled into the executable, along with a copy of the Bun runtime. All built-in Bun and Node.js APIs are supported.
|
||||
|
||||
## Cross-compile to other platforms
|
||||
|
||||
The `--target` flag lets you compile your standalone executable for a different operating system, architecture, or version of Bun than the machine you're running `bun build` on.
|
||||
|
||||
To build for Linux x64 (most servers):
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-linux-x64 ./index.ts --outfile myapp
|
||||
|
||||
# To support CPUs from before 2013, use the baseline version (nehalem)
|
||||
bun build --compile --target=bun-linux-x64-baseline ./index.ts --outfile myapp
|
||||
|
||||
# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
|
||||
# modern is faster, but baseline is more compatible.
|
||||
bun build --compile --target=bun-linux-x64-modern ./index.ts --outfile myapp
|
||||
```
|
||||
|
||||
To build for Linux ARM64 (e.g. Graviton or Raspberry Pi):
|
||||
|
||||
```sh
|
||||
# Note: the default architecture is x64 if no architecture is specified.
|
||||
bun build --compile --target=bun-linux-arm64 ./index.ts --outfile myapp
|
||||
```
|
||||
|
||||
To build for Windows x64:
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-windows-x64 ./path/to/my/app.ts --outfile myapp
|
||||
|
||||
# To support CPUs from before 2013, use the baseline version (nehalem)
|
||||
bun build --compile --target=bun-windows-x64-baseline ./path/to/my/app.ts --outfile myapp
|
||||
|
||||
# To explicitly only support CPUs from 2013 and later, use the modern version (haswell)
|
||||
bun build --compile --target=bun-windows-x64-modern ./path/to/my/app.ts --outfile myapp
|
||||
|
||||
# note: if no .exe extension is provided, Bun will automatically add it for Windows executables
|
||||
```
|
||||
|
||||
To build for macOS arm64:
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-darwin-arm64 ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
To build for macOS x64:
|
||||
|
||||
```sh
|
||||
bun build --compile --target=bun-darwin-x64 ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
#### Supported targets
|
||||
|
||||
The order of the `--target` flag does not matter, as long as they're delimited by a `-`.
|
||||
|
||||
| --target | Operating System | Architecture | Modern | Baseline | Libc |
|
||||
| --------------------- | ---------------- | ------------ | ------ | -------- | ----- |
|
||||
| bun-linux-x64 | Linux | x64 | ✅ | ✅ | glibc |
|
||||
| bun-linux-arm64 | Linux | arm64 | ✅ | N/A | glibc |
|
||||
| bun-windows-x64 | Windows | x64 | ✅ | ✅ | - |
|
||||
| ~~bun-windows-arm64~~ | Windows | arm64 | ❌ | ❌ | - |
|
||||
| bun-darwin-x64 | macOS | x64 | ✅ | ✅ | - |
|
||||
| bun-darwin-arm64 | macOS | arm64 | ✅ | N/A | - |
|
||||
| bun-linux-x64-musl | Linux | x64 | ✅ | ✅ | musl |
|
||||
| bun-linux-arm64-musl | Linux | arm64 | ✅ | N/A | musl |
|
||||
|
||||
On x64 platforms, Bun uses SIMD optimizations which require a modern CPU supporting AVX2 instructions. The `-baseline` build of Bun is for older CPUs that don't support these optimizations. Normally, when you install Bun we automatically detect which version to use but this can be harder to do when cross-compiling since you might not know the target CPU. You usually don't need to worry about it on Darwin x64, but it is relevant for Windows x64 and Linux x64. If you or your users see `"Illegal instruction"` errors, you might need to use the baseline version.
|
||||
|
||||
## Build-time constants
|
||||
|
||||
Use the `--define` flag to inject build-time constants into your executable, such as version numbers, build timestamps, or configuration values:
|
||||
|
||||
```bash
|
||||
$ bun build --compile --define BUILD_VERSION='"1.2.3"' --define BUILD_TIME='"2024-01-15T10:30:00Z"' src/cli.ts --outfile mycli
|
||||
```
|
||||
|
||||
These constants are embedded directly into your compiled binary at build time, providing zero runtime overhead and enabling dead code elimination optimizations.
|
||||
|
||||
{% callout type="info" %}
|
||||
For comprehensive examples and advanced patterns, see the [Build-time constants guide](/guides/runtime/build-time-constants).
|
||||
{% /callout %}
|
||||
|
||||
## Deploying to production
|
||||
|
||||
Compiled executables reduce memory usage and improve Bun's start time.
|
||||
|
||||
Normally, Bun reads and transpiles JavaScript and TypeScript files on `import` and `require`. This is part of what makes so much of Bun "just work", but it's not free. It costs time and memory to read files from disk, resolve file paths, parse, transpile, and print source code.
|
||||
|
||||
With compiled executables, you can move that cost from runtime to build-time.
|
||||
|
||||
When deploying to production, we recommend the following:
|
||||
|
||||
```sh
|
||||
bun build --compile --minify --sourcemap ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
### Bytecode compilation
|
||||
|
||||
To improve startup time, enable bytecode compilation:
|
||||
|
||||
```sh
|
||||
bun build --compile --minify --sourcemap --bytecode ./path/to/my/app.ts --outfile myapp
|
||||
```
|
||||
|
||||
Using bytecode compilation, `tsc` starts 2x faster:
|
||||
|
||||
{% image src="https://github.com/user-attachments/assets/dc8913db-01d2-48f8-a8ef-ac4e984f9763" width="689" /%}
|
||||
|
||||
Bytecode compilation moves parsing overhead for large input files from runtime to bundle time. Your app starts faster, in exchange for making the `bun build` command a little slower. It doesn't obscure source code.
|
||||
|
||||
**Experimental:** Bytecode compilation is an experimental feature introduced in Bun v1.1.30. Only `cjs` format is supported (which means no top-level-await). Let us know if you run into any issues!
|
||||
|
||||
### What do these flags do?
|
||||
|
||||
The `--minify` argument optimizes the size of the transpiled output code. If you have a large application, this can save megabytes of space. For smaller applications, it might still improve start time a little.
|
||||
|
||||
The `--sourcemap` argument embeds a sourcemap compressed with zstd, so that errors & stacktraces point to their original locations instead of the transpiled location. Bun will automatically decompress & resolve the sourcemap when an error occurs.
|
||||
|
||||
The `--bytecode` argument enables bytecode compilation. Every time you run JavaScript code in Bun, JavaScriptCore (the engine) will compile your source code into bytecode. We can move this parsing work from runtime to bundle time, saving you startup time.
|
||||
|
||||
## Act as the Bun CLI
|
||||
|
||||
{% note %}
|
||||
|
||||
New in Bun v1.2.16
|
||||
|
||||
{% /note %}
|
||||
|
||||
You can run a standalone executable as if it were the `bun` CLI itself by setting the `BUN_BE_BUN=1` environment variable. When this variable is set, the executable will ignore its bundled entrypoint and instead expose all the features of Bun's CLI.
|
||||
|
||||
For example, consider an executable compiled from a simple script:
|
||||
|
||||
```sh
|
||||
$ cat such-bun.js
|
||||
console.log("you shouldn't see this");
|
||||
|
||||
$ bun build --compile ./such-bun.js
|
||||
[3ms] bundle 1 modules
|
||||
[89ms] compile such-bun
|
||||
```
|
||||
|
||||
Normally, running `./such-bun` with arguments would execute the script. However, with the `BUN_BE_BUN=1` environment variable, it acts just like the `bun` binary:
|
||||
|
||||
```sh
|
||||
# Executable runs its own entrypoint by default
|
||||
$ ./such-bun install
|
||||
you shouldn't see this
|
||||
|
||||
# With the env var, the executable acts like the `bun` CLI
|
||||
$ BUN_BE_BUN=1 ./such-bun install
|
||||
bun install v1.2.16-canary.1 (1d1db811)
|
||||
Checked 63 installs across 64 packages (no changes) [5.00ms]
|
||||
```
|
||||
|
||||
This is useful for building CLI tools on top of Bun that may need to install packages, bundle dependencies, run different or local files and more without needing to download a separate binary or install bun.
|
||||
|
||||
## Full-stack executables
|
||||
|
||||
{% note %}
|
||||
|
||||
New in Bun v1.2.17
|
||||
|
||||
{% /note %}
|
||||
|
||||
Bun's `--compile` flag can create standalone executables that contain both server and client code, making it ideal for full-stack applications. When you import an HTML file in your server code, Bun automatically bundles all frontend assets (JavaScript, CSS, etc.) and embeds them into the executable. When Bun sees the HTML import on the server, it kicks off a frontend build process to bundle JavaScript, CSS, and other assets.
|
||||
|
||||
{% codetabs %}
|
||||
|
||||
```ts#server.ts
|
||||
import { serve } from "bun";
|
||||
import index from "./index.html";
|
||||
|
||||
const server = serve({
|
||||
routes: {
|
||||
"/": index,
|
||||
"/api/hello": { GET: () => Response.json({ message: "Hello from API" }) },
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`Server running at http://localhost:${server.port}`);
|
||||
```
|
||||
|
||||
```html#index.html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>My App</title>
|
||||
<link rel="stylesheet" href="./styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World</h1>
|
||||
<script src="./app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```js#app.js
|
||||
console.log("Hello from the client!");
|
||||
```
|
||||
|
||||
```css#styles.css
|
||||
body {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
```
|
||||
|
||||
{% /codetabs %}
|
||||
|
||||
To build this into a single executable:
|
||||
|
||||
```sh
|
||||
bun build --compile ./server.ts --outfile myapp
|
||||
```
|
||||
|
||||
This creates a self-contained binary that includes:
|
||||
|
||||
- Your server code
|
||||
- The Bun runtime
|
||||
- All frontend assets (HTML, CSS, JavaScript)
|
||||
- Any npm packages used by your server
|
||||
|
||||
The result is a single file that can be deployed anywhere without needing Node.js, Bun, or any dependencies installed. Just run:
|
||||
|
||||
```sh
|
||||
./myapp
|
||||
```
|
||||
|
||||
Bun automatically handles serving the frontend assets with proper MIME types and cache headers. The HTML import is replaced with a manifest object that `Bun.serve` uses to efficiently serve pre-bundled assets.
|
||||
|
||||
For more details on building full-stack applications with Bun, see the [full-stack guide](/docs/bundler/fullstack).
|
||||
|
||||
## Worker
|
||||
|
||||
To use workers in a standalone executable, add the worker's entrypoint to the CLI arguments:
|
||||
|
||||
```sh
|
||||
$ bun build --compile ./index.ts ./my-worker.ts --outfile myapp
|
||||
```
|
||||
|
||||
Then, reference the worker in your code:
|
||||
|
||||
```ts
|
||||
console.log("Hello from Bun!");
|
||||
|
||||
// Any of these will work:
|
||||
new Worker("./my-worker.ts");
|
||||
new Worker(new URL("./my-worker.ts", import.meta.url));
|
||||
new Worker(new URL("./my-worker.ts", import.meta.url).href);
|
||||
```
|
||||
|
||||
As of Bun v1.1.25, when you add multiple entrypoints to a standalone executable, they will be bundled separately into the executable.
|
||||
|
||||
In the future, we may automatically detect usages of statically-known paths in `new Worker(path)` and then bundle those into the executable, but for now, you'll need to add it to the shell command manually like the above example.
|
||||
|
||||
If you use a relative path to a file not included in the standalone executable, it will attempt to load that path from disk relative to the current working directory of the process (and then error if it doesn't exist).
|
||||
|
||||
## SQLite
|
||||
|
||||
You can use `bun:sqlite` imports with `bun build --compile`.
|
||||
|
||||
By default, the database is resolved relative to the current working directory of the process.
|
||||
|
||||
```js
|
||||
import db from "./my.db" with { type: "sqlite" };
|
||||
|
||||
console.log(db.query("select * from users LIMIT 1").get());
|
||||
```
|
||||
|
||||
That means if the executable is located at `/usr/bin/hello`, the user's terminal is located at `/home/me/Desktop`, it will look for `/home/me/Desktop/my.db`.
|
||||
|
||||
```
|
||||
$ cd /home/me/Desktop
|
||||
$ ./hello
|
||||
```
|
||||
|
||||
## Embed assets & files
|
||||
|
||||
Standalone executables support embedding files.
|
||||
|
||||
To embed files into an executable with `bun build --compile`, import the file in your code.
|
||||
|
||||
```ts
|
||||
// this becomes an internal file path
|
||||
import icon from "./icon.png" with { type: "file" };
|
||||
import { file } from "bun";
|
||||
|
||||
export default {
|
||||
fetch(req) {
|
||||
// Embedded files can be streamed from Response objects
|
||||
return new Response(file(icon));
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
Embedded files can be read using `Bun.file`'s functions or the Node.js `fs.readFile` function (in `"node:fs"`).
|
||||
|
||||
For example, to read the contents of the embedded file:
|
||||
|
||||
```js
|
||||
import icon from "./icon.png" with { type: "file" };
|
||||
import { file } from "bun";
|
||||
|
||||
const bytes = await file(icon).arrayBuffer();
|
||||
// await fs.promises.readFile(icon)
|
||||
// fs.readFileSync(icon)
|
||||
```
|
||||
|
||||
### Embed SQLite databases
|
||||
|
||||
If your application wants to embed a SQLite database, set `type: "sqlite"` in the import attribute and the `embed` attribute to `"true"`.
|
||||
|
||||
```js
|
||||
import myEmbeddedDb from "./my.db" with { type: "sqlite", embed: "true" };
|
||||
|
||||
console.log(myEmbeddedDb.query("select * from users LIMIT 1").get());
|
||||
```
|
||||
|
||||
This database is read-write, but all changes are lost when the executable exits (since it's stored in memory).
|
||||
|
||||
### Embed N-API Addons
|
||||
|
||||
As of Bun v1.0.23, you can embed `.node` files into executables.
|
||||
|
||||
```js
|
||||
const addon = require("./addon.node");
|
||||
|
||||
console.log(addon.hello());
|
||||
```
|
||||
|
||||
Unfortunately, if you're using `@mapbox/node-pre-gyp` or other similar tools, you'll need to make sure the `.node` file is directly required or it won't bundle correctly.
|
||||
|
||||
### Embed directories
|
||||
|
||||
To embed a directory with `bun build --compile`, use a shell glob in your `bun build` command:
|
||||
|
||||
```sh
|
||||
$ bun build --compile ./index.ts ./public/**/*.png
|
||||
```
|
||||
|
||||
Then, you can reference the files in your code:
|
||||
|
||||
```ts
|
||||
import icon from "./public/assets/icon.png" with { type: "file" };
|
||||
import { file } from "bun";
|
||||
|
||||
export default {
|
||||
fetch(req) {
|
||||
// Embedded files can be streamed from Response objects
|
||||
return new Response(file(icon));
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
This is honestly a workaround, and we expect to improve this in the future with a more direct API.
|
||||
|
||||
### Listing embedded files
|
||||
|
||||
To get a list of all embedded files, use `Bun.embeddedFiles`:
|
||||
|
||||
```js
|
||||
import "./icon.png" with { type: "file" };
|
||||
import { embeddedFiles } from "bun";
|
||||
|
||||
console.log(embeddedFiles[0].name); // `icon-${hash}.png`
|
||||
```
|
||||
|
||||
`Bun.embeddedFiles` returns an array of `Blob` objects which you can use to get the size, contents, and other properties of the files.
|
||||
|
||||
```ts
|
||||
embeddedFiles: Blob[]
|
||||
```
|
||||
|
||||
The list of embedded files excludes bundled source code like `.ts` and `.js` files.
|
||||
|
||||
#### Content hash
|
||||
|
||||
By default, embedded files have a content hash appended to their name. This is useful for situations where you want to serve the file from a URL or CDN and have fewer cache invalidation issues. But sometimes, this is unexpected and you might want the original name instead:
|
||||
|
||||
To disable the content hash, pass `--asset-naming` to `bun build --compile` like this:
|
||||
|
||||
```sh
|
||||
$ bun build --compile --asset-naming="[name].[ext]" ./index.ts
|
||||
```
|
||||
|
||||
## Minification
|
||||
|
||||
To trim down the size of the executable a little, pass `--minify` to `bun build --compile`. This uses Bun's minifier to reduce the code size. Overall though, Bun's binary is still way too big and we need to make it smaller.
|
||||
|
||||
## Using Bun.build() API
|
||||
|
||||
You can also generate standalone executables using the `Bun.build()` JavaScript API. This is useful when you need programmatic control over the build process.
|
||||
|
||||
### Basic usage
|
||||
|
||||
```js
|
||||
await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
compile: {
|
||||
target: "bun-windows-x64",
|
||||
outfile: "myapp.exe",
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Windows metadata with Bun.build()
|
||||
|
||||
When targeting Windows, you can specify metadata through the `windows` object:
|
||||
|
||||
```js
|
||||
await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
compile: {
|
||||
target: "bun-windows-x64",
|
||||
outfile: "myapp.exe",
|
||||
windows: {
|
||||
title: "My Application",
|
||||
publisher: "My Company Inc",
|
||||
version: "1.2.3.4",
|
||||
description: "A powerful application built with Bun",
|
||||
copyright: "© 2024 My Company Inc",
|
||||
hideConsole: false, // Set to true for GUI applications
|
||||
icon: "./icon.ico", // Path to icon file
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Cross-compilation with Bun.build()
|
||||
|
||||
You can cross-compile for different platforms:
|
||||
|
||||
```js
|
||||
// Build for multiple platforms
|
||||
const platforms = [
|
||||
{ target: "bun-windows-x64", outfile: "app-windows.exe" },
|
||||
{ target: "bun-linux-x64", outfile: "app-linux" },
|
||||
{ target: "bun-darwin-arm64", outfile: "app-macos" },
|
||||
];
|
||||
|
||||
for (const platform of platforms) {
|
||||
await Bun.build({
|
||||
entrypoints: ["./app.ts"],
|
||||
outdir: "./dist",
|
||||
compile: platform,
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Windows-specific flags
|
||||
|
||||
When compiling a standalone executable for Windows, there are several platform-specific options that can be used to customize the generated `.exe` file:
|
||||
|
||||
### Visual customization
|
||||
|
||||
- `--windows-icon=path/to/icon.ico` - Set the executable file icon
|
||||
- `--windows-hide-console` - Disable the background terminal window (useful for GUI applications)
|
||||
|
||||
### Metadata customization
|
||||
|
||||
You can embed version information and other metadata into your Windows executable:
|
||||
|
||||
- `--windows-title <STR>` - Set the product name (appears in file properties)
|
||||
- `--windows-publisher <STR>` - Set the company name
|
||||
- `--windows-version <STR>` - Set the version number (e.g. "1.2.3.4")
|
||||
- `--windows-description <STR>` - Set the file description
|
||||
- `--windows-copyright <STR>` - Set the copyright information
|
||||
|
||||
#### Example with all metadata flags:
|
||||
|
||||
```sh
|
||||
bun build --compile ./app.ts \
|
||||
--outfile myapp.exe \
|
||||
--windows-title "My Application" \
|
||||
--windows-publisher "My Company Inc" \
|
||||
--windows-version "1.2.3.4" \
|
||||
--windows-description "A powerful application built with Bun" \
|
||||
--windows-copyright "© 2024 My Company Inc"
|
||||
```
|
||||
|
||||
This metadata will be visible in Windows Explorer when viewing the file properties:
|
||||
|
||||
1. Right-click the executable in Windows Explorer
|
||||
2. Select "Properties"
|
||||
3. Go to the "Details" tab
|
||||
|
||||
#### Version string format
|
||||
|
||||
The `--windows-version` flag accepts version strings in the following formats:
|
||||
|
||||
- `"1"` - Will be normalized to "1.0.0.0"
|
||||
- `"1.2"` - Will be normalized to "1.2.0.0"
|
||||
- `"1.2.3"` - Will be normalized to "1.2.3.0"
|
||||
- `"1.2.3.4"` - Full version format
|
||||
|
||||
Each version component must be a number between 0 and 65535.
|
||||
|
||||
{% callout %}
|
||||
|
||||
These flags currently cannot be used when cross-compiling because they depend on Windows APIs. They are only available when building on Windows itself.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## Code signing on macOS
|
||||
|
||||
To codesign a standalone executable on macOS (which fixes Gatekeeper warnings), use the `codesign` command.
|
||||
|
||||
```sh
|
||||
$ codesign --deep --force -vvvv --sign "XXXXXXXXXX" ./myapp
|
||||
```
|
||||
|
||||
We recommend including an `entitlements.plist` file with JIT permissions.
|
||||
|
||||
```xml#entitlements.plist
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-executable-page-protection</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
To codesign with JIT support, pass the `--entitlements` flag to `codesign`.
|
||||
|
||||
```sh
|
||||
$ codesign --deep --force -vvvv --sign "XXXXXXXXXX" --entitlements entitlements.plist ./myapp
|
||||
```
|
||||
|
||||
After codesigning, verify the executable:
|
||||
|
||||
```sh
|
||||
$ codesign -vvv --verify ./myapp
|
||||
./myapp: valid on disk
|
||||
./myapp: satisfies its Designated Requirement
|
||||
```
|
||||
|
||||
{% callout %}
|
||||
|
||||
Codesign support requires Bun v1.2.4 or newer.
|
||||
|
||||
{% /callout %}
|
||||
|
||||
## Unsupported CLI arguments
|
||||
|
||||
Currently, the `--compile` flag can only accept a single entrypoint at a time and does not support the following flags:
|
||||
|
||||
- `--outdir` — use `outfile` instead.
|
||||
- `--splitting`
|
||||
- `--public-path`
|
||||
- `--target=node` or `--target=browser`
|
||||
- `--no-bundle` - we always bundle everything into the executable.
|
||||
@@ -1,99 +0,0 @@
|
||||
# Output styles
|
||||
|
||||
> Adapt Claude Code for uses beyond software engineering
|
||||
|
||||
Output styles allow you to use Claude Code as any type of agent while keeping
|
||||
its core capabilities, such as running local scripts, reading/writing files, and
|
||||
tracking TODOs.
|
||||
|
||||
## Built-in output styles
|
||||
|
||||
Claude Code's **Default** output style is the existing system prompt, designed
|
||||
to help you complete software engineering tasks efficiently.
|
||||
|
||||
There are two additional built-in output styles focused on teaching you the
|
||||
codebase and how Claude operates:
|
||||
|
||||
* **Explanatory**: Provides educational "Insights" in between helping you
|
||||
complete software engineering tasks. Helps you understand implementation
|
||||
choices and codebase patterns.
|
||||
|
||||
* **Learning**: Collaborative, learn-by-doing mode where Claude will not only
|
||||
share "Insights" while coding, but also ask you to contribute small, strategic
|
||||
pieces of code yourself. Claude Code will add `TODO(human)` markers in your
|
||||
code for you to implement.
|
||||
|
||||
## How output styles work
|
||||
|
||||
Output styles directly modify Claude Code's system prompt.
|
||||
|
||||
* Non-default output styles exclude instructions specific to code generation and
|
||||
efficient output normally built into Claude Code (such as responding concisely
|
||||
and verifying code with tests).
|
||||
* Instead, these output styles have their own custom instructions added to the
|
||||
system prompt.
|
||||
|
||||
## Change your output style
|
||||
|
||||
You can either:
|
||||
|
||||
* Run `/output-style` to access the menu and select your output style (this can
|
||||
also be accessed from the `/config` menu)
|
||||
|
||||
* Run `/output-style [style]`, such as `/output-style explanatory`, to directly
|
||||
switch to a style
|
||||
|
||||
These changes apply to the [local project level](/en/docs/claude-code/settings)
|
||||
and are saved in `.claude/settings.local.json`.
|
||||
|
||||
## Create a custom output style
|
||||
|
||||
To set up a new output style with Claude's help, run
|
||||
`/output-style:new I want an output style that ...`
|
||||
|
||||
By default, output styles created through `/output-style:new` are saved as
|
||||
markdown files at the user level in `~/.claude/output-styles` and can be used
|
||||
across projects. They have the following structure:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: My Custom Style
|
||||
description:
|
||||
A brief description of what this style does, to be displayed to the user
|
||||
---
|
||||
|
||||
# Custom Style Instructions
|
||||
|
||||
You are an interactive CLI tool that helps users with software engineering
|
||||
tasks. [Your custom instructions here...]
|
||||
|
||||
## Specific Behaviors
|
||||
|
||||
[Define how the assistant should behave in this style...]
|
||||
```
|
||||
|
||||
You can also create your own output style Markdown files and save them either at
|
||||
the user level (`~/.claude/output-styles`) or the project level
|
||||
(`.claude/output-styles`).
|
||||
|
||||
## Comparisons to related features
|
||||
|
||||
### Output Styles vs. CLAUDE.md vs. --append-system-prompt
|
||||
|
||||
Output styles completely “turn off” the parts of Claude Code’s default system
|
||||
prompt specific to software engineering. Neither CLAUDE.md nor
|
||||
`--append-system-prompt` edit Claude Code’s default system prompt. CLAUDE.md
|
||||
adds the contents as a user message *following* Claude Code’s default system
|
||||
prompt. `--append-system-prompt` appends the content to the system prompt.
|
||||
|
||||
### Output Styles vs. [Agents](/en/docs/claude-code/sub-agents)
|
||||
|
||||
Output styles directly affect the main agent loop and only affect the system
|
||||
prompt. Agents are invoked to handle specific tasks and can include additional
|
||||
settings like the model to use, the tools they have available, and some context
|
||||
about when to use the agent.
|
||||
|
||||
### Output Styles vs. [Custom Slash Commands](/en/docs/claude-code/slash-commands)
|
||||
|
||||
You can think of output styles as “stored system prompts” and custom slash
|
||||
commands as “stored prompts”.
|
||||
@@ -1,80 +0,0 @@
|
||||
### Project Memory Example
|
||||
|
||||
Claude's context window has limits - long conversations eventually get truncated, and chats don't persist between sessions. Using Chroma as an external memory store solves these limitations, allowing Claude to reference past conversations and maintain context across multiple sessions.
|
||||
|
||||
First, tell Claude to use Chroma for memory as part of the project setup:
|
||||
```
|
||||
Remember, you have access to Chroma tools.
|
||||
At any point if the user references previous chats or memory, check chroma for similar conversations.
|
||||
Try to use retrieved information where possible.
|
||||
```
|
||||
|
||||
This prompt instructs Claude to:
|
||||
- Proactively check Chroma when memory-related topics come up
|
||||
- Search for semantically similar past conversations
|
||||
- Incorporate relevant historical context into responses
|
||||
|
||||
To store the current conversation:
|
||||
|
||||
```
|
||||
Please chunk our conversation into small chunks and store it in Chroma for future reference.
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
can you chunk our entire conversation into small, embeddable text chunks (not the code, but describe it so you can recreate it if necessary). no longer than a couple lines each. then, add it to the chroma collection for this project.
|
||||
```
|
||||
|
||||
Claude will:
|
||||
1. Break the conversation into smaller chunks (typically 512-1024 tokens)
|
||||
- Chunking is necessary because:
|
||||
- Large texts are harder to search semantically
|
||||
- Smaller chunks help retrieve more precise context
|
||||
- It prevents token limits in future retrievals
|
||||
2. Generate embeddings for each chunk
|
||||
3. Add metadata like timestamps and detected topics
|
||||
4. Store everything in your Chroma collection
|
||||
|
||||
Later, you can access past conversations naturally:
|
||||
```
|
||||
What did we discuss previously about the authentication system?
|
||||
```
|
||||
|
||||
Claude will:
|
||||
1. Search Chroma for chunks semantically related to authentication
|
||||
2. Filter by timestamp metadata for last week's discussions
|
||||
3. Incorporate the relevant historical context into its response
|
||||
|
||||
This setup is particularly useful for:
|
||||
- Long-running projects where context gets lost
|
||||
- Teams where multiple people interact with Claude
|
||||
- Complex discussions that reference past decisions
|
||||
- Maintaining consistent context across multiple chat sessions
|
||||
|
||||
### Advanced Features
|
||||
|
||||
The Chroma MCP server supports:
|
||||
|
||||
- **Collection Management**: Create and organize separate collections for different projects
|
||||
- **Document Operations**: Add, update, or delete documents
|
||||
- **Search Capabilities**:
|
||||
- Vector similarity search
|
||||
- Keyword-based search
|
||||
- Metadata filtering
|
||||
- **Batch Processing**: Efficient handling of multiple operations
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. Verify your configuration file syntax
|
||||
2. Ensure all paths are absolute and valid
|
||||
3. Try using full paths for `uvx` with `which uvx` and using that path in the config
|
||||
4. Check the Claude logs (paths listed above)
|
||||
|
||||
## Resources
|
||||
|
||||
- [Model Context Protocol Documentation](https://modelcontextprotocol.io/introduction)
|
||||
- [Chroma MCP Server Documentation](https://github.com/chroma-core/chroma-mcp)
|
||||
- [Claude Desktop Guide](https://docs.anthropic.com/claude/docs/claude-desktop)
|
||||
@@ -1,92 +0,0 @@
|
||||
### Team Knowledge Base Example
|
||||
|
||||
Let's say your team maintains a knowledge base of customer support interactions. By storing these in Chroma Cloud, team members can use Claude to quickly access and learn from past support cases.
|
||||
|
||||
First, set up your shared knowledge base:
|
||||
|
||||
```python
|
||||
import chromadb
|
||||
from datetime import datetime
|
||||
|
||||
# Connect to Chroma Cloud
|
||||
client = chromadb.HttpClient(
|
||||
ssl=True,
|
||||
host='api.trychroma.com',
|
||||
tenant='your-tenant-id',
|
||||
database='support-kb',
|
||||
headers={
|
||||
'x-chroma-token': 'YOUR_API_KEY'
|
||||
}
|
||||
)
|
||||
|
||||
# Create a collection for support cases
|
||||
collection = client.create_collection("support_cases")
|
||||
|
||||
# Add some example support cases
|
||||
support_cases = [
|
||||
{
|
||||
"case": "Customer reported issues connecting their IoT devices to the dashboard.",
|
||||
"resolution": "Guided customer through firewall configuration and port forwarding setup.",
|
||||
"category": "connectivity",
|
||||
"date": "2024-03-15"
|
||||
},
|
||||
{
|
||||
"case": "User couldn't access admin features after recent update.",
|
||||
"resolution": "Discovered role permissions weren't migrated correctly. Applied fix and documented process.",
|
||||
"category": "permissions",
|
||||
"date": "2024-03-16"
|
||||
}
|
||||
]
|
||||
|
||||
# Add documents to collection
|
||||
collection.add(
|
||||
documents=[case["case"] + "\n" + case["resolution"] for case in support_cases],
|
||||
metadatas=[{
|
||||
"category": case["category"],
|
||||
"date": case["date"]
|
||||
} for case in support_cases],
|
||||
ids=[f"case_{i}" for i in range(len(support_cases))]
|
||||
)
|
||||
```
|
||||
|
||||
Now team members can use Claude to access this knowledge.
|
||||
|
||||
In your claude config, add the following:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"chroma": {
|
||||
"command": "uvx",
|
||||
"args": [
|
||||
"chroma-mcp",
|
||||
"--client-type",
|
||||
"cloud",
|
||||
"--tenant",
|
||||
"your-tenant-id",
|
||||
"--database",
|
||||
"support-kb",
|
||||
"--api-key",
|
||||
"YOUR_API_KEY"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now you can use the knowledge base in your chats:
|
||||
```
|
||||
Claude, I'm having trouble helping a customer with IoT device connectivity.
|
||||
Can you check our support knowledge base for similar cases and suggest a solution?
|
||||
```
|
||||
|
||||
Claude will:
|
||||
1. Search the shared knowledge base for relevant cases
|
||||
2. Consider the context and solutions from similar past issues
|
||||
3. Provide recommendations based on previous successful resolutions
|
||||
|
||||
This setup is particularly powerful because:
|
||||
- All support team members have access to the same knowledge base
|
||||
- Claude can learn from the entire team's experience
|
||||
- Solutions are standardized across the organization
|
||||
- New team members can quickly get up to speed on common issues
|
||||
|
||||
@@ -1,787 +0,0 @@
|
||||
# Hooks reference
|
||||
|
||||
> This page provides reference documentation for implementing hooks in Claude Code.
|
||||
|
||||
<Tip>
|
||||
For a quickstart guide with examples, see [Get started with Claude Code hooks](/en/docs/claude-code/hooks-guide).
|
||||
</Tip>
|
||||
|
||||
## Configuration
|
||||
|
||||
Claude Code hooks are configured in your [settings files](/en/docs/claude-code/settings):
|
||||
|
||||
* `~/.claude/settings.json` - User settings
|
||||
* `.claude/settings.json` - Project settings
|
||||
* `.claude/settings.local.json` - Local project settings (not committed)
|
||||
* Enterprise managed policy settings
|
||||
|
||||
### Structure
|
||||
|
||||
Hooks are organized by matchers, where each matcher can have multiple hooks:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"EventName": [
|
||||
{
|
||||
"matcher": "ToolPattern",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "your-command-here"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* **matcher**: Pattern to match tool names, case-sensitive (only applicable for
|
||||
`PreToolUse` and `PostToolUse`)
|
||||
* Simple strings match exactly: `Write` matches only the Write tool
|
||||
* Supports regex: `Edit|Write` or `Notebook.*`
|
||||
* Use `*` to match all tools. You can also use empty string (`""`) or leave
|
||||
`matcher` blank.
|
||||
* **hooks**: Array of commands to execute when the pattern matches
|
||||
* `type`: Currently only `"command"` is supported
|
||||
* `command`: The bash command to execute (can use `$CLAUDE_PROJECT_DIR`
|
||||
environment variable)
|
||||
* `timeout`: (Optional) How long a command should run, in seconds, before
|
||||
canceling that specific command.
|
||||
|
||||
For events like `UserPromptSubmit`, `Notification`, `Stop`, and `SubagentStop`
|
||||
that don't use matchers, you can omit the matcher field:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "/path/to/prompt-validator.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Project-Specific Hook Scripts
|
||||
|
||||
You can use the environment variable `CLAUDE_PROJECT_DIR` (only available when
|
||||
Claude Code spawns the hook command) to reference scripts stored in your project,
|
||||
ensuring they work regardless of Claude's current directory:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Write|Edit",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-style.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Events
|
||||
|
||||
### PreToolUse
|
||||
|
||||
Runs after Claude creates tool parameters and before processing the tool call.
|
||||
|
||||
**Common matchers:**
|
||||
|
||||
* `Task` - Subagent tasks (see [subagents documentation](/en/docs/claude-code/sub-agents))
|
||||
* `Bash` - Shell commands
|
||||
* `Glob` - File pattern matching
|
||||
* `Grep` - Content search
|
||||
* `Read` - File reading
|
||||
* `Edit`, `MultiEdit` - File editing
|
||||
* `Write` - File writing
|
||||
* `WebFetch`, `WebSearch` - Web operations
|
||||
|
||||
### PostToolUse
|
||||
|
||||
Runs immediately after a tool completes successfully.
|
||||
|
||||
Recognizes the same matcher values as PreToolUse.
|
||||
|
||||
### Notification
|
||||
|
||||
Runs when Claude Code sends notifications. Notifications are sent when:
|
||||
|
||||
1. Claude needs your permission to use a tool. Example: "Claude needs your
|
||||
permission to use Bash"
|
||||
2. The prompt input has been idle for at least 60 seconds. "Claude is waiting
|
||||
for your input"
|
||||
|
||||
### UserPromptSubmit
|
||||
|
||||
Runs when the user submits a prompt, before Claude processes it. This allows you
|
||||
to add additional context based on the prompt/conversation, validate prompts, or
|
||||
block certain types of prompts.
|
||||
|
||||
### Stop
|
||||
|
||||
Runs when the main Claude Code agent has finished responding. Does not run if
|
||||
the stoppage occurred due to a user interrupt.
|
||||
|
||||
### SubagentStop
|
||||
|
||||
Runs when a Claude Code subagent (Task tool call) has finished responding.
|
||||
|
||||
### SessionEnd
|
||||
|
||||
Runs when a Claude Code session ends. Useful for cleanup tasks, logging session
|
||||
statistics, or saving session state.
|
||||
|
||||
The `reason` field in the hook input will be one of:
|
||||
|
||||
* `clear` - Session cleared with /clear command
|
||||
* `logout` - User logged out
|
||||
* `prompt_input_exit` - User exited while prompt input was visible
|
||||
* `other` - Other exit reasons
|
||||
|
||||
### PreCompact
|
||||
|
||||
Runs before Claude Code is about to run a compact operation.
|
||||
|
||||
**Matchers:**
|
||||
|
||||
* `manual` - Invoked from `/compact`
|
||||
* `auto` - Invoked from auto-compact (due to full context window)
|
||||
|
||||
### SessionStart
|
||||
|
||||
Runs when Claude Code starts a new session or resumes an existing session (which
|
||||
currently does start a new session under the hood). Useful for loading in
|
||||
development context like existing issues or recent changes to your codebase.
|
||||
|
||||
**Matchers:**
|
||||
|
||||
* `startup` - Invoked from startup
|
||||
* `resume` - Invoked from `--resume`, `--continue`, or `/resume`
|
||||
* `clear` - Invoked from `/clear`
|
||||
|
||||
## Hook Input
|
||||
|
||||
Hooks receive JSON data via stdin containing session information and
|
||||
event-specific data:
|
||||
|
||||
```typescript
|
||||
{
|
||||
// Common fields
|
||||
session_id: string
|
||||
transcript_path: string // Path to conversation JSON
|
||||
cwd: string // The current working directory when the hook is invoked
|
||||
|
||||
// Event-specific fields
|
||||
hook_event_name: string
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### PreToolUse Input
|
||||
|
||||
The exact schema for `tool_input` depends on the tool.
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"cwd": "/Users/...",
|
||||
"hook_event_name": "PreToolUse",
|
||||
"tool_name": "Write",
|
||||
"tool_input": {
|
||||
"file_path": "/path/to/file.txt",
|
||||
"content": "file content"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PostToolUse Input
|
||||
|
||||
The exact schema for `tool_input` and `tool_response` depends on the tool.
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"cwd": "/Users/...",
|
||||
"hook_event_name": "PostToolUse",
|
||||
"tool_name": "Write",
|
||||
"tool_input": {
|
||||
"file_path": "/path/to/file.txt",
|
||||
"content": "file content"
|
||||
},
|
||||
"tool_response": {
|
||||
"filePath": "/path/to/file.txt",
|
||||
"success": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Notification Input
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"cwd": "/Users/...",
|
||||
"hook_event_name": "Notification",
|
||||
"message": "Task completed successfully"
|
||||
}
|
||||
```
|
||||
|
||||
### UserPromptSubmit Input
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"cwd": "/Users/...",
|
||||
"hook_event_name": "UserPromptSubmit",
|
||||
"prompt": "Write a function to calculate the factorial of a number"
|
||||
}
|
||||
```
|
||||
|
||||
### Stop and SubagentStop Input
|
||||
|
||||
`stop_hook_active` is true when Claude Code is already continuing as a result of
|
||||
a stop hook. Check this value or process the transcript to prevent Claude Code
|
||||
from running indefinitely.
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"hook_event_name": "Stop",
|
||||
"stop_hook_active": true
|
||||
}
|
||||
```
|
||||
|
||||
### PreCompact Input
|
||||
|
||||
For `manual`, `custom_instructions` comes from what the user passes into
|
||||
`/compact`. For `auto`, `custom_instructions` is empty.
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"hook_event_name": "PreCompact",
|
||||
"trigger": "manual",
|
||||
"custom_instructions": ""
|
||||
}
|
||||
```
|
||||
|
||||
### SessionStart Input
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"hook_event_name": "SessionStart",
|
||||
"source": "startup"
|
||||
}
|
||||
```
|
||||
|
||||
### SessionEnd Input
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "abc123",
|
||||
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
|
||||
"cwd": "/Users/...",
|
||||
"hook_event_name": "SessionEnd",
|
||||
"reason": "exit"
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Output
|
||||
|
||||
There are two ways for hooks to return output back to Claude Code. The output
|
||||
communicates whether to block and any feedback that should be shown to Claude
|
||||
and the user.
|
||||
|
||||
### Simple: Exit Code
|
||||
|
||||
Hooks communicate status through exit codes, stdout, and stderr:
|
||||
|
||||
* **Exit code 0**: Success. `stdout` is shown to the user in transcript mode
|
||||
(CTRL-R), except for `UserPromptSubmit` and `SessionStart`, where stdout is
|
||||
added to the context.
|
||||
* **Exit code 2**: Blocking error. `stderr` is fed back to Claude to process
|
||||
automatically. See per-hook-event behavior below.
|
||||
* **Other exit codes**: Non-blocking error. `stderr` is shown to the user and
|
||||
execution continues.
|
||||
|
||||
<Warning>
|
||||
Reminder: Claude Code does not see stdout if the exit code is 0, except for
|
||||
the `UserPromptSubmit` hook where stdout is injected as context.
|
||||
</Warning>
|
||||
|
||||
#### Exit Code 2 Behavior
|
||||
|
||||
| Hook Event | Behavior |
|
||||
| ------------------ | ------------------------------------------------------------------ |
|
||||
| `PreToolUse` | Blocks the tool call, shows stderr to Claude |
|
||||
| `PostToolUse` | Shows stderr to Claude (tool already ran) |
|
||||
| `Notification` | N/A, shows stderr to user only |
|
||||
| `UserPromptSubmit` | Blocks prompt processing, erases prompt, shows stderr to user only |
|
||||
| `Stop` | Blocks stoppage, shows stderr to Claude |
|
||||
| `SubagentStop` | Blocks stoppage, shows stderr to Claude subagent |
|
||||
| `PreCompact` | N/A, shows stderr to user only |
|
||||
| `SessionStart` | N/A, shows stderr to user only |
|
||||
| `SessionEnd` | N/A, shows stderr to user only |
|
||||
|
||||
### Advanced: JSON Output
|
||||
|
||||
Hooks can return structured JSON in `stdout` for more sophisticated control:
|
||||
|
||||
#### Common JSON Fields
|
||||
|
||||
All hook types can include these optional fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"continue": true, // Whether Claude should continue after hook execution (default: true)
|
||||
"stopReason": "string", // Message shown when continue is false
|
||||
|
||||
"suppressOutput": true, // Hide stdout from transcript mode (default: false)
|
||||
"systemMessage": "string" // Optional warning message shown to the user
|
||||
}
|
||||
```
|
||||
|
||||
If `continue` is false, Claude stops processing after the hooks run.
|
||||
|
||||
* For `PreToolUse`, this is different from `"permissionDecision": "deny"`, which
|
||||
only blocks a specific tool call and provides automatic feedback to Claude.
|
||||
* For `PostToolUse`, this is different from `"decision": "block"`, which
|
||||
provides automated feedback to Claude.
|
||||
* For `UserPromptSubmit`, this prevents the prompt from being processed.
|
||||
* For `Stop` and `SubagentStop`, this takes precedence over any
|
||||
`"decision": "block"` output.
|
||||
* In all cases, `"continue" = false` takes precedence over any
|
||||
`"decision": "block"` output.
|
||||
|
||||
`stopReason` accompanies `continue` with a reason shown to the user, not shown
|
||||
to Claude.
|
||||
|
||||
#### `PreToolUse` Decision Control
|
||||
|
||||
`PreToolUse` hooks can control whether a tool call proceeds.
|
||||
|
||||
* `"allow"` bypasses the permission system. `permissionDecisionReason` is shown
|
||||
to the user but not to Claude.
|
||||
* `"deny"` prevents the tool call from executing. `permissionDecisionReason` is
|
||||
shown to Claude.
|
||||
* `"ask"` asks the user to confirm the tool call in the UI.
|
||||
`permissionDecisionReason` is shown to the user but not to Claude.
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PreToolUse",
|
||||
"permissionDecision": "allow" | "deny" | "ask",
|
||||
"permissionDecisionReason": "My reason here"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<Note>
|
||||
The `decision` and `reason` fields are deprecated for PreToolUse hooks.
|
||||
Use `hookSpecificOutput.permissionDecision` and
|
||||
`hookSpecificOutput.permissionDecisionReason` instead. The deprecated fields
|
||||
`"approve"` and `"block"` map to `"allow"` and `"deny"` respectively.
|
||||
</Note>
|
||||
|
||||
#### `PostToolUse` Decision Control
|
||||
|
||||
`PostToolUse` hooks can provide feedback to Claude after tool execution.
|
||||
|
||||
* `"block"` automatically prompts Claude with `reason`.
|
||||
* `undefined` does nothing. `reason` is ignored.
|
||||
* `"hookSpecificOutput.additionalContext"` adds context for Claude to consider.
|
||||
|
||||
```json
|
||||
{
|
||||
"decision": "block" | undefined,
|
||||
"reason": "Explanation for decision",
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PostToolUse",
|
||||
"additionalContext": "Additional information for Claude"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `UserPromptSubmit` Decision Control
|
||||
|
||||
`UserPromptSubmit` hooks can control whether a user prompt is processed.
|
||||
|
||||
* `"block"` prevents the prompt from being processed. The submitted prompt is
|
||||
erased from context. `"reason"` is shown to the user but not added to context.
|
||||
* `undefined` allows the prompt to proceed normally. `"reason"` is ignored.
|
||||
* `"hookSpecificOutput.additionalContext"` adds the string to the context if not
|
||||
blocked.
|
||||
|
||||
```json
|
||||
{
|
||||
"decision": "block" | undefined,
|
||||
"reason": "Explanation for decision",
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "UserPromptSubmit",
|
||||
"additionalContext": "My additional context here"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `Stop`/`SubagentStop` Decision Control
|
||||
|
||||
`Stop` and `SubagentStop` hooks can control whether Claude must continue.
|
||||
|
||||
* `"block"` prevents Claude from stopping. You must populate `reason` for Claude
|
||||
to know how to proceed.
|
||||
* `undefined` allows Claude to stop. `reason` is ignored.
|
||||
|
||||
```json
|
||||
{
|
||||
"decision": "block" | undefined,
|
||||
"reason": "Must be provided when Claude is blocked from stopping"
|
||||
}
|
||||
```
|
||||
|
||||
#### `SessionStart` Decision Control
|
||||
|
||||
`SessionStart` hooks allow you to load in context at the start of a session.
|
||||
|
||||
* `"hookSpecificOutput.additionalContext"` adds the string to the context.
|
||||
* Multiple hooks' `additionalContext` values are concatenated.
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "My additional context here"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `SessionEnd` Decision Control
|
||||
|
||||
`SessionEnd` hooks run when a session ends. They cannot block session termination
|
||||
but can perform cleanup tasks.
|
||||
|
||||
#### Exit Code Example: Bash Command Validation
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Define validation rules as a list of (regex pattern, message) tuples
|
||||
VALIDATION_RULES = [
|
||||
(
|
||||
r"\bgrep\b(?!.*\|)",
|
||||
"Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
|
||||
),
|
||||
(
|
||||
r"\bfind\s+\S+\s+-name\b",
|
||||
"Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def validate_command(command: str) -> list[str]:
|
||||
issues = []
|
||||
for pattern, message in VALIDATION_RULES:
|
||||
if re.search(pattern, command):
|
||||
issues.append(message)
|
||||
return issues
|
||||
|
||||
|
||||
try:
|
||||
input_data = json.load(sys.stdin)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
tool_name = input_data.get("tool_name", "")
|
||||
tool_input = input_data.get("tool_input", {})
|
||||
command = tool_input.get("command", "")
|
||||
|
||||
if tool_name != "Bash" or not command:
|
||||
sys.exit(1)
|
||||
|
||||
# Validate the command
|
||||
issues = validate_command(command)
|
||||
|
||||
if issues:
|
||||
for message in issues:
|
||||
print(f"• {message}", file=sys.stderr)
|
||||
# Exit code 2 blocks tool call and shows stderr to Claude
|
||||
sys.exit(2)
|
||||
```
|
||||
|
||||
#### JSON Output Example: UserPromptSubmit to Add Context and Validation
|
||||
|
||||
<Note>
|
||||
For `UserPromptSubmit` hooks, you can inject context using either method:
|
||||
|
||||
* Exit code 0 with stdout: Claude sees the context (special case for `UserPromptSubmit`)
|
||||
* JSON output: Provides more control over the behavior
|
||||
</Note>
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import sys
|
||||
import re
|
||||
import datetime
|
||||
|
||||
# Load input from stdin
|
||||
try:
|
||||
input_data = json.load(sys.stdin)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
prompt = input_data.get("prompt", "")
|
||||
|
||||
# Check for sensitive patterns
|
||||
sensitive_patterns = [
|
||||
(r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
|
||||
]
|
||||
|
||||
for pattern, message in sensitive_patterns:
|
||||
if re.search(pattern, prompt):
|
||||
# Use JSON output to block with a specific reason
|
||||
output = {
|
||||
"decision": "block",
|
||||
"reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
|
||||
}
|
||||
print(json.dumps(output))
|
||||
sys.exit(0)
|
||||
|
||||
# Add current time to context
|
||||
context = f"Current time: {datetime.datetime.now()}"
|
||||
print(context)
|
||||
|
||||
"""
|
||||
The following is also equivalent:
|
||||
print(json.dumps({
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "UserPromptSubmit",
|
||||
"additionalContext": context,
|
||||
},
|
||||
}))
|
||||
"""
|
||||
|
||||
# Allow the prompt to proceed with the additional context
|
||||
sys.exit(0)
|
||||
```
|
||||
|
||||
#### JSON Output Example: PreToolUse with Approval
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import sys
|
||||
|
||||
# Load input from stdin
|
||||
try:
|
||||
input_data = json.load(sys.stdin)
|
||||
except json.JSONDecodeError as e:
|
||||
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
tool_name = input_data.get("tool_name", "")
|
||||
tool_input = input_data.get("tool_input", {})
|
||||
|
||||
# Example: Auto-approve file reads for documentation files
|
||||
if tool_name == "Read":
|
||||
file_path = tool_input.get("file_path", "")
|
||||
if file_path.endswith((".md", ".mdx", ".txt", ".json")):
|
||||
# Use JSON output to auto-approve the tool call
|
||||
output = {
|
||||
"decision": "approve",
|
||||
"reason": "Documentation file auto-approved",
|
||||
"suppressOutput": True # Don't show in transcript mode
|
||||
}
|
||||
print(json.dumps(output))
|
||||
sys.exit(0)
|
||||
|
||||
# For other cases, let the normal permission flow proceed
|
||||
sys.exit(0)
|
||||
```
|
||||
|
||||
## Working with MCP Tools
|
||||
|
||||
Claude Code hooks work seamlessly with
|
||||
[Model Context Protocol (MCP) tools](/en/docs/claude-code/mcp). When MCP servers
|
||||
provide tools, they appear with a special naming pattern that you can match in
|
||||
your hooks.
|
||||
|
||||
### MCP Tool Naming
|
||||
|
||||
MCP tools follow the pattern `mcp__<server>__<tool>`, for example:
|
||||
|
||||
* `mcp__memory__create_entities` - Memory server's create entities tool
|
||||
* `mcp__filesystem__read_file` - Filesystem server's read file tool
|
||||
* `mcp__github__search_repositories` - GitHub server's search tool
|
||||
|
||||
### Configuring Hooks for MCP Tools
|
||||
|
||||
You can target specific MCP tools or entire MCP servers:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "mcp__memory__.*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "mcp__.*__write.*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "/home/user/scripts/validate-mcp-write.py"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
<Tip>
|
||||
For practical examples including code formatting, notifications, and file protection, see [More Examples](/en/docs/claude-code/hooks-guide#more-examples) in the get started guide.
|
||||
</Tip>
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Disclaimer
|
||||
|
||||
**USE AT YOUR OWN RISK**: Claude Code hooks execute arbitrary shell commands on
|
||||
your system automatically. By using hooks, you acknowledge that:
|
||||
|
||||
* You are solely responsible for the commands you configure
|
||||
* Hooks can modify, delete, or access any files your user account can access
|
||||
* Malicious or poorly written hooks can cause data loss or system damage
|
||||
* Anthropic provides no warranty and assumes no liability for any damages
|
||||
resulting from hook usage
|
||||
* You should thoroughly test hooks in a safe environment before production use
|
||||
|
||||
Always review and understand any hook commands before adding them to your
|
||||
configuration.
|
||||
|
||||
### Security Best Practices
|
||||
|
||||
Here are some key practices for writing more secure hooks:
|
||||
|
||||
1. **Validate and sanitize inputs** - Never trust input data blindly
|
||||
2. **Always quote shell variables** - Use `"$VAR"` not `$VAR`
|
||||
3. **Block path traversal** - Check for `..` in file paths
|
||||
4. **Use absolute paths** - Specify full paths for scripts (use
|
||||
`$CLAUDE_PROJECT_DIR` for the project path)
|
||||
5. **Skip sensitive files** - Avoid `.env`, `.git/`, keys, etc.
|
||||
|
||||
### Configuration Safety
|
||||
|
||||
Direct edits to hooks in settings files don't take effect immediately. Claude
|
||||
Code:
|
||||
|
||||
1. Captures a snapshot of hooks at startup
|
||||
2. Uses this snapshot throughout the session
|
||||
3. Warns if hooks are modified externally
|
||||
4. Requires review in `/hooks` menu for changes to apply
|
||||
|
||||
This prevents malicious hook modifications from affecting your current session.
|
||||
|
||||
## Hook Execution Details
|
||||
|
||||
* **Timeout**: 60-second execution limit by default, configurable per command.
|
||||
* A timeout for an individual command does not affect the other commands.
|
||||
* **Parallelization**: All matching hooks run in parallel
|
||||
* **Deduplication**: Multiple identical hook commands are deduplicated automatically
|
||||
* **Environment**: Runs in current directory with Claude Code's environment
|
||||
* The `CLAUDE_PROJECT_DIR` environment variable is available and contains the
|
||||
absolute path to the project root directory (where Claude Code was started)
|
||||
* **Input**: JSON via stdin
|
||||
* **Output**:
|
||||
* PreToolUse/PostToolUse/Stop/SubagentStop: Progress shown in transcript (Ctrl-R)
|
||||
* Notification/SessionEnd: Logged to debug only (`--debug`)
|
||||
* UserPromptSubmit/SessionStart: stdout added as context for Claude
|
||||
|
||||
## Debugging
|
||||
|
||||
### Basic Troubleshooting
|
||||
|
||||
If your hooks aren't working:
|
||||
|
||||
1. **Check configuration** - Run `/hooks` to see if your hook is registered
|
||||
2. **Verify syntax** - Ensure your JSON settings are valid
|
||||
3. **Test commands** - Run hook commands manually first
|
||||
4. **Check permissions** - Make sure scripts are executable
|
||||
5. **Review logs** - Use `claude --debug` to see hook execution details
|
||||
|
||||
Common issues:
|
||||
|
||||
* **Quotes not escaped** - Use `\"` inside JSON strings
|
||||
* **Wrong matcher** - Check tool names match exactly (case-sensitive)
|
||||
* **Command not found** - Use full paths for scripts
|
||||
|
||||
### Advanced Debugging
|
||||
|
||||
For complex hook issues:
|
||||
|
||||
1. **Inspect hook execution** - Use `claude --debug` to see detailed hook
|
||||
execution
|
||||
2. **Validate JSON schemas** - Test hook input/output with external tools
|
||||
3. **Check environment variables** - Verify Claude Code's environment is correct
|
||||
4. **Test edge cases** - Try hooks with unusual file paths or inputs
|
||||
5. **Monitor system resources** - Check for resource exhaustion during hook
|
||||
execution
|
||||
6. **Use structured logging** - Implement logging in your hook scripts
|
||||
|
||||
### Debug Output Example
|
||||
|
||||
Use `claude --debug` to see hook execution details:
|
||||
|
||||
```
|
||||
[DEBUG] Executing hooks for PostToolUse:Write
|
||||
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
|
||||
[DEBUG] Found 1 hook matchers in settings
|
||||
[DEBUG] Matched 1 hooks for query "Write"
|
||||
[DEBUG] Found 1 hook commands to execute
|
||||
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
|
||||
[DEBUG] Hook command completed with status 0: <Your stdout>
|
||||
```
|
||||
|
||||
Progress messages appear in transcript mode (Ctrl-R) showing:
|
||||
|
||||
* Which hook is running
|
||||
* Command being executed
|
||||
* Success/failure status
|
||||
* Output or error messages
|
||||
@@ -1,202 +0,0 @@
|
||||
# Status line configuration
|
||||
|
||||
> Create a custom status line for Claude Code to display contextual information
|
||||
|
||||
Make Claude Code your own with a custom status line that displays at the bottom of the Claude Code interface, similar to how terminal prompts (PS1) work in shells like Oh-my-zsh.
|
||||
|
||||
## Create a custom status line
|
||||
|
||||
You can either:
|
||||
|
||||
* Run `/statusline` to ask Claude Code to help you set up a custom status line. By default, it will try to reproduce your terminal's prompt, but you can provide additional instructions about the behavior you want to Claude Code, such as `/statusline show the model name in orange`
|
||||
|
||||
* Directly add a `statusLine` command to your `.claude/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"statusLine": {
|
||||
"type": "command",
|
||||
"command": "~/.claude/statusline.sh",
|
||||
"padding": 0 // Optional: set to 0 to let status line go to edge
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## How it Works
|
||||
|
||||
* The status line is updated when the conversation messages update
|
||||
* Updates run at most every 300ms
|
||||
* The first line of stdout from your command becomes the status line text
|
||||
* ANSI color codes are supported for styling your status line
|
||||
* Claude Code passes contextual information about the current session (model, directories, etc.) as JSON to your script via stdin
|
||||
|
||||
## JSON Input Structure
|
||||
|
||||
Your status line command receives structured data via stdin in JSON format:
|
||||
|
||||
```json
|
||||
{
|
||||
"hook_event_name": "Status",
|
||||
"session_id": "abc123...",
|
||||
"transcript_path": "/path/to/transcript.json",
|
||||
"cwd": "/current/working/directory",
|
||||
"model": {
|
||||
"id": "claude-opus-4-1",
|
||||
"display_name": "Opus"
|
||||
},
|
||||
"workspace": {
|
||||
"current_dir": "/current/working/directory",
|
||||
"project_dir": "/original/project/directory"
|
||||
},
|
||||
"version": "1.0.80",
|
||||
"output_style": {
|
||||
"name": "default"
|
||||
},
|
||||
"cost": {
|
||||
"total_cost_usd": 0.01234,
|
||||
"total_duration_ms": 45000,
|
||||
"total_api_duration_ms": 2300,
|
||||
"total_lines_added": 156,
|
||||
"total_lines_removed": 23
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example Scripts
|
||||
|
||||
### Simple Status Line
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Read JSON input from stdin
|
||||
input=$(cat)
|
||||
|
||||
# Extract values using jq
|
||||
MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name')
|
||||
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
|
||||
|
||||
echo "[$MODEL_DISPLAY] 📁 ${CURRENT_DIR##*/}"
|
||||
```
|
||||
|
||||
### Git-Aware Status Line
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Read JSON input from stdin
|
||||
input=$(cat)
|
||||
|
||||
# Extract values using jq
|
||||
MODEL_DISPLAY=$(echo "$input" | jq -r '.model.display_name')
|
||||
CURRENT_DIR=$(echo "$input" | jq -r '.workspace.current_dir')
|
||||
|
||||
# Show git branch if in a git repo
|
||||
GIT_BRANCH=""
|
||||
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
BRANCH=$(git branch --show-current 2>/dev/null)
|
||||
if [ -n "$BRANCH" ]; then
|
||||
GIT_BRANCH=" | 🌿 $BRANCH"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[$MODEL_DISPLAY] 📁 ${CURRENT_DIR##*/}$GIT_BRANCH"
|
||||
```
|
||||
|
||||
### Python Example
|
||||
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
|
||||
# Read JSON from stdin
|
||||
data = json.load(sys.stdin)
|
||||
|
||||
# Extract values
|
||||
model = data['model']['display_name']
|
||||
current_dir = os.path.basename(data['workspace']['current_dir'])
|
||||
|
||||
# Check for git branch
|
||||
git_branch = ""
|
||||
if os.path.exists('.git'):
|
||||
try:
|
||||
with open('.git/HEAD', 'r') as f:
|
||||
ref = f.read().strip()
|
||||
if ref.startswith('ref: refs/heads/'):
|
||||
git_branch = f" | 🌿 {ref.replace('ref: refs/heads/', '')}"
|
||||
except:
|
||||
pass
|
||||
|
||||
print(f"[{model}] 📁 {current_dir}{git_branch}")
|
||||
```
|
||||
|
||||
### Node.js Example
|
||||
|
||||
```javascript
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Read JSON from stdin
|
||||
let input = '';
|
||||
process.stdin.on('data', chunk => input += chunk);
|
||||
process.stdin.on('end', () => {
|
||||
const data = JSON.parse(input);
|
||||
|
||||
// Extract values
|
||||
const model = data.model.display_name;
|
||||
const currentDir = path.basename(data.workspace.current_dir);
|
||||
|
||||
// Check for git branch
|
||||
let gitBranch = '';
|
||||
try {
|
||||
const headContent = fs.readFileSync('.git/HEAD', 'utf8').trim();
|
||||
if (headContent.startsWith('ref: refs/heads/')) {
|
||||
gitBranch = ` | 🌿 ${headContent.replace('ref: refs/heads/', '')}`;
|
||||
}
|
||||
} catch (e) {
|
||||
// Not a git repo or can't read HEAD
|
||||
}
|
||||
|
||||
console.log(`[${model}] 📁 ${currentDir}${gitBranch}`);
|
||||
});
|
||||
```
|
||||
|
||||
### Helper Function Approach
|
||||
|
||||
For more complex bash scripts, you can create helper functions:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Read JSON input once
|
||||
input=$(cat)
|
||||
|
||||
# Helper functions for common extractions
|
||||
get_model_name() { echo "$input" | jq -r '.model.display_name'; }
|
||||
get_current_dir() { echo "$input" | jq -r '.workspace.current_dir'; }
|
||||
get_project_dir() { echo "$input" | jq -r '.workspace.project_dir'; }
|
||||
get_version() { echo "$input" | jq -r '.version'; }
|
||||
get_cost() { echo "$input" | jq -r '.cost.total_cost_usd'; }
|
||||
get_duration() { echo "$input" | jq -r '.cost.total_duration_ms'; }
|
||||
get_lines_added() { echo "$input" | jq -r '.cost.total_lines_added'; }
|
||||
get_lines_removed() { echo "$input" | jq -r '.cost.total_lines_removed'; }
|
||||
|
||||
# Use the helpers
|
||||
MODEL=$(get_model_name)
|
||||
DIR=$(get_current_dir)
|
||||
echo "[$MODEL] 📁 ${DIR##*/}"
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
* Keep your status line concise - it should fit on one line
|
||||
* Use emojis (if your terminal supports them) and colors to make information scannable
|
||||
* Use `jq` for JSON parsing in Bash (see examples above)
|
||||
* Test your script by running it manually with mock JSON input: `echo '{"model":{"display_name":"Test"},"workspace":{"current_dir":"/test"}}' | ./statusline.sh`
|
||||
* Consider caching expensive operations (like git status) if needed
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* If your status line doesn't appear, check that your script is executable (`chmod +x`)
|
||||
* Ensure your script outputs to stdout (not stderr)
|
||||
@@ -1,173 +0,0 @@
|
||||
# Claude Code Hook Configuration Documentation
|
||||
|
||||
**LOCKED by @docs-agent | Change to 🔑 to allow @docs-agent edits**
|
||||
|
||||
## Official Documentation Reference
|
||||
|
||||
- **Source**: Claude Code Hooks API Documentation
|
||||
- **Version**: v2025
|
||||
- **Last Verified**: 2025-08-31
|
||||
- **Official URL**: https://docs.anthropic.com/en/docs/claude-code/hooks
|
||||
|
||||
## Hook Configuration Structure
|
||||
|
||||
### Two Categories of Hooks
|
||||
|
||||
Claude Code hooks are divided into two distinct categories with different configuration structures:
|
||||
|
||||
#### 1. Tool-Related Hooks
|
||||
These hooks are triggered in relation to tool usage and require a `matcher` field:
|
||||
- `PreToolUse`: Executed before a tool is invoked
|
||||
- `PostToolUse`: Executed after a tool completes
|
||||
|
||||
**Configuration Structure:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Edit|MultiEdit|Write",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "/path/to/script.js",
|
||||
"timeout": 60000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Non-Tool Hooks
|
||||
These hooks are triggered by system events and **MUST NOT** have a `matcher` or `pattern` field:
|
||||
- `PreCompact`: Before conversation compaction
|
||||
- `SessionStart`: When a new session begins
|
||||
- `SessionEnd`: When a session ends
|
||||
- `UserPromptSubmit`: When user submits a prompt
|
||||
- `Notification`: For system notifications
|
||||
- `Stop`: When Claude is stopping
|
||||
- `SubagentStop`: When a subagent is stopping
|
||||
|
||||
**Configuration Structure:**
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "/path/to/script.js",
|
||||
"timeout": 30000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Common Configuration Mistakes
|
||||
|
||||
### ❌ INCORRECT: Adding `pattern` field to non-tool hooks
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreCompact": [
|
||||
{
|
||||
"pattern": "*", // WRONG: Non-tool hooks don't use patterns
|
||||
"hooks": [...]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ CORRECT: Non-tool hooks without matcher
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreCompact": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "/path/to/pre-compact.js",
|
||||
"timeout": 180000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Hook Field Reference
|
||||
|
||||
### Common Fields (All Hooks)
|
||||
- `type`: Always `"command"` for external scripts
|
||||
- `command`: Absolute path to the executable script
|
||||
- `timeout`: Optional timeout in milliseconds (default: 60000)
|
||||
|
||||
### Tool Hook Specific
|
||||
- `matcher`: Regex pattern to match tool names
|
||||
- Example: `"Edit|MultiEdit|Write"`
|
||||
- Example: `"mcp__.*__write.*"`
|
||||
- Example: `"Bash"`
|
||||
|
||||
### Environment Variables Available to Hooks
|
||||
- `$CLAUDE_PROJECT_DIR`: Project root directory
|
||||
- Standard environment variables from the shell
|
||||
|
||||
## Hook Input/Output
|
||||
|
||||
### Input (via stdin)
|
||||
All hooks receive JSON input with common fields:
|
||||
```json
|
||||
{
|
||||
"session_id": "string",
|
||||
"transcript_path": "string",
|
||||
"cwd": "string",
|
||||
"hook_event_name": "string",
|
||||
// Additional event-specific fields
|
||||
}
|
||||
```
|
||||
|
||||
### Output Options
|
||||
Hooks can output:
|
||||
1. **Plain text** (stdout): Added as context
|
||||
2. **JSON** (stdout): Structured response for decisions
|
||||
3. **Exit codes**:
|
||||
- `0`: Success, continue normally
|
||||
- `1`: General error
|
||||
- `2`: Block operation (for PreToolUse)
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### File Locations
|
||||
- User settings: `~/.claude/settings.json`
|
||||
- Project settings: `./.claude/settings.json`
|
||||
- Local settings: `./.claude/settings.local.json`
|
||||
|
||||
### Settings Precedence (Highest to Lowest)
|
||||
1. Enterprise managed policies
|
||||
2. Command line arguments
|
||||
3. Local project settings
|
||||
4. Shared project settings
|
||||
5. User settings
|
||||
|
||||
## Cross-References
|
||||
|
||||
- Code Implementation: `/Users/alexnewman/Scripts/claude-mem/src/commands/install.ts:263-320`
|
||||
- Hook Files: `/Users/alexnewman/Scripts/claude-mem/hooks/`
|
||||
- User Guide: `/Users/alexnewman/Scripts/claude-mem/README-npm.md`
|
||||
|
||||
## Version History
|
||||
|
||||
- **2025-08-31**: Fixed hook configuration to remove incorrect `pattern` field from non-tool hooks
|
||||
- **2025-08-31**: Documented official hook structure requirements per Claude Code API
|
||||
|
||||
---
|
||||
*This documentation is maintained by @docs-agent and verified against official Anthropic documentation.*
|
||||
@@ -1,127 +0,0 @@
|
||||
# Claude Code Hook Response Format Documentation
|
||||
## Source: Official Claude Code Docs v2025
|
||||
## Last Verified: 2025-08-31
|
||||
|
||||
## Common Hook Response Fields
|
||||
|
||||
All hooks can return these common fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"continue": true, // Whether Claude should continue (default: true)
|
||||
"stopReason": "string", // Message shown when continue is false
|
||||
"suppressOutput": true, // Hide stdout from transcript (default: false)
|
||||
"systemMessage": "string" // Optional warning message shown to user
|
||||
}
|
||||
```
|
||||
|
||||
## Hook-Specific Response Formats
|
||||
|
||||
### PreCompact Hook
|
||||
**IMPORTANT**: PreCompact does NOT support `hookSpecificOutput`
|
||||
|
||||
```json
|
||||
{
|
||||
"continue": true,
|
||||
"suppressOutput": true
|
||||
}
|
||||
```
|
||||
|
||||
### SessionStart Hook
|
||||
SessionStart DOES support `hookSpecificOutput`:
|
||||
|
||||
```json
|
||||
{
|
||||
"continue": true,
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "Context string to add to session"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PreToolUse Hook
|
||||
```json
|
||||
{
|
||||
"continue": true,
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PreToolUse",
|
||||
"permissionDecision": "allow" | "deny" | "ask",
|
||||
"permissionDecisionReason": "Reason for decision"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### PostToolUse Hook
|
||||
```json
|
||||
{
|
||||
"decision": "block", // Optional - blocks further processing
|
||||
"reason": "Explanation",
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PostToolUse",
|
||||
"additionalContext": "Additional information for Claude"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### UserPromptSubmit Hook
|
||||
```json
|
||||
{
|
||||
"decision": "block", // Optional - blocks the prompt
|
||||
"reason": "Security policy violation",
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "UserPromptSubmit",
|
||||
"additionalContext": "Additional context for the prompt"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- `0`: Success - hook executed successfully
|
||||
- `1`: Error - shown to user with stdout
|
||||
- `2`: Error - shown to Claude with stderr
|
||||
|
||||
## Common Mistakes to Avoid
|
||||
|
||||
### \u274c INCORRECT: Using wrong field names
|
||||
```javascript
|
||||
// WRONG
|
||||
{
|
||||
"decision": "block", // \u274c Wrong field
|
||||
"reason": "Error message" // \u274c Wrong field
|
||||
}
|
||||
```
|
||||
|
||||
### \u2705 CORRECT: Using official field names
|
||||
```javascript
|
||||
// RIGHT
|
||||
{
|
||||
"continue": false,
|
||||
"stopReason": "Error message"
|
||||
}
|
||||
```
|
||||
|
||||
### \u274c INCORRECT: Adding hookSpecificOutput to PreCompact
|
||||
```javascript
|
||||
// WRONG - PreCompact doesn't support this
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PreCompact",
|
||||
"status": "success"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### \u2705 CORRECT: Simple response for PreCompact
|
||||
```javascript
|
||||
// RIGHT
|
||||
{
|
||||
"continue": true,
|
||||
"suppressOutput": true
|
||||
}
|
||||
```
|
||||
|
||||
## References
|
||||
- Official Docs: https://docs.anthropic.com/en/docs/claude-code/hooks
|
||||
- Hook Examples: https://docs.anthropic.com/en/docs/claude-code/hooks-guide
|
||||
@@ -1,175 +0,0 @@
|
||||
# Claude Code Hooks Configuration Documentation
|
||||
## Source: Official Claude Code Docs v2025
|
||||
## Last Verified: 2025-08-31
|
||||
|
||||
## Hook Configuration Structure
|
||||
|
||||
### For Tool-Based Hooks (PreToolUse, PostToolUse)
|
||||
These hooks use the `matcher` field to match tool patterns:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "ToolPattern", // Required for tool hooks
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "your-command-here",
|
||||
"timeout": 60000 // Optional, in milliseconds
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### For Non-Tool Hooks (PreCompact, SessionStart, etc.)
|
||||
These hooks DO NOT use matcher/pattern fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreCompact": [
|
||||
{
|
||||
// NO matcher or pattern field!
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "/path/to/script.js",
|
||||
"timeout": 180000
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Available Hook Events
|
||||
|
||||
### Tool-Related Hooks (use matcher)
|
||||
- **PreToolUse**: Before tool execution
|
||||
- **PostToolUse**: After tool execution
|
||||
|
||||
### System Event Hooks (no matcher)
|
||||
- **PreCompact**: Before conversation compaction
|
||||
- **SessionStart**: When session begins
|
||||
- **SessionEnd**: When session ends (not in official docs)
|
||||
- **UserPromptSubmit**: When user submits prompt
|
||||
- **Notification**: When Claude needs user input
|
||||
- **Stop**: When stop is requested
|
||||
- **SubagentStop**: When subagent stop is requested
|
||||
|
||||
## Hook Payload Structure
|
||||
|
||||
### Common Fields (all hooks)
|
||||
```json
|
||||
{
|
||||
"session_id": "string",
|
||||
"transcript_path": "string",
|
||||
"hook_event_name": "string",
|
||||
"cwd": "string" // Current working directory
|
||||
}
|
||||
```
|
||||
|
||||
### PreCompact Specific
|
||||
```json
|
||||
{
|
||||
"hook_event_name": "PreCompact",
|
||||
"trigger": "manual" | "auto",
|
||||
"custom_instructions": "string"
|
||||
}
|
||||
```
|
||||
|
||||
### SessionStart Specific
|
||||
```json
|
||||
{
|
||||
"hook_event_name": "SessionStart",
|
||||
"source": "startup" | "compact" | "vscode" | "web"
|
||||
}
|
||||
```
|
||||
|
||||
### PreToolUse/PostToolUse Specific
|
||||
```json
|
||||
{
|
||||
"tool_name": "string",
|
||||
"tool_input": { /* tool specific */ },
|
||||
"tool_response": { /* PostToolUse only */ }
|
||||
}
|
||||
```
|
||||
|
||||
## Common Configuration Mistakes
|
||||
|
||||
### \u274c INCORRECT: Using 'pattern' for non-tool hooks
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreCompact": [{
|
||||
"pattern": "*", // \u274c WRONG - non-tool hooks don't use this
|
||||
"hooks": [...]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### \u2705 CORRECT: No matcher for non-tool hooks
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreCompact": [{
|
||||
// No pattern or matcher field
|
||||
"hooks": [...]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### \u274c INCORRECT: Wrong matcher field name
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [{
|
||||
"pattern": "Bash", // \u274c WRONG field name
|
||||
"hooks": [...]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### \u2705 CORRECT: Using 'matcher' for tool hooks
|
||||
```json
|
||||
{
|
||||
"hooks": {
|
||||
"PreToolUse": [{
|
||||
"matcher": "Bash", // \u2705 Correct field name
|
||||
"hooks": [...]
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Matcher Patterns for Tool Hooks
|
||||
|
||||
- **Exact match**: `"Bash"` - matches only Bash tool
|
||||
- **Multiple tools**: `"Edit|MultiEdit|Write"` - matches any of these
|
||||
- **MCP tools**: `"mcp__memory__.*"` - matches all memory server tools
|
||||
- **All tools**: `"*"` - matches everything
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Hooks have access to:
|
||||
- `$CLAUDE_PROJECT_DIR` - Project root directory
|
||||
|
||||
## Settings File Locations
|
||||
|
||||
1. **User settings**: `~/.claude/settings.json`
|
||||
2. **Project settings**: `./.claude/settings.json`
|
||||
3. **Local settings**: `./.claude/settings.local.json`
|
||||
4. **Managed settings**: `/Library/Application Support/ClaudeCode/managed-settings.json`
|
||||
|
||||
## References
|
||||
- Official Docs: https://docs.anthropic.com/en/docs/claude-code/hooks
|
||||
- Hook Guide: https://docs.anthropic.com/en/docs/claude-code/hooks-guide
|
||||
@@ -1,133 +0,0 @@
|
||||
# MCP Configuration Documentation
|
||||
## Source: Official Claude Code Docs v2025
|
||||
## Last Verified: 2025-08-31
|
||||
|
||||
## MCP Configuration File Locations
|
||||
|
||||
### User Scope
|
||||
- **File**: `~/.claude.json`
|
||||
- **Purpose**: User-wide MCP servers available across all projects
|
||||
- **Persistence**: Persists across projects
|
||||
- **Example Path**: `/Users/username/.claude.json`
|
||||
|
||||
### Project Scope
|
||||
- **File**: `./.mcp.json`
|
||||
- **Purpose**: Project-specific servers for team collaboration
|
||||
- **Persistence**: Checked into version control
|
||||
- **Example Path**: `/path/to/project/.mcp.json`
|
||||
|
||||
### Local Scope
|
||||
- **Status**: Not officially documented
|
||||
- **Implementation**: Currently uses `~/.claude.json` (may need revision)
|
||||
|
||||
## Configuration Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"server-name": {
|
||||
"command": "command-to-run",
|
||||
"args": ["arg1", "arg2"],
|
||||
"env": {
|
||||
"ENV_VAR": "value"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Example Configurations
|
||||
|
||||
### Memory Server (stdio)
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"claude-mem": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@modelcontextprotocol/server-memory"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### HTTP Server
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"api-server": {
|
||||
"type": "sse",
|
||||
"url": "${API_BASE_URL:-https://api.example.com}/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${API_KEY}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Environment Variable Expansion
|
||||
|
||||
MCP configs support environment variable expansion:
|
||||
- `${VAR}` - Direct expansion
|
||||
- `${VAR:-default}` - With fallback value
|
||||
|
||||
Applicable fields:
|
||||
- `command`
|
||||
- `args`
|
||||
- `env`
|
||||
- `url`
|
||||
- `headers`
|
||||
|
||||
## CLI Commands
|
||||
|
||||
```bash
|
||||
# Add a server
|
||||
claude mcp add <name> <command> [args...]
|
||||
|
||||
# Add with scope
|
||||
claude mcp add <name> --scope project /path/to/server
|
||||
claude mcp add <name> --scope user /path/to/server
|
||||
|
||||
# List servers
|
||||
claude mcp list
|
||||
|
||||
# Get server details
|
||||
claude mcp get <name>
|
||||
|
||||
# Remove server
|
||||
claude mcp remove <name>
|
||||
|
||||
# Check status (within Claude Code)
|
||||
/mcp
|
||||
```
|
||||
|
||||
## Tool Naming Convention
|
||||
|
||||
MCP tools follow the pattern: `mcp__<serverName>__<toolName>`
|
||||
|
||||
Example:
|
||||
- Server: `claude-mem`
|
||||
- Tool: `create_entities`
|
||||
- Full name: `mcp__claude_mem__create_entities`
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **Tool Permissions**: Must explicitly allow MCP tools via `--allowedTools`
|
||||
2. **Server Trust**: Only use MCP servers from trusted sources
|
||||
3. **Credential Management**: Use environment variables for sensitive data
|
||||
4. **Audit Trail**: MCP operations can be monitored via hooks
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue: MCP server not connecting
|
||||
**Solution**: Check that the command and args are correct, and npx is in PATH
|
||||
|
||||
### Issue: Tools not available
|
||||
**Solution**: Ensure server is in allowed list and properly configured
|
||||
|
||||
### Issue: Configuration not loading
|
||||
**Solution**: Verify JSON syntax and file location
|
||||
|
||||
## References
|
||||
- Official Docs: https://docs.anthropic.com/en/docs/claude-code/mcp
|
||||
- MCP Protocol: https://modelcontextprotocol.io/
|
||||
@@ -1,82 +0,0 @@
|
||||
# SessionStart Hook Documentation
|
||||
|
||||
## Official Documentation Reference
|
||||
- **Source**: https://docs.anthropic.com/en/docs/claude-code/hooks#sessionstart
|
||||
- **Last Verified**: 2025-08-31
|
||||
- **Version**: Claude Code v2025
|
||||
|
||||
## Hook Payload Structure
|
||||
|
||||
The SessionStart hook receives the following JSON payload via stdin:
|
||||
|
||||
```json
|
||||
{
|
||||
"session_id": "string",
|
||||
"transcript_path": "string",
|
||||
"hook_event_name": "SessionStart",
|
||||
"source": "startup" | "compact" | "vscode" | "web"
|
||||
}
|
||||
```
|
||||
|
||||
### Field Descriptions
|
||||
|
||||
- **session_id**: Unique identifier for the Claude Code session
|
||||
- **transcript_path**: Path to the conversation transcript JSONL file
|
||||
- **hook_event_name**: Always "SessionStart" for this hook
|
||||
- **source**: Indicates how the session was initiated:
|
||||
- `"startup"`: New session started normally (should load context)
|
||||
- `"compact"`: Session started after compaction (may skip context)
|
||||
- `"vscode"`: Session initiated from VS Code extension
|
||||
- `"web"`: Session initiated from web interface
|
||||
|
||||
## Response Format
|
||||
|
||||
The hook should output JSON in the following format to add context:
|
||||
|
||||
```json
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "string"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response Fields
|
||||
|
||||
- **hookSpecificOutput**: Container for hook-specific output
|
||||
- **hookEventName**: Must be "SessionStart"
|
||||
- **additionalContext**: String content to add to the session context
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
### Context Loading Strategy
|
||||
|
||||
The hook should determine whether to load context based on the `source` field:
|
||||
|
||||
1. **For "startup" source**: Load full context from memory
|
||||
2. **For "compact" source**: Skip or load minimal context (session continuing after compaction)
|
||||
3. **For "vscode"/"web" sources**: Load context as appropriate
|
||||
|
||||
### Error Handling
|
||||
|
||||
- If context loading fails, exit silently (exit code 0)
|
||||
- Do not break the session start with errors
|
||||
- Log errors to separate log file if needed
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### Incorrect Field Check (FIXED)
|
||||
**Wrong**: Checking `payload.reason === 'continue'`
|
||||
**Correct**: Checking `payload.source === 'compact'`
|
||||
|
||||
The payload does not have a `reason` field. The `source` field indicates the session initiation context.
|
||||
|
||||
## Code Location
|
||||
- **File**: `/Users/alexnewman/Scripts/claude-mem/hooks/session-start.js`
|
||||
- **Line**: 53-66 (field check and documentation)
|
||||
|
||||
## Cross-References
|
||||
- General Hooks Documentation: [docs/claude-code/hooks.md](./hooks.md)
|
||||
- Hook Response Formats: [docs/claude-code/hook-responses.md](./hook-responses.md)
|
||||
- MCP Configuration: [docs/claude-code/mcp-configuration.md](./mcp-configuration.md)
|
||||
@@ -1,33 +0,0 @@
|
||||
<session-start-hook>
|
||||
|
||||
🧠 What's new: Thursday, September 4, 2025 at 06:13 PM EDT
|
||||
====================================================================
|
||||
Established Claude memory management infrastructure with compression tools for session archiving. Optimized session summary generation with compact command overviews for improved retrieval efficiency.
|
||||
|
||||
📚 Recent Context
|
||||
====================================================================
|
||||
👀 in claude_mem_source_d096f650-76a3-4163-9b7a-19f36a13c648_{number}:
|
||||
|
||||
1. Removed maxTurns:1 limitation that prevented Claude from completing multi-step compression with tool calls
|
||||
— maxTurns, Claude SDK, compression fix, MCP tools
|
||||
|
||||
3. Deployed steve-krug-ux agent to redesign prompt from pipe-separated to JSON with XMLResponse tags
|
||||
— steve-krug-ux, JSON format, prompt redesign
|
||||
|
||||
5. Expanded TranscriptCompressor to use all 13 claude-mem MCP tools for intelligent compression
|
||||
— allowedTools, MCP tools expansion, TranscriptCompressor
|
||||
|
||||
6. Traced index population failure through multiple system layers to identify root cause
|
||||
— debugging, ContextTemplates, claude-mem-index, trace
|
||||
|
||||
======================================================================
|
||||
👀 in claude_mem_source_d096f650-76a3-4163-9b7a-19f36a13c648_{number}:
|
||||
|
||||
1. Implemented Claude memory management and compression tools system
|
||||
— memory management, compression, archiving, session context
|
||||
|
||||
2. Generated compact command overview for session summaries
|
||||
— command overview, session summaries, memory retrieval
|
||||
|
||||
======================================================================
|
||||
</session-start-hook>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,286 +0,0 @@
|
||||
# MCP TypeScript SDK Server Implementation Guide
|
||||
|
||||
## Documentation Source
|
||||
- **SDK Version**: @modelcontextprotocol/sdk v1.0.0
|
||||
- **Last Verified**: 2025-09-01
|
||||
- **Official Docs**: https://github.com/modelcontextprotocol/typescript-sdk
|
||||
|
||||
## Server Creation Patterns
|
||||
|
||||
### Low-Level Server vs McpServer
|
||||
|
||||
The SDK provides two approaches for creating MCP servers:
|
||||
|
||||
1. **Low-Level Server Class** (Used in claude-mem)
|
||||
- Direct control over request handling
|
||||
- Manual registration with `setRequestHandler`
|
||||
- More flexibility for custom routing logic
|
||||
|
||||
```typescript
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
|
||||
const server = new Server(
|
||||
{
|
||||
name: 'server-name',
|
||||
version: '1.0.0'
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {} // Declare tool capability
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
2. **High-Level McpServer Class** (Alternative approach)
|
||||
- Simplified API with `registerTool`, `registerResource`, `registerPrompt`
|
||||
- Automatic routing and validation
|
||||
- Less boilerplate code
|
||||
|
||||
```typescript
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
|
||||
const server = new McpServer({
|
||||
name: 'server-name',
|
||||
version: '1.0.0'
|
||||
});
|
||||
```
|
||||
|
||||
## Tool Handler Registration
|
||||
|
||||
### Pattern 1: Single Handler with CallToolRequestSchema (claude-mem approach)
|
||||
|
||||
```typescript
|
||||
import { CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
||||
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params;
|
||||
|
||||
// Validate arguments exist
|
||||
if (!args) {
|
||||
throw new Error(`No arguments provided for tool: ${name}`);
|
||||
}
|
||||
|
||||
// Route to specific tool implementation
|
||||
switch (name) {
|
||||
case 'tool-name':
|
||||
// Tool implementation
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: 'Result'
|
||||
}]
|
||||
};
|
||||
default:
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Pattern 2: Individual Tool Registration (McpServer approach)
|
||||
|
||||
```typescript
|
||||
server.registerTool(
|
||||
'tool-name',
|
||||
{
|
||||
title: 'Tool Title',
|
||||
description: 'Tool description',
|
||||
inputSchema: { param: z.string() }
|
||||
},
|
||||
async ({ param }) => ({
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: `Result for ${param}`
|
||||
}]
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
## Stdio Transport Usage
|
||||
|
||||
### Standard Pattern for CLI-based Servers
|
||||
|
||||
```typescript
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
|
||||
async function main() {
|
||||
// 1. Initialize backend services first
|
||||
await initializeBackend();
|
||||
|
||||
// 2. Create transport
|
||||
const transport = new StdioServerTransport();
|
||||
|
||||
// 3. Connect server to transport
|
||||
await server.connect(transport);
|
||||
|
||||
// 4. Log to stderr (stdout is for protocol)
|
||||
console.error('Server started on stdio');
|
||||
}
|
||||
```
|
||||
|
||||
### Key Points:
|
||||
- **Stdin**: Receives MCP protocol messages
|
||||
- **Stdout**: Sends MCP protocol responses
|
||||
- **Stderr**: Used for logging and diagnostics
|
||||
|
||||
## Error Handling Patterns
|
||||
|
||||
### Tool Error Response
|
||||
|
||||
```typescript
|
||||
try {
|
||||
// Tool implementation
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: 'Success result'
|
||||
}]
|
||||
};
|
||||
} catch (error) {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
|
||||
// Log to stderr for debugging
|
||||
console.error(`[Error] Tool: ${name}, Error: ${errorMessage}`);
|
||||
|
||||
// Return error response with isError flag
|
||||
return {
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: `Error: ${errorMessage}`
|
||||
}],
|
||||
isError: true // Important: Indicates tool failure
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Startup Error Handling
|
||||
|
||||
```typescript
|
||||
main().catch((error) => {
|
||||
console.error('Startup error:', error);
|
||||
process.exit(1); // Exit with error code
|
||||
});
|
||||
```
|
||||
|
||||
## Response Formatting
|
||||
|
||||
### Success Response Structure
|
||||
|
||||
```typescript
|
||||
{
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Response text'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Error Response Structure
|
||||
|
||||
```typescript
|
||||
{
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Error: Description'
|
||||
}
|
||||
],
|
||||
isError: true
|
||||
}
|
||||
```
|
||||
|
||||
### Resource Link Response
|
||||
|
||||
```typescript
|
||||
{
|
||||
content: [
|
||||
{
|
||||
type: 'resource_link',
|
||||
uri: 'file:///path/to/resource',
|
||||
name: 'Resource Name',
|
||||
mimeType: 'text/plain',
|
||||
description: 'Resource description'
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Lifecycle Management
|
||||
|
||||
### Initialization Pattern
|
||||
|
||||
```typescript
|
||||
async function initializeServer(): Promise<void> {
|
||||
try {
|
||||
// Initialize backend connections
|
||||
await backend.connect();
|
||||
console.error('Backend initialized');
|
||||
} catch (error) {
|
||||
console.error('Initialization failed:', error);
|
||||
throw error; // Prevent server startup
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Shutdown Pattern
|
||||
|
||||
```typescript
|
||||
function setupShutdownHandlers(): void {
|
||||
const handleShutdown = async (signal: string) => {
|
||||
console.error(`Received ${signal}, shutting down...`);
|
||||
|
||||
try {
|
||||
await backend.disconnect();
|
||||
process.exit(0); // Clean exit
|
||||
} catch (error) {
|
||||
console.error('Shutdown error:', error);
|
||||
process.exit(1); // Error exit
|
||||
}
|
||||
};
|
||||
|
||||
process.on('SIGINT', () => handleShutdown('SIGINT'));
|
||||
process.on('SIGTERM', () => handleShutdown('SIGTERM'));
|
||||
|
||||
// Handle unexpected errors
|
||||
process.on('uncaughtException', async (error) => {
|
||||
console.error('Uncaught exception:', error);
|
||||
await backend.disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
1. **Server Creation**
|
||||
- Use low-level Server for custom routing
|
||||
- Use McpServer for standard implementations
|
||||
|
||||
2. **Transport Usage**
|
||||
- Initialize backends before connecting transport
|
||||
- Use StdioServerTransport for CLI tools
|
||||
- Log to stderr, not stdout
|
||||
|
||||
3. **Error Handling**
|
||||
- Always validate tool arguments
|
||||
- Include isError flag in error responses
|
||||
- Log errors to stderr with context
|
||||
|
||||
4. **Response Format**
|
||||
- Always return content array
|
||||
- Use consistent type/text structure
|
||||
- Include isError for failures
|
||||
|
||||
5. **Lifecycle**
|
||||
- Clean initialization sequence
|
||||
- Graceful shutdown handlers
|
||||
- Proper exit codes (0 for success, 1 for error)
|
||||
|
||||
## References
|
||||
|
||||
- [MCP TypeScript SDK README](https://github.com/modelcontextprotocol/typescript-sdk)
|
||||
- [Low-Level Server Pattern](https://github.com/modelcontextprotocol/typescript-sdk#low-level-server-implementation)
|
||||
- [Stdio Transport Example](https://github.com/modelcontextprotocol/typescript-sdk#stdio-transport)
|
||||
- [Error Handling Examples](https://github.com/modelcontextprotocol/typescript-sdk#sqlite-explorer)
|
||||
@@ -1,345 +0,0 @@
|
||||
# MCP TypeScript SDK Stdio Transport Guide
|
||||
|
||||
## Documentation Source
|
||||
- **SDK Version**: @modelcontextprotocol/sdk v1.0.0
|
||||
- **Last Verified**: 2025-09-01
|
||||
- **Official Docs**: https://github.com/modelcontextprotocol/typescript-sdk
|
||||
|
||||
## Stdio Transport Overview
|
||||
|
||||
The StdioServerTransport enables MCP servers to communicate via standard input/output streams, making them ideal for CLI tools and direct integrations with Claude Code.
|
||||
|
||||
## Communication Channels
|
||||
|
||||
### Stream Usage
|
||||
- **stdin**: Receives MCP protocol messages (JSON-RPC)
|
||||
- **stdout**: Sends MCP protocol responses (JSON-RPC)
|
||||
- **stderr**: Logging and diagnostic output
|
||||
|
||||
### Important Rules
|
||||
1. **Never write non-protocol data to stdout** - This will break the protocol
|
||||
2. **Always use console.error() for logging** - Goes to stderr
|
||||
3. **Handle binary data carefully** - Protocol is text-based JSON
|
||||
|
||||
## Implementation Patterns
|
||||
|
||||
### Basic Stdio Server Setup
|
||||
|
||||
```typescript
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
|
||||
// Create server
|
||||
const server = new Server(
|
||||
{ name: 'my-server', version: '1.0.0' },
|
||||
{ capabilities: { tools: {} } }
|
||||
);
|
||||
|
||||
// Create and connect transport
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
|
||||
// Server is now listening on stdin/stdout
|
||||
console.error('Server started'); // Note: console.error for logging
|
||||
```
|
||||
|
||||
### With McpServer (High-Level API)
|
||||
|
||||
```typescript
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
|
||||
const server = new McpServer({
|
||||
name: 'my-server',
|
||||
version: '1.0.0'
|
||||
});
|
||||
|
||||
// Register tools, resources, prompts...
|
||||
server.registerTool(...);
|
||||
|
||||
// Connect to stdio
|
||||
const transport = new StdioServerTransport();
|
||||
await server.connect(transport);
|
||||
```
|
||||
|
||||
## CLI Entry Point Pattern
|
||||
|
||||
### Proper Module Detection (ES Modules)
|
||||
|
||||
```typescript
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname } from 'path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Only run if executed directly
|
||||
if (process.argv[1] === __filename ||
|
||||
process.argv[1].endsWith('server.js')) {
|
||||
main().catch((error) => {
|
||||
console.error('Startup error:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### Main Function Pattern
|
||||
|
||||
```typescript
|
||||
async function main(): Promise<void> {
|
||||
try {
|
||||
// 1. Initialize dependencies
|
||||
await initializeDatabase();
|
||||
|
||||
// 2. Create server
|
||||
const server = createServer();
|
||||
|
||||
// 3. Create transport
|
||||
const transport = new StdioServerTransport();
|
||||
|
||||
// 4. Connect
|
||||
await server.connect(transport);
|
||||
|
||||
// 5. Setup shutdown handlers
|
||||
setupShutdownHandlers();
|
||||
|
||||
// 6. Log readiness to stderr
|
||||
console.error('MCP server ready on stdio');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to start server:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Shutdown Handling
|
||||
|
||||
### Graceful Shutdown Pattern
|
||||
|
||||
```typescript
|
||||
function setupShutdownHandlers(): void {
|
||||
const shutdown = async (signal: string) => {
|
||||
console.error(`\nReceived ${signal}, shutting down...`);
|
||||
|
||||
try {
|
||||
// Clean up resources
|
||||
await cleanupResources();
|
||||
|
||||
// Note: Transport cleanup is handled automatically
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('Shutdown error:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle termination signals
|
||||
process.on('SIGINT', () => shutdown('SIGINT')); // Ctrl+C
|
||||
process.on('SIGTERM', () => shutdown('SIGTERM')); // Kill
|
||||
process.on('SIGHUP', () => shutdown('SIGHUP')); // Terminal closed
|
||||
|
||||
// Handle errors
|
||||
process.on('uncaughtException', (error) => {
|
||||
console.error('Uncaught exception:', error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on('unhandledRejection', (reason) => {
|
||||
console.error('Unhandled rejection:', reason);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Logging Best Practices
|
||||
|
||||
### Do's and Don'ts
|
||||
|
||||
```typescript
|
||||
// ✅ DO: Log to stderr
|
||||
console.error('Server initialized');
|
||||
console.error('Processing request:', requestId);
|
||||
console.error('Debug info:', { data });
|
||||
|
||||
// ❌ DON'T: Log to stdout
|
||||
console.log('This breaks the protocol!'); // NEVER DO THIS
|
||||
|
||||
// ✅ DO: Use structured logging to stderr
|
||||
const log = (level: string, message: string, data?: any) => {
|
||||
console.error(JSON.stringify({
|
||||
timestamp: new Date().toISOString(),
|
||||
level,
|
||||
message,
|
||||
...data
|
||||
}));
|
||||
};
|
||||
|
||||
log('info', 'Server started', { port: 'stdio' });
|
||||
```
|
||||
|
||||
### Debug Mode Pattern
|
||||
|
||||
```typescript
|
||||
const DEBUG = process.env.DEBUG === 'true';
|
||||
|
||||
const debug = (message: string, ...args: any[]) => {
|
||||
if (DEBUG) {
|
||||
console.error(`[DEBUG] ${message}`, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
// Usage
|
||||
debug('Request received:', request);
|
||||
```
|
||||
|
||||
## Testing Stdio Servers
|
||||
|
||||
### Manual Testing
|
||||
|
||||
```bash
|
||||
# Start server and interact manually
|
||||
node dist/server.js
|
||||
|
||||
# With debug logging
|
||||
DEBUG=true node dist/server.js
|
||||
|
||||
# Pipe test input
|
||||
echo '{"jsonrpc":"2.0","method":"initialize","params":{},"id":1}' | node dist/server.js
|
||||
```
|
||||
|
||||
### Automated Testing Pattern
|
||||
|
||||
```typescript
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
function testServer() {
|
||||
const server = spawn('node', ['dist/server.js']);
|
||||
|
||||
// Capture stderr for logs
|
||||
server.stderr.on('data', (data) => {
|
||||
console.log('Server log:', data.toString());
|
||||
});
|
||||
|
||||
// Capture stdout for protocol
|
||||
let response = '';
|
||||
server.stdout.on('data', (data) => {
|
||||
response += data.toString();
|
||||
// Parse and validate response
|
||||
});
|
||||
|
||||
// Send test request
|
||||
server.stdin.write(JSON.stringify({
|
||||
jsonrpc: '2.0',
|
||||
method: 'initialize',
|
||||
params: {},
|
||||
id: 1
|
||||
}));
|
||||
server.stdin.end();
|
||||
}
|
||||
```
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Issue 1: Protocol Corruption
|
||||
|
||||
**Problem**: Random text in stdout breaks communication
|
||||
**Solution**: Always use console.error() for logging
|
||||
|
||||
```typescript
|
||||
// Wrong
|
||||
console.log('Debug:', data); // Breaks protocol
|
||||
|
||||
// Right
|
||||
console.error('Debug:', data); // Safe for debugging
|
||||
```
|
||||
|
||||
### Issue 2: Server Not Responding
|
||||
|
||||
**Problem**: Server starts but doesn't respond to requests
|
||||
**Solution**: Ensure transport is connected
|
||||
|
||||
```typescript
|
||||
// Check connection is awaited
|
||||
await server.connect(transport); // Must await!
|
||||
console.error('Transport connected');
|
||||
```
|
||||
|
||||
### Issue 3: Premature Exit
|
||||
|
||||
**Problem**: Server exits immediately
|
||||
**Solution**: Don't close stdin/stdout
|
||||
|
||||
```typescript
|
||||
// Wrong
|
||||
process.stdin.end(); // Don't do this
|
||||
|
||||
// Right
|
||||
// Let the transport manage streams
|
||||
```
|
||||
|
||||
## Integration with Claude Code
|
||||
|
||||
### Configuration in .claude.json
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"my-server": {
|
||||
"command": "node",
|
||||
"args": ["/path/to/dist/server.js"],
|
||||
"env": {
|
||||
"DEBUG": "false"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Best Practices for Claude Code Integration
|
||||
|
||||
1. **Startup Messages**: Log clear startup messages to stderr
|
||||
2. **Error Messages**: Provide actionable error messages
|
||||
3. **Ready Signal**: Log when server is ready to accept requests
|
||||
4. **Version Info**: Include version in startup logs
|
||||
|
||||
```typescript
|
||||
console.error(`Starting ${serverName} v${version}`);
|
||||
console.error('Initializing...');
|
||||
// ... initialization ...
|
||||
console.error(`${serverName} ready on stdio`);
|
||||
```
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Buffering and Streaming
|
||||
|
||||
```typescript
|
||||
// For large responses, consider streaming
|
||||
import { Transform } from 'stream';
|
||||
|
||||
class ResponseStream extends Transform {
|
||||
_transform(chunk: any, encoding: string, callback: Function) {
|
||||
// Process chunk
|
||||
this.push(JSON.stringify(chunk));
|
||||
callback();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Memory Management
|
||||
|
||||
```typescript
|
||||
// Clear large objects after use
|
||||
let largeData = await processData();
|
||||
// Use data...
|
||||
largeData = null; // Allow GC
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [StdioServerTransport Docs](https://github.com/modelcontextprotocol/typescript-sdk#stdio-transport)
|
||||
- [Server Examples](https://github.com/modelcontextprotocol/typescript-sdk/tree/main/src/examples/server)
|
||||
- [MCP Protocol Specification](https://modelcontextprotocol.io/docs)
|
||||
@@ -1,81 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Pre-Compact Hook for Claude Memory System
|
||||
*
|
||||
* Updated to use the centralized PromptOrchestrator and HookTemplates system.
|
||||
* This hook validates the pre-compact request and executes compression using
|
||||
* standardized response templates for consistent Claude Code integration.
|
||||
*/
|
||||
|
||||
import { loadCliCommand } from './shared/config-loader.js';
|
||||
import {
|
||||
createHookResponse,
|
||||
executeCliCommand,
|
||||
validateHookPayload,
|
||||
debugLog
|
||||
} from './shared/hook-helpers.js';
|
||||
|
||||
const cliCommand = loadCliCommand();
|
||||
|
||||
// Read input from stdin
|
||||
let input = '';
|
||||
process.stdin.on('data', chunk => {
|
||||
input += chunk;
|
||||
});
|
||||
|
||||
process.stdin.on('end', async () => {
|
||||
try {
|
||||
const payload = JSON.parse(input);
|
||||
debugLog('Pre-compact hook started', { payload });
|
||||
|
||||
// Validate payload using centralized validation
|
||||
const validation = validateHookPayload(payload, 'PreCompact');
|
||||
if (!validation.valid) {
|
||||
const response = createHookResponse('PreCompact', false, { reason: validation.error });
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Check for environment-based blocking conditions
|
||||
if (payload.trigger === 'auto' && process.env.DISABLE_AUTO_COMPRESSION === 'true') {
|
||||
debugLog('Auto-compression disabled by configuration');
|
||||
const response = createHookResponse('PreCompact', false, {
|
||||
reason: 'Auto-compression disabled by configuration'
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Execute compression using standardized CLI execution helper
|
||||
debugLog('Executing compression command', {
|
||||
command: cliCommand,
|
||||
args: ['compress', payload.transcript_path]
|
||||
});
|
||||
|
||||
const result = await executeCliCommand(cliCommand, ['compress', payload.transcript_path]);
|
||||
|
||||
if (!result.success) {
|
||||
debugLog('Compression command failed', { stderr: result.stderr });
|
||||
const response = createHookResponse('PreCompact', false, {
|
||||
reason: `Compression failed: ${result.stderr || 'Unknown error'}`
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Success - create standardized approval response using HookTemplates
|
||||
debugLog('Compression completed successfully');
|
||||
const response = createHookResponse('PreCompact', true);
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
|
||||
} catch (error) {
|
||||
debugLog('Pre-compact hook error', { error: error.message });
|
||||
const response = createHookResponse('PreCompact', false, {
|
||||
reason: `Hook execution error: ${error.message}`
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
@@ -1,58 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Session End Hook - Handles session end events including /clear
|
||||
*/
|
||||
|
||||
import { loadCliCommand } from './shared/config-loader.js';
|
||||
import { execSync } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
|
||||
const cliCommand = loadCliCommand();
|
||||
|
||||
// Check if save-on-clear is enabled
|
||||
function isSaveOnClearEnabled() {
|
||||
const settingsPath = join(homedir(), '.claude-mem', 'settings.json');
|
||||
if (existsSync(settingsPath)) {
|
||||
try {
|
||||
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
||||
return settings.saveMemoriesOnClear === true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read input
|
||||
let input = '';
|
||||
process.stdin.on('data', chunk => {
|
||||
input += chunk;
|
||||
});
|
||||
|
||||
process.stdin.on('end', async () => {
|
||||
const data = JSON.parse(input);
|
||||
|
||||
// Check if this is a clear event and save-on-clear is enabled
|
||||
if (data.reason === 'clear' && isSaveOnClearEnabled()) {
|
||||
console.error('🧠 Saving memories before clearing context...');
|
||||
|
||||
try {
|
||||
// Use the CLI to compress current transcript
|
||||
execSync(`${cliCommand} compress --output ${homedir()}/.claude-mem/archives`, {
|
||||
stdio: 'inherit',
|
||||
env: { ...process.env, CLAUDE_MEM_SILENT: 'true' }
|
||||
});
|
||||
|
||||
console.error('✅ Memories saved successfully');
|
||||
} catch (error) {
|
||||
console.error('[session-end] Failed to save memories:', error.message);
|
||||
// Don't block the clear operation if memory saving fails
|
||||
}
|
||||
}
|
||||
|
||||
// Always continue
|
||||
console.log(JSON.stringify({ continue: true }));
|
||||
});
|
||||
@@ -1,166 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Session Start Hook - Load context when Claude Code starts
|
||||
*
|
||||
* Updated to use the centralized PromptOrchestrator and HookTemplates system.
|
||||
* This hook loads previous session context using standardized formatting and
|
||||
* provides rich context messages for Claude Code integration.
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { loadCliCommand } from './shared/config-loader.js';
|
||||
import {
|
||||
createHookResponse,
|
||||
formatSessionStartContext,
|
||||
executeCliCommand,
|
||||
parseContextData,
|
||||
validateHookPayload,
|
||||
debugLog
|
||||
} from './shared/hook-helpers.js';
|
||||
|
||||
const cliCommand = loadCliCommand();
|
||||
|
||||
// Read input from stdin
|
||||
let input = '';
|
||||
process.stdin.on('data', chunk => {
|
||||
input += chunk;
|
||||
});
|
||||
|
||||
process.stdin.on('end', async () => {
|
||||
try {
|
||||
const payload = JSON.parse(input);
|
||||
debugLog('Session start hook started', { payload });
|
||||
|
||||
// Validate payload using centralized validation
|
||||
const validation = validateHookPayload(payload, 'SessionStart');
|
||||
if (!validation.valid) {
|
||||
debugLog('Payload validation failed', { error: validation.error });
|
||||
// For session start, continue even with invalid payload but log the error
|
||||
const response = createHookResponse('SessionStart', false, {
|
||||
error: `Payload validation failed: ${validation.error}`
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Skip load-context when source is "resume" to avoid duplicate context
|
||||
if (payload.source === 'resume') {
|
||||
debugLog('Skipping load-context for resume source');
|
||||
// Output nothing at all for resume - no message, no context
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Extract project name from current working directory and sanitize
|
||||
const rawProjectName = path.basename(process.cwd());
|
||||
const projectName = rawProjectName.replace(/-/g, '_');
|
||||
debugLog('Extracted project name', { rawProjectName, projectName });
|
||||
|
||||
// Load context using standardized CLI execution helper
|
||||
const contextResult = await executeCliCommand(cliCommand, [
|
||||
'load-context',
|
||||
'--format', 'session-start',
|
||||
'--project', projectName
|
||||
]);
|
||||
|
||||
if (!contextResult.success) {
|
||||
debugLog('Context loading failed', { stderr: contextResult.stderr });
|
||||
// Don't fail the session start, just provide error context
|
||||
const response = createHookResponse('SessionStart', false, {
|
||||
error: contextResult.stderr || 'Failed to load context'
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const rawContext = contextResult.stdout;
|
||||
debugLog('Raw context loaded', { contextLength: rawContext.length });
|
||||
|
||||
// Check if the output is actually an error message (starts with ❌)
|
||||
if (rawContext && rawContext.trim().startsWith('❌')) {
|
||||
debugLog('Detected error message in stdout', { rawContext });
|
||||
// Extract the clean error message without the emoji and format
|
||||
const errorMatch = rawContext.match(/❌\s*[^:]+:\s*([^\n]+)(?:\n\n💡\s*(.+))?/);
|
||||
let errorMsg = 'No previous memories found';
|
||||
let suggestion = '';
|
||||
|
||||
if (errorMatch) {
|
||||
errorMsg = errorMatch[1] || errorMsg;
|
||||
suggestion = errorMatch[2] || '';
|
||||
}
|
||||
|
||||
// Create a clean response without duplicating the error formatting
|
||||
const response = createHookResponse('SessionStart', false, {
|
||||
error: errorMsg + (suggestion ? `. ${suggestion}` : '')
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!rawContext || !rawContext.trim()) {
|
||||
debugLog('No context available, creating empty response');
|
||||
// No context available - use standardized empty response
|
||||
const response = createHookResponse('SessionStart', true);
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Parse context data and format using centralized templates
|
||||
const contextData = parseContextData(rawContext);
|
||||
contextData.projectName = projectName;
|
||||
|
||||
// If we have raw context (not structured data), use it directly
|
||||
let formattedContext;
|
||||
if (contextData.rawContext) {
|
||||
formattedContext = contextData.rawContext;
|
||||
} else {
|
||||
// Use standardized formatting for structured context
|
||||
formattedContext = formatSessionStartContext(contextData);
|
||||
}
|
||||
|
||||
debugLog('Context formatted successfully', {
|
||||
memoryCount: contextData.memoryCount,
|
||||
hasStructuredData: !contextData.rawContext
|
||||
});
|
||||
|
||||
// Create standardized session start response using HookTemplates
|
||||
const response = createHookResponse('SessionStart', true, {
|
||||
context: formattedContext
|
||||
});
|
||||
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
|
||||
} catch (error) {
|
||||
debugLog('Session start hook error', { error: error.message });
|
||||
// Even on error, continue the session with error information
|
||||
const response = createHookResponse('SessionStart', false, {
|
||||
error: `Hook execution error: ${error.message}`
|
||||
});
|
||||
console.log(JSON.stringify(response));
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Extracts project name from transcript path
|
||||
* @param {string} transcriptPath - Path to transcript file
|
||||
* @returns {string|null} Extracted project name or null
|
||||
*/
|
||||
function extractProjectName(transcriptPath) {
|
||||
if (!transcriptPath) return null;
|
||||
|
||||
// Look for project pattern: /path/to/PROJECT_NAME/.claude/
|
||||
// Need to get PROJECT_NAME, not the parent directory
|
||||
const parts = transcriptPath.split('/');
|
||||
const claudeIndex = parts.indexOf('.claude');
|
||||
|
||||
if (claudeIndex > 0) {
|
||||
// Get the directory immediately before .claude
|
||||
return parts[claudeIndex - 1];
|
||||
}
|
||||
|
||||
// Fall back to directory containing the transcript
|
||||
const dir = path.dirname(transcriptPath);
|
||||
return path.basename(dir);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Shared configuration loader utility for Claude Memory hooks
|
||||
* Loads CLI command name from config.json with proper fallback handling
|
||||
*/
|
||||
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
|
||||
/**
|
||||
* Loads the CLI command name from the hooks config.json file
|
||||
* @returns {string} The CLI command name (defaults to 'claude-mem')
|
||||
*/
|
||||
export function loadCliCommand() {
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const configPath = join(__dirname, '..', 'config.json');
|
||||
|
||||
if (existsSync(configPath)) {
|
||||
const config = JSON.parse(readFileSync(configPath, 'utf-8'));
|
||||
return config.cliCommand || 'claude-mem';
|
||||
}
|
||||
|
||||
return 'claude-mem';
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Hook Helper Functions
|
||||
*
|
||||
* This module provides JavaScript wrappers around the TypeScript PromptOrchestrator
|
||||
* and HookTemplates system, making them accessible to the JavaScript hook scripts.
|
||||
*/
|
||||
|
||||
import { spawn } from 'child_process';
|
||||
import { join, dirname } from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
/**
|
||||
* Creates a standardized hook response using the HookTemplates system
|
||||
* @param {string} hookType - Type of hook ('PreCompact' or 'SessionStart')
|
||||
* @param {boolean} success - Whether the operation was successful
|
||||
* @param {Object} options - Additional options
|
||||
* @returns {Object} Formatted hook response
|
||||
*/
|
||||
export function createHookResponse(hookType, success, options = {}) {
|
||||
if (hookType === 'PreCompact') {
|
||||
if (success) {
|
||||
return {
|
||||
continue: true,
|
||||
suppressOutput: true
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
continue: false,
|
||||
stopReason: options.reason || 'Pre-compact operation failed',
|
||||
suppressOutput: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (hookType === 'SessionStart') {
|
||||
if (success && options.context) {
|
||||
return {
|
||||
continue: true,
|
||||
suppressOutput: true,
|
||||
hookSpecificOutput: {
|
||||
hookEventName: 'SessionStart',
|
||||
additionalContext: options.context
|
||||
}
|
||||
};
|
||||
} else if (success) {
|
||||
return {
|
||||
continue: true,
|
||||
suppressOutput: true,
|
||||
hookSpecificOutput: {
|
||||
hookEventName: 'SessionStart',
|
||||
additionalContext: 'Starting fresh session - no previous context available'
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
continue: true, // Continue even on context loading failure
|
||||
suppressOutput: true,
|
||||
hookSpecificOutput: {
|
||||
hookEventName: 'SessionStart',
|
||||
additionalContext: `Context loading encountered an issue: ${options.error || 'Unknown error'}. Starting without previous context.`
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Generic response for unknown hook types
|
||||
return {
|
||||
continue: success,
|
||||
suppressOutput: true,
|
||||
...(options.reason && !success ? { stopReason: options.reason } : {})
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a session start context message using standardized templates
|
||||
* @param {Object} contextData - Context information
|
||||
* @returns {string} Formatted context message
|
||||
*/
|
||||
export function formatSessionStartContext(contextData) {
|
||||
const {
|
||||
projectName = 'unknown project',
|
||||
memoryCount = 0,
|
||||
lastSessionTime,
|
||||
recentComponents = [],
|
||||
recentDecisions = []
|
||||
} = contextData;
|
||||
|
||||
const timeInfo = lastSessionTime ? ` (last worked: ${lastSessionTime})` : '';
|
||||
const contextParts = [];
|
||||
|
||||
contextParts.push(`🧠 Loaded ${memoryCount} memories from previous sessions for ${projectName}${timeInfo}`);
|
||||
|
||||
if (recentComponents.length > 0) {
|
||||
contextParts.push(`\n🎯 Recent components: ${recentComponents.slice(0, 3).join(', ')}`);
|
||||
}
|
||||
|
||||
if (recentDecisions.length > 0) {
|
||||
contextParts.push(`\n🔄 Recent decisions: ${recentDecisions.slice(0, 2).join(', ')}`);
|
||||
}
|
||||
|
||||
if (memoryCount > 0) {
|
||||
contextParts.push('\n💡 Use search_nodes("keywords") to find related work or open_nodes(["entity_name"]) to load specific components');
|
||||
}
|
||||
|
||||
return contextParts.join('');
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a CLI command and returns the result
|
||||
* @param {string} command - CLI command to execute
|
||||
* @param {Array} args - Command arguments
|
||||
* @param {Object} options - Spawn options
|
||||
* @returns {Promise<{stdout: string, stderr: string, success: boolean}>}
|
||||
*/
|
||||
export async function executeCliCommand(command, args = [], options = {}) {
|
||||
return new Promise((resolve) => {
|
||||
const process = spawn(command, args, {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
...options
|
||||
});
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
if (process.stdout) {
|
||||
process.stdout.on('data', (data) => {
|
||||
stdout += data.toString();
|
||||
});
|
||||
}
|
||||
|
||||
if (process.stderr) {
|
||||
process.stderr.on('data', (data) => {
|
||||
stderr += data.toString();
|
||||
});
|
||||
}
|
||||
|
||||
process.on('close', (code) => {
|
||||
resolve({
|
||||
stdout: stdout.trim(),
|
||||
stderr: stderr.trim(),
|
||||
success: code === 0
|
||||
});
|
||||
});
|
||||
|
||||
process.on('error', (error) => {
|
||||
resolve({
|
||||
stdout: '',
|
||||
stderr: error.message,
|
||||
success: false
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses context data from CLI output
|
||||
* @param {string} output - Raw CLI output
|
||||
* @returns {Object} Parsed context data
|
||||
*/
|
||||
export function parseContextData(output) {
|
||||
if (!output || !output.trim()) {
|
||||
return {
|
||||
memoryCount: 0,
|
||||
recentComponents: [],
|
||||
recentDecisions: []
|
||||
};
|
||||
}
|
||||
|
||||
// Try to parse as JSON first (if CLI outputs structured data)
|
||||
try {
|
||||
const parsed = JSON.parse(output);
|
||||
return {
|
||||
memoryCount: parsed.memoryCount || 0,
|
||||
recentComponents: parsed.recentComponents || [],
|
||||
recentDecisions: parsed.recentDecisions || [],
|
||||
lastSessionTime: parsed.lastSessionTime
|
||||
};
|
||||
} catch (e) {
|
||||
// If not JSON, treat as plain text context
|
||||
const lines = output.split('\n').filter(line => line.trim());
|
||||
return {
|
||||
memoryCount: lines.length,
|
||||
recentComponents: [],
|
||||
recentDecisions: [],
|
||||
rawContext: output
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates hook payload structure
|
||||
* @param {Object} payload - Hook payload to validate
|
||||
* @param {string} expectedHookType - Expected hook event name
|
||||
* @returns {{valid: boolean, error?: string}} Validation result
|
||||
*/
|
||||
export function validateHookPayload(payload, expectedHookType) {
|
||||
if (!payload || typeof payload !== 'object') {
|
||||
return { valid: false, error: 'Payload must be a valid object' };
|
||||
}
|
||||
|
||||
if (!payload.session_id || typeof payload.session_id !== 'string') {
|
||||
return { valid: false, error: 'Missing or invalid session_id' };
|
||||
}
|
||||
|
||||
if (!payload.transcript_path || typeof payload.transcript_path !== 'string') {
|
||||
return { valid: false, error: 'Missing or invalid transcript_path' };
|
||||
}
|
||||
|
||||
if (expectedHookType && payload.hook_event_name !== expectedHookType) {
|
||||
return { valid: false, error: `Expected hook_event_name to be ${expectedHookType}` };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs debug information if debug mode is enabled
|
||||
* @param {string} message - Debug message
|
||||
* @param {Object} data - Additional data to log
|
||||
*/
|
||||
export function debugLog(message, data = {}) {
|
||||
if (process.env.DEBUG === 'true' || process.env.CLAUDE_MEM_DEBUG === 'true') {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.error(`[${timestamp}] HOOK DEBUG: ${message}`, data);
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Claude Mem Installation Script
|
||||
|
||||
set -e
|
||||
|
||||
VERSION="${1:-latest}"
|
||||
PLATFORM=""
|
||||
ARCH=$(uname -m)
|
||||
OS=$(uname -s)
|
||||
|
||||
# Detect platform
|
||||
case "$OS" in
|
||||
Darwin)
|
||||
if [ "$ARCH" = "arm64" ]; then
|
||||
PLATFORM="macos-arm64"
|
||||
BINARY="claude-mem-macos-arm64"
|
||||
else
|
||||
PLATFORM="macos-x64"
|
||||
BINARY="claude-mem-macos-x64"
|
||||
fi
|
||||
;;
|
||||
Linux)
|
||||
if [ "$ARCH" = "aarch64" ]; then
|
||||
PLATFORM="linux-arm64"
|
||||
BINARY="claude-mem-linux-arm64"
|
||||
else
|
||||
PLATFORM="linux-x64"
|
||||
BINARY="claude-mem-linux"
|
||||
fi
|
||||
;;
|
||||
MINGW*|MSYS*|CYGWIN*)
|
||||
PLATFORM="windows-x64"
|
||||
BINARY="claude-mem.exe"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported platform: $OS $ARCH"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "📥 Downloading Claude Mem for $PLATFORM..."
|
||||
|
||||
# Download binary from GitHub releases
|
||||
if [ "$VERSION" = "latest" ]; then
|
||||
DOWNLOAD_URL="https://github.com/thedotmack/claude-mem/releases/latest/download/${BINARY}"
|
||||
else
|
||||
DOWNLOAD_URL="https://github.com/thedotmack/claude-mem/releases/download/${VERSION}/${BINARY}"
|
||||
fi
|
||||
|
||||
curl -L -o claude-mem "$DOWNLOAD_URL"
|
||||
|
||||
# Make executable (non-Windows)
|
||||
if [ "$OS" != "MINGW" ] && [ "$OS" != "MSYS" ] && [ "$OS" != "CYGWIN" ]; then
|
||||
chmod +x claude-mem
|
||||
fi
|
||||
|
||||
echo "✅ Claude Mem installed successfully!"
|
||||
echo "Run ./claude-mem --help to get started"
|
||||
Generated
+3882
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "7.1.3",
|
||||
"description": "Memory compression system for Claude Code - persist context across sessions",
|
||||
"keywords": [
|
||||
"claude",
|
||||
"claude-code",
|
||||
"claude-agent-sdk",
|
||||
"mcp",
|
||||
"plugin",
|
||||
"memory",
|
||||
"compression",
|
||||
"knowledge-graph",
|
||||
"transcript",
|
||||
"typescript",
|
||||
"nodejs"
|
||||
],
|
||||
"author": "Alex Newman",
|
||||
"license": "AGPL-3.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thedotmack/claude-mem.git"
|
||||
},
|
||||
"homepage": "https://github.com/thedotmack/claude-mem#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/thedotmack/claude-mem/issues"
|
||||
},
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"bun": ">=1.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node scripts/build-hooks.js",
|
||||
"test": "vitest",
|
||||
"test:parser": "npx tsx src/sdk/parser.test.ts",
|
||||
"test:context": "echo '{\"session_id\":\"test-'$(date +%s)'\",\"cwd\":\"'$(pwd)'\",\"source\":\"startup\"}' | node plugin/scripts/context-hook.js 2>/dev/null",
|
||||
"test:context:verbose": "echo '{\"session_id\":\"test-'$(date +%s)'\",\"cwd\":\"'$(pwd)'\",\"source\":\"startup\"}' | node plugin/scripts/context-hook.js",
|
||||
"sync-marketplace": "node scripts/sync-marketplace.cjs",
|
||||
"sync-marketplace:force": "node scripts/sync-marketplace.cjs --force",
|
||||
"build:binaries": "node scripts/build-worker-binary.js",
|
||||
"worker:start": "bun plugin/scripts/worker-cli.js start",
|
||||
"worker:stop": "bun plugin/scripts/worker-cli.js stop",
|
||||
"worker:restart": "bun plugin/scripts/worker-cli.js restart",
|
||||
"worker:status": "bun plugin/scripts/worker-cli.js status",
|
||||
"worker:logs": "tail -f ~/.claude-mem/logs/worker-$(date +%Y-%m-%d).log",
|
||||
"changelog:generate": "node scripts/generate-changelog.js",
|
||||
"usage:analyze": "node scripts/analyze-usage.js",
|
||||
"usage:today": "node scripts/analyze-usage.js $(date +%Y-%m-%d)",
|
||||
"translate-readme": "npx tsx scripts/translate-readme/cli.ts -v README.md zh ko ja"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk": "^0.1.67",
|
||||
"@modelcontextprotocol/sdk": "^1.20.1",
|
||||
"ansi-to-html": "^0.7.2",
|
||||
"express": "^4.18.2",
|
||||
"glob": "^11.0.3",
|
||||
"handlebars": "^4.7.8",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"zod-to-json-schema": "^3.24.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.19",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/react": "^18.3.5",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"esbuild": "^0.25.12",
|
||||
"tsx": "^4.20.6",
|
||||
"typescript": "^5.3.0",
|
||||
"vitest": "^4.0.15"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "claude-mem",
|
||||
"version": "7.1.3",
|
||||
"description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions",
|
||||
"author": {
|
||||
"name": "Alex Newman"
|
||||
},
|
||||
"repository": "https://github.com/thedotmack/claude-mem",
|
||||
"license": "AGPL-3.0",
|
||||
"keywords": [
|
||||
"memory",
|
||||
"context",
|
||||
"persistence",
|
||||
"hooks",
|
||||
"mcp"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"claude-mem-search": {
|
||||
"type": "stdio",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/mcp-server.cjs"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"description": "Claude-mem memory system hooks",
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "startup|clear|compact",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/smart-install.js\" && bun \"${CLAUDE_PLUGIN_ROOT}/scripts/context-hook.js\"",
|
||||
"timeout": 300
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/user-message-hook.js\"",
|
||||
"timeout": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"UserPromptSubmit": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/new-hook.js\"",
|
||||
"timeout": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "*",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/save-hook.js\"",
|
||||
"timeout": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/summary-hook.js\"",
|
||||
"timeout": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SessionEnd": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bun \"${CLAUDE_PLUGIN_ROOT}/scripts/cleanup-hook.js\"",
|
||||
"timeout": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "claude-mem-plugin",
|
||||
"version": "7.1.3",
|
||||
"private": true,
|
||||
"description": "Runtime dependencies for claude-mem bundled hooks",
|
||||
"type": "module",
|
||||
"dependencies": {},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"bun": ">=1.0.0"
|
||||
}
|
||||
}
|
||||
Executable
+11
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Executable
+9
File diff suppressed because one or more lines are too long
Executable
+17
File diff suppressed because one or more lines are too long
Executable
+11
File diff suppressed because one or more lines are too long
Executable
+11
File diff suppressed because one or more lines are too long
@@ -0,0 +1,335 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Smart Install Script for claude-mem
|
||||
*
|
||||
* Ensures Bun runtime and uv (Python package manager) are installed
|
||||
* (auto-installs if missing) and handles dependency installation when needed.
|
||||
*/
|
||||
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
||||
import { execSync, spawnSync } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
|
||||
const ROOT = join(homedir(), '.claude', 'plugins', 'marketplaces', 'thedotmack');
|
||||
const MARKER = join(ROOT, '.install-version');
|
||||
const IS_WINDOWS = process.platform === 'win32';
|
||||
|
||||
/**
|
||||
* Check if Bun is installed and accessible
|
||||
*/
|
||||
function isBunInstalled() {
|
||||
try {
|
||||
const result = spawnSync('bun', ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: IS_WINDOWS
|
||||
});
|
||||
if (result.status === 0) return true;
|
||||
} catch {
|
||||
// PATH check failed, try common installation paths
|
||||
}
|
||||
|
||||
// Check common installation paths (handles fresh installs before PATH reload)
|
||||
const bunPaths = IS_WINDOWS
|
||||
? [join(homedir(), '.bun', 'bin', 'bun.exe')]
|
||||
: [join(homedir(), '.bun', 'bin', 'bun'), '/usr/local/bin/bun'];
|
||||
|
||||
return bunPaths.some(existsSync);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Bun executable path (from PATH or common install locations)
|
||||
*/
|
||||
function getBunPath() {
|
||||
// Try PATH first
|
||||
try {
|
||||
const result = spawnSync('bun', ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: IS_WINDOWS
|
||||
});
|
||||
if (result.status === 0) return 'bun';
|
||||
} catch {
|
||||
// Not in PATH
|
||||
}
|
||||
|
||||
// Check common installation paths
|
||||
const bunPaths = IS_WINDOWS
|
||||
? [join(homedir(), '.bun', 'bin', 'bun.exe')]
|
||||
: [join(homedir(), '.bun', 'bin', 'bun'), '/usr/local/bin/bun'];
|
||||
|
||||
for (const bunPath of bunPaths) {
|
||||
if (existsSync(bunPath)) return bunPath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Bun version if installed
|
||||
*/
|
||||
function getBunVersion() {
|
||||
const bunPath = getBunPath();
|
||||
if (!bunPath) return null;
|
||||
|
||||
try {
|
||||
const result = spawnSync(bunPath, ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: IS_WINDOWS
|
||||
});
|
||||
return result.status === 0 ? result.stdout.trim() : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if uv is installed and accessible
|
||||
*/
|
||||
function isUvInstalled() {
|
||||
try {
|
||||
const result = spawnSync('uv', ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: IS_WINDOWS
|
||||
});
|
||||
if (result.status === 0) return true;
|
||||
} catch {
|
||||
// PATH check failed, try common installation paths
|
||||
}
|
||||
|
||||
// Check common installation paths (handles fresh installs before PATH reload)
|
||||
const uvPaths = IS_WINDOWS
|
||||
? [join(homedir(), '.local', 'bin', 'uv.exe'), join(homedir(), '.cargo', 'bin', 'uv.exe')]
|
||||
: [join(homedir(), '.local', 'bin', 'uv'), join(homedir(), '.cargo', 'bin', 'uv'), '/usr/local/bin/uv'];
|
||||
|
||||
return uvPaths.some(existsSync);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get uv version if installed
|
||||
*/
|
||||
function getUvVersion() {
|
||||
try {
|
||||
const result = spawnSync('uv', ['--version'], {
|
||||
encoding: 'utf-8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
shell: IS_WINDOWS
|
||||
});
|
||||
return result.status === 0 ? result.stdout.trim() : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install Bun automatically based on platform
|
||||
*/
|
||||
function installBun() {
|
||||
console.error('🔧 Bun not found. Installing Bun runtime...');
|
||||
|
||||
try {
|
||||
if (IS_WINDOWS) {
|
||||
// Windows: Use PowerShell installer
|
||||
console.error(' Installing via PowerShell...');
|
||||
execSync('powershell -c "irm bun.sh/install.ps1 | iex"', {
|
||||
stdio: 'inherit',
|
||||
shell: true
|
||||
});
|
||||
} else {
|
||||
// Unix/macOS: Use curl installer
|
||||
console.error(' Installing via curl...');
|
||||
execSync('curl -fsSL https://bun.sh/install | bash', {
|
||||
stdio: 'inherit',
|
||||
shell: true
|
||||
});
|
||||
}
|
||||
|
||||
// Verify installation
|
||||
if (isBunInstalled()) {
|
||||
const version = getBunVersion();
|
||||
console.error(`✅ Bun ${version} installed successfully`);
|
||||
return true;
|
||||
} else {
|
||||
// Bun may be installed but not in PATH yet for this session
|
||||
// Try common installation paths
|
||||
const bunPaths = IS_WINDOWS
|
||||
? [join(homedir(), '.bun', 'bin', 'bun.exe')]
|
||||
: [join(homedir(), '.bun', 'bin', 'bun'), '/usr/local/bin/bun'];
|
||||
|
||||
for (const bunPath of bunPaths) {
|
||||
if (existsSync(bunPath)) {
|
||||
console.error(`✅ Bun installed at ${bunPath}`);
|
||||
console.error('⚠️ Please restart your terminal or add Bun to PATH:');
|
||||
if (IS_WINDOWS) {
|
||||
console.error(` $env:Path += ";${join(homedir(), '.bun', 'bin')}"`);
|
||||
} else {
|
||||
console.error(` export PATH="$HOME/.bun/bin:$PATH"`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Bun installation completed but binary not found');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to install Bun automatically');
|
||||
console.error(' Please install manually:');
|
||||
if (IS_WINDOWS) {
|
||||
console.error(' - winget install Oven-sh.Bun');
|
||||
console.error(' - Or: powershell -c "irm bun.sh/install.ps1 | iex"');
|
||||
} else {
|
||||
console.error(' - curl -fsSL https://bun.sh/install | bash');
|
||||
console.error(' - Or: brew install oven-sh/bun/bun');
|
||||
}
|
||||
console.error(' Then restart your terminal and try again.');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install uv automatically based on platform
|
||||
*/
|
||||
function installUv() {
|
||||
console.error('🐍 Installing uv for Python/Chroma support...');
|
||||
|
||||
try {
|
||||
if (IS_WINDOWS) {
|
||||
// Windows: Use PowerShell installer
|
||||
console.error(' Installing via PowerShell...');
|
||||
execSync('powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"', {
|
||||
stdio: 'inherit',
|
||||
shell: true
|
||||
});
|
||||
} else {
|
||||
// Unix/macOS: Use curl installer
|
||||
console.error(' Installing via curl...');
|
||||
execSync('curl -LsSf https://astral.sh/uv/install.sh | sh', {
|
||||
stdio: 'inherit',
|
||||
shell: true
|
||||
});
|
||||
}
|
||||
|
||||
// Verify installation
|
||||
if (isUvInstalled()) {
|
||||
const version = getUvVersion();
|
||||
console.error(`✅ uv ${version} installed successfully`);
|
||||
return true;
|
||||
} else {
|
||||
// uv may be installed but not in PATH yet for this session
|
||||
// Try common installation paths
|
||||
const uvPaths = IS_WINDOWS
|
||||
? [join(homedir(), '.local', 'bin', 'uv.exe'), join(homedir(), '.cargo', 'bin', 'uv.exe')]
|
||||
: [join(homedir(), '.local', 'bin', 'uv'), join(homedir(), '.cargo', 'bin', 'uv'), '/usr/local/bin/uv'];
|
||||
|
||||
for (const uvPath of uvPaths) {
|
||||
if (existsSync(uvPath)) {
|
||||
console.error(`✅ uv installed at ${uvPath}`);
|
||||
console.error('⚠️ Please restart your terminal or add uv to PATH:');
|
||||
if (IS_WINDOWS) {
|
||||
console.error(` $env:Path += ";${join(homedir(), '.local', 'bin')}"`);
|
||||
} else {
|
||||
console.error(` export PATH="$HOME/.local/bin:$PATH"`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('uv installation completed but binary not found');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to install uv automatically');
|
||||
console.error(' Please install manually:');
|
||||
if (IS_WINDOWS) {
|
||||
console.error(' - winget install astral-sh.uv');
|
||||
console.error(' - Or: powershell -c "irm https://astral.sh/uv/install.ps1 | iex"');
|
||||
} else {
|
||||
console.error(' - curl -LsSf https://astral.sh/uv/install.sh | sh');
|
||||
console.error(' - Or: brew install uv (macOS)');
|
||||
}
|
||||
console.error(' Then restart your terminal and try again.');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if dependencies need to be installed
|
||||
*/
|
||||
function needsInstall() {
|
||||
if (!existsSync(join(ROOT, 'node_modules'))) return true;
|
||||
try {
|
||||
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
|
||||
const marker = JSON.parse(readFileSync(MARKER, 'utf-8'));
|
||||
return pkg.version !== marker.version || getBunVersion() !== marker.bun;
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Install dependencies using Bun
|
||||
*/
|
||||
function installDeps() {
|
||||
const bunPath = getBunPath();
|
||||
if (!bunPath) {
|
||||
throw new Error('Bun executable not found');
|
||||
}
|
||||
|
||||
console.error('📦 Installing dependencies with Bun...');
|
||||
|
||||
// Quote path for Windows paths with spaces
|
||||
const bunCmd = IS_WINDOWS && bunPath.includes(' ') ? `"${bunPath}"` : bunPath;
|
||||
|
||||
try {
|
||||
execSync(`${bunCmd} install`, { cwd: ROOT, stdio: 'inherit', shell: IS_WINDOWS });
|
||||
} catch {
|
||||
// Retry with force flag
|
||||
execSync(`${bunCmd} install --force`, { cwd: ROOT, stdio: 'inherit', shell: IS_WINDOWS });
|
||||
}
|
||||
|
||||
// Write version marker
|
||||
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8'));
|
||||
writeFileSync(MARKER, JSON.stringify({
|
||||
version: pkg.version,
|
||||
bun: getBunVersion(),
|
||||
uv: getUvVersion(),
|
||||
installedAt: new Date().toISOString()
|
||||
}));
|
||||
}
|
||||
|
||||
// Main execution
|
||||
try {
|
||||
// Step 1: Ensure Bun is installed (REQUIRED)
|
||||
if (!isBunInstalled()) {
|
||||
installBun();
|
||||
|
||||
// Re-check after installation
|
||||
if (!isBunInstalled()) {
|
||||
console.error('❌ Bun is required but not available in PATH');
|
||||
console.error(' Please restart your terminal after installation');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Ensure uv is installed (REQUIRED for vector search)
|
||||
if (!isUvInstalled()) {
|
||||
installUv();
|
||||
|
||||
// Re-check after installation
|
||||
if (!isUvInstalled()) {
|
||||
console.error('❌ uv is required but not available in PATH');
|
||||
console.error(' Please restart your terminal after installation');
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Install dependencies if needed
|
||||
if (needsInstall()) {
|
||||
installDeps();
|
||||
console.error('✅ Dependencies installed');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('❌ Installation failed:', e.message);
|
||||
process.exit(1);
|
||||
}
|
||||
Executable
+15
File diff suppressed because one or more lines are too long
Executable
+38
File diff suppressed because one or more lines are too long
Executable
+4
File diff suppressed because one or more lines are too long
Executable
+1357
File diff suppressed because one or more lines are too long
@@ -0,0 +1,143 @@
|
||||
---
|
||||
name: mem-search
|
||||
description: Search claude-mem's persistent cross-session memory database. Use when user asks "did we already solve this?", "how did we do X last time?", or needs work from previous sessions.
|
||||
---
|
||||
|
||||
# Memory Search
|
||||
|
||||
Search past work across all sessions. Simple workflow: search → get IDs → fetch details by ID.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use when users ask about PREVIOUS sessions (not current conversation):
|
||||
- "Did we already fix this?"
|
||||
- "How did we solve X last time?"
|
||||
- "What happened last week?"
|
||||
|
||||
## The Workflow
|
||||
|
||||
**ALWAYS follow this exact flow:**
|
||||
|
||||
1. **Search** - Get an index of results with IDs
|
||||
2. **Timeline** (optional) - Get context around top results to understand what was happening
|
||||
3. **Review** - Look at titles/dates/context, pick relevant IDs
|
||||
4. **Fetch** - Get full details ONLY for those IDs
|
||||
|
||||
### Step 1: Search Everything
|
||||
|
||||
```bash
|
||||
curl "http://localhost:37777/api/search?query=authentication&format=index&limit=5"
|
||||
```
|
||||
|
||||
**Required parameters:**
|
||||
- `query` - Search term
|
||||
- `format=index` - ALWAYS start with index (lightweight)
|
||||
- `limit=5` - Start small (3-5 results)
|
||||
|
||||
**Returns:**
|
||||
```
|
||||
1. [feature] Added JWT authentication
|
||||
Date: 11/17/2025, 3:48:45 PM
|
||||
ID: 11131
|
||||
|
||||
2. [bugfix] Fixed auth token expiration
|
||||
Date: 11/16/2025, 2:15:22 PM
|
||||
ID: 10942
|
||||
```
|
||||
|
||||
### Step 2: Get Timeline Context (Optional)
|
||||
|
||||
When you need to understand "what was happening" around a result:
|
||||
|
||||
```bash
|
||||
# Get timeline around an observation ID
|
||||
curl "http://localhost:37777/api/timeline?anchor=11131&depth_before=3&depth_after=3"
|
||||
|
||||
# Or use query to find + get timeline in one step
|
||||
curl "http://localhost:37777/api/timeline?query=authentication&depth_before=3&depth_after=3"
|
||||
```
|
||||
|
||||
**Returns exactly `depth_before + 1 + depth_after` items** - observations, sessions, and prompts interleaved chronologically around the anchor.
|
||||
|
||||
**When to use:**
|
||||
- User asks "what was happening when..."
|
||||
- Need to understand sequence of events
|
||||
- Want broader context around a specific observation
|
||||
|
||||
### Step 3: Pick IDs
|
||||
|
||||
Review the index results (and timeline if used). Identify which IDs are actually relevant. Discard the rest.
|
||||
|
||||
### Step 4: Fetch by ID
|
||||
|
||||
For each relevant ID, fetch full details:
|
||||
|
||||
```bash
|
||||
# Fetch observation
|
||||
curl "http://localhost:37777/api/observation/11131"
|
||||
|
||||
# Fetch session
|
||||
curl "http://localhost:37777/api/session/2005"
|
||||
|
||||
# Fetch prompt
|
||||
curl "http://localhost:37777/api/prompt/5421"
|
||||
```
|
||||
|
||||
**ID formats:**
|
||||
- Observations: Just the number (11131)
|
||||
- Sessions: Just the number (2005) from "S2005"
|
||||
- Prompts: Just the number (5421)
|
||||
|
||||
## Search Parameters
|
||||
|
||||
**Basic:**
|
||||
- `query` - What to search for (required)
|
||||
- `format` - "index" or "full" (always use "index" first)
|
||||
- `limit` - How many results (default 5, max 100)
|
||||
|
||||
**Filters (optional):**
|
||||
- `type` - Filter to "observations", "sessions", or "prompts"
|
||||
- `project` - Filter by project name
|
||||
- `dateStart` - Start date (YYYY-MM-DD or epoch timestamp)
|
||||
- `dateEnd` - End date (YYYY-MM-DD or epoch timestamp)
|
||||
- `obs_type` - Filter observations by type (comma-separated): bugfix, feature, decision, discovery, change
|
||||
|
||||
## Examples
|
||||
|
||||
**Find recent bug fixes:**
|
||||
```bash
|
||||
curl "http://localhost:37777/api/search?query=bug&type=observations&obs_type=bugfix&format=index&limit=5"
|
||||
```
|
||||
|
||||
**Find what happened last week:**
|
||||
```bash
|
||||
curl "http://localhost:37777/api/search?query=&type=observations&dateStart=2025-11-11&format=index&limit=10"
|
||||
```
|
||||
|
||||
**Search everything:**
|
||||
```bash
|
||||
curl "http://localhost:37777/api/search?query=database+migration&format=index&limit=5"
|
||||
```
|
||||
|
||||
## Why This Workflow?
|
||||
|
||||
**Token efficiency:**
|
||||
- Index format: ~50-100 tokens per result
|
||||
- Full format: ~500-1000 tokens per result
|
||||
- **10x difference** - only fetch full when you know it's relevant
|
||||
|
||||
**Clarity:**
|
||||
- See everything first
|
||||
- Pick what matters
|
||||
- Get details only for what you need
|
||||
|
||||
## Error Handling
|
||||
|
||||
If search fails, tell the user the worker isn't available and suggest:
|
||||
```bash
|
||||
pm2 list # Check if worker is running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Remember:** ALWAYS search with format=index first. ALWAYS fetch by ID for details. The IDs are there for a reason - USE THEM.
|
||||
@@ -0,0 +1,124 @@
|
||||
# Search by Concept
|
||||
|
||||
Find observations tagged with specific concepts.
|
||||
|
||||
## When to Use
|
||||
|
||||
- User asks: "What discoveries did we make?"
|
||||
- User asks: "What patterns did we identify?"
|
||||
- User asks: "What gotchas did we encounter?"
|
||||
- Looking for observations with semantic tags
|
||||
|
||||
## Command
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-concept?concept=discovery&format=index&limit=5"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
- **concept** (required): Concept tag to search for
|
||||
- `discovery` - New discoveries and insights
|
||||
- `problem-solution` - Problems and their solutions
|
||||
- `what-changed` - Change descriptions
|
||||
- `how-it-works` - Explanations of mechanisms
|
||||
- `pattern` - Identified patterns
|
||||
- `gotcha` - Edge cases and gotchas
|
||||
- `change` - General changes
|
||||
- **format**: "index" (summary) or "full" (complete details). Default: "full"
|
||||
- **limit**: Number of results (default: 20, max: 100)
|
||||
- **project**: Filter by project name (optional)
|
||||
- **dateStart/dateEnd**: Filter by date range (optional)
|
||||
|
||||
## When to Use Each Format
|
||||
|
||||
**Use format=index for:**
|
||||
- Quick overviews of observations by concept
|
||||
- Finding IDs for deeper investigation
|
||||
- Listing multiple results
|
||||
- **Token cost: ~50-100 per result**
|
||||
|
||||
**Use format=full for:**
|
||||
- Complete details including narrative, facts, files, concepts
|
||||
- Understanding the full context of specific observations
|
||||
- **Token cost: ~500-1000 per result**
|
||||
|
||||
## Example Response (format=index)
|
||||
|
||||
```json
|
||||
{
|
||||
"concept": "discovery",
|
||||
"count": 3,
|
||||
"format": "index",
|
||||
"results": [
|
||||
{
|
||||
"id": 1240,
|
||||
"type": "discovery",
|
||||
"title": "Worker service uses PM2 for process management",
|
||||
"subtitle": "Discovered persistent background worker pattern",
|
||||
"created_at_epoch": 1699564800000,
|
||||
"project": "claude-mem",
|
||||
"concepts": ["discovery", "how-it-works"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## How to Present Results
|
||||
|
||||
For format=index, present as a compact list:
|
||||
|
||||
```markdown
|
||||
Found 3 observations tagged with "discovery":
|
||||
|
||||
🔵 **#1240** Worker service uses PM2 for process management
|
||||
> Discovered persistent background worker pattern
|
||||
> Nov 9, 2024 • claude-mem
|
||||
> Tags: discovery, how-it-works
|
||||
|
||||
🔵 **#1241** FTS5 full-text search enables instant searches
|
||||
> SQLite FTS5 virtual tables provide sub-100ms search
|
||||
> Nov 9, 2024 • claude-mem
|
||||
> Tags: discovery, pattern
|
||||
```
|
||||
|
||||
For complete formatting guidelines, see [formatting.md](formatting.md).
|
||||
|
||||
## Available Concepts
|
||||
|
||||
| Concept | Description | When to Use |
|
||||
|---------|-------------|-------------|
|
||||
| `discovery` | New discoveries and insights | Finding what was learned |
|
||||
| `problem-solution` | Problems and their solutions | Finding how issues were resolved |
|
||||
| `what-changed` | Change descriptions | Understanding what changed |
|
||||
| `how-it-works` | Explanations of mechanisms | Learning how things work |
|
||||
| `pattern` | Identified patterns | Finding design patterns |
|
||||
| `gotcha` | Edge cases and gotchas | Learning about pitfalls |
|
||||
| `change` | General changes | Tracking modifications |
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Missing concept parameter:**
|
||||
```json
|
||||
{"error": "Missing required parameter: concept"}
|
||||
```
|
||||
Fix: Add the concept parameter
|
||||
|
||||
**Invalid concept:**
|
||||
```json
|
||||
{"error": "Invalid concept: foobar. Valid concepts: discovery, problem-solution, what-changed, how-it-works, pattern, gotcha, change"}
|
||||
```
|
||||
Fix: Use one of the valid concept values
|
||||
|
||||
## Tips
|
||||
|
||||
1. Use format=index first to see overview
|
||||
2. Start with limit=5-10 to avoid token overload
|
||||
3. Combine concepts with type filtering for precision
|
||||
4. Use `discovery` for learning what was found during investigation
|
||||
5. Use `problem-solution` for finding how past issues were resolved
|
||||
|
||||
**Token Efficiency:**
|
||||
- Start with format=index (~50-100 tokens per result)
|
||||
- Use format=full only for relevant items (~500-1000 tokens per result)
|
||||
- See [../principles/progressive-disclosure.md](../principles/progressive-disclosure.md)
|
||||
@@ -0,0 +1,127 @@
|
||||
# Search by File
|
||||
|
||||
Find all work related to a specific file path.
|
||||
|
||||
## When to Use
|
||||
|
||||
- User asks: "What changes to auth/login.ts?"
|
||||
- User asks: "What work was done on this file?"
|
||||
- User asks: "Show me the history of src/services/worker.ts"
|
||||
- Looking for all observations that reference a file
|
||||
|
||||
## Command
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-file?filePath=src/services/worker-service.ts&format=index&limit=10"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
- **filePath** (required): File path to search for (supports partial matching)
|
||||
- Full path: `src/services/worker-service.ts`
|
||||
- Partial path: `worker-service.ts`
|
||||
- Directory: `src/hooks/`
|
||||
- **format**: "index" (summary) or "full" (complete details). Default: "full"
|
||||
- **limit**: Number of results (default: 20, max: 100)
|
||||
- **project**: Filter by project name (optional)
|
||||
- **dateStart/dateEnd**: Filter by date range (optional)
|
||||
|
||||
## When to Use Each Format
|
||||
|
||||
**Use format=index for:**
|
||||
- Quick overviews of work on a file
|
||||
- Finding IDs for deeper investigation
|
||||
- Listing multiple changes
|
||||
- **Token cost: ~50-100 per result**
|
||||
|
||||
**Use format=full for:**
|
||||
- Complete details including narrative, facts, files, concepts
|
||||
- Understanding the full context of specific changes
|
||||
- **Token cost: ~500-1000 per result**
|
||||
|
||||
## Example Response (format=index)
|
||||
|
||||
```json
|
||||
{
|
||||
"filePath": "src/services/worker-service.ts",
|
||||
"count": 8,
|
||||
"format": "index",
|
||||
"results": [
|
||||
{
|
||||
"id": 1245,
|
||||
"type": "refactor",
|
||||
"title": "Simplified worker health check logic",
|
||||
"subtitle": "Removed redundant PM2 status check",
|
||||
"created_at_epoch": 1699564800000,
|
||||
"project": "claude-mem",
|
||||
"files": ["src/services/worker-service.ts", "src/services/worker-utils.ts"]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## How to Present Results
|
||||
|
||||
For format=index, present as a compact list:
|
||||
|
||||
```markdown
|
||||
Found 8 observations related to "src/services/worker-service.ts":
|
||||
|
||||
🔄 **#1245** Simplified worker health check logic
|
||||
> Removed redundant PM2 status check
|
||||
> Nov 9, 2024 • claude-mem
|
||||
> Files: worker-service.ts, worker-utils.ts
|
||||
|
||||
🟣 **#1246** Added SSE endpoint for real-time updates
|
||||
> Implemented Server-Sent Events for viewer UI
|
||||
> Nov 8, 2024 • claude-mem
|
||||
> Files: worker-service.ts
|
||||
```
|
||||
|
||||
For complete formatting guidelines, see [formatting.md](formatting.md).
|
||||
|
||||
## Partial Path Matching
|
||||
|
||||
The file path parameter supports partial matching:
|
||||
|
||||
```bash
|
||||
# These all match "src/services/worker-service.ts"
|
||||
curl -s "http://localhost:37777/api/search/by-file?filePath=worker-service.ts&format=index"
|
||||
curl -s "http://localhost:37777/api/search/by-file?filePath=services/worker&format=index"
|
||||
curl -s "http://localhost:37777/api/search/by-file?filePath=worker-service&format=index"
|
||||
```
|
||||
|
||||
## Directory Searches
|
||||
|
||||
Search for all work in a directory:
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-file?filePath=src/hooks/&format=index&limit=20"
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Missing filePath parameter:**
|
||||
```json
|
||||
{"error": "Missing required parameter: filePath"}
|
||||
```
|
||||
Fix: Add the filePath parameter
|
||||
|
||||
**No results found:**
|
||||
```json
|
||||
{"filePath": "nonexistent.ts", "count": 0, "results": []}
|
||||
```
|
||||
Response: "No observations found for 'nonexistent.ts'. Try a partial path or check the spelling."
|
||||
|
||||
## Tips
|
||||
|
||||
1. Use format=index first to see overview of all changes
|
||||
2. Start with partial paths (e.g., filename only) for broader matches
|
||||
3. Use full paths when you need specific file matches
|
||||
4. Combine with dateStart to see recent changes: `?filePath=worker.ts&dateStart=2024-11-01`
|
||||
5. Use directory searches to see all work in a module
|
||||
|
||||
**Token Efficiency:**
|
||||
- Start with format=index (~50-100 tokens per result)
|
||||
- Use format=full only for relevant items (~500-1000 tokens per result)
|
||||
- See [../principles/progressive-disclosure.md](../principles/progressive-disclosure.md)
|
||||
@@ -0,0 +1,123 @@
|
||||
# Search by Type
|
||||
|
||||
Find observations by type: bugfix, feature, refactor, decision, discovery, or change.
|
||||
|
||||
## When to Use
|
||||
|
||||
- User asks: "What bugs did we fix?"
|
||||
- User asks: "What features did we add?"
|
||||
- User asks: "What decisions did we make?"
|
||||
- Looking for specific types of work
|
||||
|
||||
## Command
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-type?type=bugfix&format=index&limit=5"
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
- **type** (required): One or more types (comma-separated)
|
||||
- `bugfix` - Bug fixes
|
||||
- `feature` - New features
|
||||
- `refactor` - Code refactoring
|
||||
- `decision` - Architectural/design decisions
|
||||
- `discovery` - Discoveries and insights
|
||||
- `change` - General changes
|
||||
- **format**: "index" (summary) or "full" (complete details). Default: "full"
|
||||
- **limit**: Number of results (default: 20, max: 100)
|
||||
- **project**: Filter by project name (optional)
|
||||
- **dateStart/dateEnd**: Filter by date range (optional)
|
||||
|
||||
## When to Use Each Format
|
||||
|
||||
**Use format=index for:**
|
||||
- Quick overviews of work by type
|
||||
- Finding IDs for deeper investigation
|
||||
- Listing multiple results
|
||||
- **Token cost: ~50-100 per result**
|
||||
|
||||
**Use format=full for:**
|
||||
- Complete details including narrative, facts, files, concepts
|
||||
- Understanding the full context of specific observations
|
||||
- **Token cost: ~500-1000 per result**
|
||||
|
||||
## Example Response (format=index)
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "bugfix",
|
||||
"count": 5,
|
||||
"format": "index",
|
||||
"results": [
|
||||
{
|
||||
"id": 1235,
|
||||
"type": "bugfix",
|
||||
"title": "Fixed token expiration edge case",
|
||||
"subtitle": "Handled race condition in refresh flow",
|
||||
"created_at_epoch": 1699564800000,
|
||||
"project": "api-server"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## How to Present Results
|
||||
|
||||
For format=index, present as a compact list with type emojis:
|
||||
|
||||
```markdown
|
||||
Found 5 bugfixes:
|
||||
|
||||
🔴 **#1235** Fixed token expiration edge case
|
||||
> Handled race condition in refresh flow
|
||||
> Nov 9, 2024 • api-server
|
||||
|
||||
🔴 **#1236** Resolved memory leak in worker
|
||||
> Fixed event listener cleanup
|
||||
> Nov 8, 2024 • worker-service
|
||||
```
|
||||
|
||||
**Type Emojis:**
|
||||
- 🔴 bugfix
|
||||
- 🟣 feature
|
||||
- 🔄 refactor
|
||||
- 🔵 discovery
|
||||
- 🧠 decision
|
||||
- ✅ change
|
||||
|
||||
For complete formatting guidelines, see [formatting.md](formatting.md).
|
||||
|
||||
## Multiple Types
|
||||
|
||||
To search for multiple types:
|
||||
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-type?type=bugfix,feature&format=index&limit=10"
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Missing type parameter:**
|
||||
```json
|
||||
{"error": "Missing required parameter: type"}
|
||||
```
|
||||
Fix: Add the type parameter
|
||||
|
||||
**Invalid type:**
|
||||
```json
|
||||
{"error": "Invalid type: foobar. Valid types: bugfix, feature, refactor, decision, discovery, change"}
|
||||
```
|
||||
Fix: Use one of the valid type values
|
||||
|
||||
## Tips
|
||||
|
||||
1. Use format=index first to see overview
|
||||
2. Start with limit=5-10 to avoid token overload
|
||||
3. Combine with dateStart for recent work: `?type=bugfix&dateStart=2024-11-01`
|
||||
4. Use project filtering when working on one codebase
|
||||
|
||||
**Token Efficiency:**
|
||||
- Start with format=index (~50-100 tokens per result)
|
||||
- Use format=full only for relevant items (~500-1000 tokens per result)
|
||||
- See [../principles/progressive-disclosure.md](../principles/progressive-disclosure.md)
|
||||
@@ -0,0 +1,251 @@
|
||||
# Common Workflows
|
||||
|
||||
Step-by-step guides for typical user requests using the search API.
|
||||
|
||||
## Workflow 1: Understanding Past Work
|
||||
|
||||
**User asks:** "What did we do last session?" or "Catch me up on recent work"
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Get recent context** (fastest path):
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/context/recent?limit=3"
|
||||
```
|
||||
|
||||
2. **Present as narrative:**
|
||||
```markdown
|
||||
## Recent Work
|
||||
|
||||
### Session #545 - Nov 9, 2024
|
||||
Implemented JWT authentication system
|
||||
|
||||
**Completed:**
|
||||
- Added token-based auth with refresh tokens
|
||||
- Created JWT signing and verification logic
|
||||
|
||||
**Key Learning:** JWT expiration requires careful handling of refresh race conditions
|
||||
```
|
||||
|
||||
**Why this workflow:**
|
||||
- Single request gets both sessions and observations
|
||||
- Optimized for "catch me up" questions
|
||||
- ~1,500-2,500 tokens for 3 sessions
|
||||
|
||||
---
|
||||
|
||||
## Workflow 2: Finding Specific Bug Fixes
|
||||
|
||||
**User asks:** "What bugs did we fix?" or "Show me recent bug fixes"
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Search by type** (index format first):
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-type?type=bugfix&format=index&limit=5"
|
||||
```
|
||||
|
||||
2. **Review index results**, identify relevant items
|
||||
|
||||
3. **Get full details** for specific bugs:
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-type?type=bugfix&format=full&limit=1&offset=2"
|
||||
```
|
||||
|
||||
4. **Present findings:**
|
||||
```markdown
|
||||
Found 5 bug fixes:
|
||||
|
||||
🔴 **#1235** Fixed token expiration edge case
|
||||
> Handled race condition in refresh flow
|
||||
> Nov 9, 2024 • api-server
|
||||
|
||||
[Click for full details on #1235]
|
||||
```
|
||||
|
||||
**Why this workflow:**
|
||||
- Progressive disclosure: index first, full details selectively
|
||||
- Type-specific search is more efficient than generic search
|
||||
- ~250-500 tokens for index, ~750-1000 per full detail
|
||||
|
||||
---
|
||||
|
||||
## Workflow 3: Understanding File History
|
||||
|
||||
**User asks:** "What changes to auth/login.ts?" or "Show me work on this file"
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Search by file** (index format):
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-file?filePath=auth/login.ts&format=index&limit=10"
|
||||
```
|
||||
|
||||
2. **Review chronological changes**
|
||||
|
||||
3. **Get full details** for specific changes:
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/by-file?filePath=auth/login.ts&format=full&limit=1&offset=3"
|
||||
```
|
||||
|
||||
4. **Present as file timeline:**
|
||||
```markdown
|
||||
## History of auth/login.ts
|
||||
|
||||
🟣 **#1230** Added JWT authentication (Nov 9)
|
||||
🔴 **#1235** Fixed token expiration bug (Nov 9)
|
||||
🔄 **#1240** Refactored auth flow (Nov 8)
|
||||
```
|
||||
|
||||
**Why this workflow:**
|
||||
- File-specific search finds all related work
|
||||
- Index format shows chronological overview
|
||||
- Selective full details for deep dives
|
||||
|
||||
---
|
||||
|
||||
## Workflow 4: Timeline Investigation
|
||||
|
||||
**User asks:** "What was happening when we deployed?" or "Show me context around that bug fix"
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Find the event** using search:
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/observations?query=deployment&format=index&limit=5"
|
||||
```
|
||||
|
||||
2. **Note observation ID** (e.g., #1234)
|
||||
|
||||
3. **Get timeline context**:
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/timeline/context?anchor=1234&depth_before=10&depth_after=10"
|
||||
```
|
||||
|
||||
4. **Present as chronological narrative:**
|
||||
```markdown
|
||||
## Timeline: Deployment
|
||||
|
||||
### Before (10 records)
|
||||
**2:45 PM** - 🟣 Prepared deployment scripts
|
||||
**2:50 PM** - 💬 User asked: "Are we ready to deploy?"
|
||||
|
||||
### ⭐ Anchor Point (2:55 PM)
|
||||
🎯 **Observation #1234**: Deployed to production
|
||||
|
||||
### After (10 records)
|
||||
**3:00 PM** - 🔴 Fixed post-deployment routing issue
|
||||
```
|
||||
|
||||
**Why this workflow:**
|
||||
- Timeline shows temporal context (what happened before/after)
|
||||
- Captures causality between events
|
||||
- All record types (observations, sessions, prompts) interleaved
|
||||
|
||||
---
|
||||
|
||||
## Workflow 5: Quick Timeline (One Request)
|
||||
|
||||
**User asks:** "Timeline of authentication work"
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Use timeline-by-query** (auto mode):
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/timeline/by-query?query=authentication&mode=auto&depth_before=10&depth_after=10"
|
||||
```
|
||||
|
||||
2. **Present timeline directly:**
|
||||
```markdown
|
||||
## Timeline: Authentication
|
||||
|
||||
**Best Match:** 🟣 Observation #1234 - Implemented JWT authentication
|
||||
|
||||
### Context (21 records)
|
||||
[... timeline around best match ...]
|
||||
```
|
||||
|
||||
**Why this workflow:**
|
||||
- Single request combines search + timeline
|
||||
- Fastest path when query is specific
|
||||
- Auto mode uses top result as anchor
|
||||
|
||||
**Alternative:** Use interactive mode for broad queries:
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/timeline/by-query?query=auth&mode=interactive&limit=5"
|
||||
```
|
||||
Then choose anchor manually.
|
||||
|
||||
---
|
||||
|
||||
## Workflow 6: Search Composition
|
||||
|
||||
**User asks:** "What features did we add to the authentication system recently?"
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. **Combine filters** for precision:
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/observations?query=authentication&type=feature&dateStart=2024-11-01&format=index&limit=10"
|
||||
```
|
||||
|
||||
2. **Review filtered results**
|
||||
|
||||
3. **Get full details** for relevant features:
|
||||
```bash
|
||||
curl -s "http://localhost:37777/api/search/observations?query=authentication&type=feature&format=full&limit=1&offset=2"
|
||||
```
|
||||
|
||||
4. **Present findings:**
|
||||
```markdown
|
||||
Found 10 authentication features added in November:
|
||||
|
||||
🟣 **#1234** Implemented JWT authentication (Nov 9)
|
||||
🟣 **#1236** Added refresh token rotation (Nov 9)
|
||||
🟣 **#1238** Implemented OAuth2 flow (Nov 7)
|
||||
```
|
||||
|
||||
**Why this workflow:**
|
||||
- Multiple filters narrow results before requesting full details
|
||||
- Type + query + dateStart/dateEnd = precise targeting
|
||||
- Progressive disclosure: index first, full details selectively
|
||||
|
||||
---
|
||||
|
||||
## Workflow Selection Guide
|
||||
|
||||
| User Request | Workflow | Operation | Token Cost |
|
||||
|--------------|----------|-----------|------------|
|
||||
| "What did we do last session?" | #1 | recent-context | 1,500-2,500 |
|
||||
| "What bugs did we fix?" | #2 | by-type | 500-3,000 |
|
||||
| "What changes to file.ts?" | #3 | by-file | 500-3,000 |
|
||||
| "What was happening then?" | #4 | search → timeline | 3,500-6,000 |
|
||||
| "Timeline of X work" | #5 | timeline-by-query | 3,000-4,000 |
|
||||
| "Recent features added?" | #6 | observations + filters | 500-3,000 |
|
||||
|
||||
## General Principles
|
||||
|
||||
1. **Start with index format** - Always use `format=index` first
|
||||
2. **Use specialized tools** - by-type, by-file, by-concept when applicable
|
||||
3. **Compose operations** - Combine search + timeline for investigations
|
||||
4. **Filter early** - Use type, dateStart/dateEnd, project to narrow before expanding
|
||||
5. **Progressive disclosure** - Load full details only for relevant items
|
||||
|
||||
## Token Budget Awareness
|
||||
|
||||
**Quick queries** (500-1,500 tokens):
|
||||
- Recent context (limit=3)
|
||||
- Index search (limit=5-10)
|
||||
- Filtered searches
|
||||
|
||||
**Medium queries** (1,500-4,000 tokens):
|
||||
- Recent context (limit=5-10)
|
||||
- Full details (3-5 items)
|
||||
- Timeline (depth 10/10)
|
||||
|
||||
**Deep queries** (4,000-8,000 tokens):
|
||||
- Timeline (depth 20/20)
|
||||
- Full details (10+ items)
|
||||
- Multiple composed operations
|
||||
|
||||
Always start with minimal token investment, expand only when needed.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user