@pcircle/footprint 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/README.md +165 -12
  2. package/SKILL.md +72 -15
  3. package/dist/src/analyzers/content-analyzer.d.ts +20 -0
  4. package/dist/src/analyzers/content-analyzer.d.ts.map +1 -0
  5. package/dist/src/analyzers/content-analyzer.js +169 -0
  6. package/dist/src/analyzers/content-analyzer.js.map +1 -0
  7. package/dist/src/index.d.ts +38 -0
  8. package/dist/src/index.d.ts.map +1 -0
  9. package/dist/src/index.js +243 -0
  10. package/dist/src/index.js.map +1 -0
  11. package/dist/src/lib/crypto/decrypt.d.ts.map +1 -0
  12. package/dist/{lib → src/lib}/crypto/decrypt.js +4 -0
  13. package/dist/src/lib/crypto/decrypt.js.map +1 -0
  14. package/dist/src/lib/crypto/encrypt.d.ts.map +1 -0
  15. package/dist/src/lib/crypto/encrypt.js.map +1 -0
  16. package/dist/{lib → src/lib}/crypto/index.d.ts +1 -1
  17. package/dist/src/lib/crypto/index.d.ts.map +1 -0
  18. package/dist/{lib → src/lib}/crypto/index.js +1 -1
  19. package/dist/src/lib/crypto/index.js.map +1 -0
  20. package/dist/{lib → src/lib}/crypto/key-derivation.d.ts +17 -3
  21. package/dist/src/lib/crypto/key-derivation.d.ts.map +1 -0
  22. package/dist/{lib → src/lib}/crypto/key-derivation.js +44 -3
  23. package/dist/src/lib/crypto/key-derivation.js.map +1 -0
  24. package/dist/src/lib/crypto/types.d.ts.map +1 -0
  25. package/dist/src/lib/crypto/types.js.map +1 -0
  26. package/dist/src/lib/errors/base-error.d.ts +15 -0
  27. package/dist/src/lib/errors/base-error.d.ts.map +1 -0
  28. package/dist/src/lib/errors/base-error.js +34 -0
  29. package/dist/src/lib/errors/base-error.js.map +1 -0
  30. package/dist/src/lib/errors/crypto-error.d.ts +29 -0
  31. package/dist/src/lib/errors/crypto-error.d.ts.map +1 -0
  32. package/dist/src/lib/errors/crypto-error.js +43 -0
  33. package/dist/src/lib/errors/crypto-error.js.map +1 -0
  34. package/dist/src/lib/errors/index.d.ts +26 -0
  35. package/dist/src/lib/errors/index.d.ts.map +1 -0
  36. package/dist/src/lib/errors/index.js +26 -0
  37. package/dist/src/lib/errors/index.js.map +1 -0
  38. package/dist/src/lib/errors/storage-error.d.ts +25 -0
  39. package/dist/src/lib/errors/storage-error.d.ts.map +1 -0
  40. package/dist/src/lib/errors/storage-error.js +38 -0
  41. package/dist/src/lib/errors/storage-error.js.map +1 -0
  42. package/dist/src/lib/errors/validation-error.d.ts +21 -0
  43. package/dist/src/lib/errors/validation-error.d.ts.map +1 -0
  44. package/dist/src/lib/errors/validation-error.js +29 -0
  45. package/dist/src/lib/errors/validation-error.js.map +1 -0
  46. package/dist/{lib → src/lib}/storage/database.d.ts +14 -2
  47. package/dist/src/lib/storage/database.d.ts.map +1 -0
  48. package/dist/{lib → src/lib}/storage/database.js +65 -29
  49. package/dist/src/lib/storage/database.js.map +1 -0
  50. package/dist/src/lib/storage/export.d.ts.map +1 -0
  51. package/dist/{lib → src/lib}/storage/export.js +16 -1
  52. package/dist/src/lib/storage/export.js.map +1 -0
  53. package/dist/{lib → src/lib}/storage/git.d.ts +1 -1
  54. package/dist/src/lib/storage/git.d.ts.map +1 -0
  55. package/dist/{lib → src/lib}/storage/git.js +5 -2
  56. package/dist/src/lib/storage/git.js.map +1 -0
  57. package/dist/{lib → src/lib}/storage/index.d.ts +1 -0
  58. package/dist/src/lib/storage/index.d.ts.map +1 -0
  59. package/dist/{lib → src/lib}/storage/index.js +1 -0
  60. package/dist/src/lib/storage/index.js.map +1 -0
  61. package/dist/src/lib/storage/salt-storage.d.ts +25 -0
  62. package/dist/src/lib/storage/salt-storage.d.ts.map +1 -0
  63. package/dist/src/lib/storage/salt-storage.js +66 -0
  64. package/dist/src/lib/storage/salt-storage.js.map +1 -0
  65. package/dist/src/lib/storage/schema.d.ts.map +1 -0
  66. package/dist/{lib → src/lib}/storage/schema.js +22 -1
  67. package/dist/src/lib/storage/schema.js.map +1 -0
  68. package/dist/src/lib/storage/types.d.ts.map +1 -0
  69. package/dist/src/lib/storage/types.js.map +1 -0
  70. package/dist/src/lib/tool-response.d.ts +84 -0
  71. package/dist/src/lib/tool-response.d.ts.map +1 -0
  72. package/dist/src/lib/tool-response.js +91 -0
  73. package/dist/src/lib/tool-response.js.map +1 -0
  74. package/dist/src/lib/tool-wrapper.d.ts +45 -0
  75. package/dist/src/lib/tool-wrapper.d.ts.map +1 -0
  76. package/dist/src/lib/tool-wrapper.js +73 -0
  77. package/dist/src/lib/tool-wrapper.js.map +1 -0
  78. package/dist/{test-helpers.d.ts → src/test-helpers.d.ts} +4 -4
  79. package/dist/src/test-helpers.d.ts.map +1 -0
  80. package/dist/{test-helpers.js → src/test-helpers.js} +2 -2
  81. package/dist/src/test-helpers.js.map +1 -0
  82. package/dist/src/tools/capture-footprint.d.ts +29 -0
  83. package/dist/src/tools/capture-footprint.d.ts.map +1 -0
  84. package/dist/src/tools/capture-footprint.js +94 -0
  85. package/dist/src/tools/capture-footprint.js.map +1 -0
  86. package/dist/src/tools/delete-footprints.d.ts +22 -0
  87. package/dist/src/tools/delete-footprints.d.ts.map +1 -0
  88. package/dist/src/tools/delete-footprints.js +33 -0
  89. package/dist/src/tools/delete-footprints.js.map +1 -0
  90. package/dist/src/tools/export-footprints.d.ts +33 -0
  91. package/dist/src/tools/export-footprints.d.ts.map +1 -0
  92. package/dist/src/tools/export-footprints.js +50 -0
  93. package/dist/src/tools/export-footprints.js.map +1 -0
  94. package/dist/src/tools/get-footprint.d.ts +51 -0
  95. package/dist/src/tools/get-footprint.d.ts.map +1 -0
  96. package/dist/src/tools/get-footprint.js +66 -0
  97. package/dist/src/tools/get-footprint.js.map +1 -0
  98. package/dist/src/tools/get-tag-stats.d.ts +30 -0
  99. package/dist/src/tools/get-tag-stats.d.ts.map +1 -0
  100. package/dist/src/tools/get-tag-stats.js +33 -0
  101. package/dist/src/tools/get-tag-stats.js.map +1 -0
  102. package/dist/src/tools/index.d.ts +16 -0
  103. package/dist/src/tools/index.d.ts.map +1 -0
  104. package/dist/src/tools/index.js +16 -0
  105. package/dist/src/tools/index.js.map +1 -0
  106. package/dist/src/tools/list-footprints.d.ts +57 -0
  107. package/dist/src/tools/list-footprints.d.ts.map +1 -0
  108. package/dist/src/tools/list-footprints.js +57 -0
  109. package/dist/src/tools/list-footprints.js.map +1 -0
  110. package/dist/src/tools/remove-tag.d.ts +22 -0
  111. package/dist/src/tools/remove-tag.d.ts.map +1 -0
  112. package/dist/src/tools/remove-tag.js +30 -0
  113. package/dist/src/tools/remove-tag.js.map +1 -0
  114. package/dist/src/tools/rename-tag.d.ts +24 -0
  115. package/dist/src/tools/rename-tag.d.ts.map +1 -0
  116. package/dist/src/tools/rename-tag.js +34 -0
  117. package/dist/src/tools/rename-tag.js.map +1 -0
  118. package/dist/src/tools/search-footprints.d.ts +60 -0
  119. package/dist/src/tools/search-footprints.d.ts.map +1 -0
  120. package/dist/src/tools/search-footprints.js +78 -0
  121. package/dist/src/tools/search-footprints.js.map +1 -0
  122. package/dist/src/tools/suggest-capture.d.ts +21 -0
  123. package/dist/src/tools/suggest-capture.d.ts.map +1 -0
  124. package/dist/src/tools/suggest-capture.js +37 -0
  125. package/dist/src/tools/suggest-capture.js.map +1 -0
  126. package/dist/src/tools/verify-footprint.d.ts +104 -0
  127. package/dist/src/tools/verify-footprint.d.ts.map +1 -0
  128. package/dist/src/tools/verify-footprint.js +102 -0
  129. package/dist/src/tools/verify-footprint.js.map +1 -0
  130. package/dist/{types.d.ts → src/types.d.ts} +1 -1
  131. package/dist/src/types.d.ts.map +1 -0
  132. package/dist/{lib/storage → src}/types.js.map +1 -1
  133. package/dist/src/ui/register.d.ts.map +1 -0
  134. package/dist/src/ui/register.js +94 -0
  135. package/dist/src/ui/register.js.map +1 -0
  136. package/dist/tests/error-handling.test.d.ts +2 -0
  137. package/dist/tests/error-handling.test.d.ts.map +1 -0
  138. package/dist/tests/error-handling.test.js +114 -0
  139. package/dist/tests/error-handling.test.js.map +1 -0
  140. package/dist/tests/fixtures.d.ts +87 -0
  141. package/dist/tests/fixtures.d.ts.map +1 -0
  142. package/dist/tests/fixtures.js +130 -0
  143. package/dist/tests/fixtures.js.map +1 -0
  144. package/dist/tests/integration.test.d.ts +2 -0
  145. package/dist/tests/integration.test.d.ts.map +1 -0
  146. package/dist/tests/integration.test.js +115 -0
  147. package/dist/tests/integration.test.js.map +1 -0
  148. package/dist/tests/resources.test.d.ts +2 -0
  149. package/dist/tests/resources.test.d.ts.map +1 -0
  150. package/dist/tests/resources.test.js +73 -0
  151. package/dist/tests/resources.test.js.map +1 -0
  152. package/dist/tests/setup.d.ts +8 -0
  153. package/dist/tests/setup.d.ts.map +1 -0
  154. package/dist/tests/setup.js +8 -0
  155. package/dist/tests/setup.js.map +1 -0
  156. package/dist/tests/tools.test.d.ts +2 -0
  157. package/dist/tests/tools.test.d.ts.map +1 -0
  158. package/dist/tests/tools.test.js +224 -0
  159. package/dist/tests/tools.test.js.map +1 -0
  160. package/dist/ui/dashboard.html +1 -1
  161. package/dist/ui/detail.html +1 -1
  162. package/dist/ui/export.html +1 -1
  163. package/dist/ui-tmp/ui/export.html +1 -1
  164. package/package.json +6 -6
  165. package/dist/index.d.ts +0 -19
  166. package/dist/index.d.ts.map +0 -1
  167. package/dist/index.js +0 -694
  168. package/dist/index.js.map +0 -1
  169. package/dist/lib/crypto/decrypt.d.ts.map +0 -1
  170. package/dist/lib/crypto/decrypt.js.map +0 -1
  171. package/dist/lib/crypto/encrypt.d.ts.map +0 -1
  172. package/dist/lib/crypto/encrypt.js.map +0 -1
  173. package/dist/lib/crypto/index.d.ts.map +0 -1
  174. package/dist/lib/crypto/index.js.map +0 -1
  175. package/dist/lib/crypto/key-derivation.d.ts.map +0 -1
  176. package/dist/lib/crypto/key-derivation.js.map +0 -1
  177. package/dist/lib/crypto/types.d.ts.map +0 -1
  178. package/dist/lib/crypto/types.js.map +0 -1
  179. package/dist/lib/storage/database.d.ts.map +0 -1
  180. package/dist/lib/storage/database.js.map +0 -1
  181. package/dist/lib/storage/export.d.ts.map +0 -1
  182. package/dist/lib/storage/export.js.map +0 -1
  183. package/dist/lib/storage/git.d.ts.map +0 -1
  184. package/dist/lib/storage/git.js.map +0 -1
  185. package/dist/lib/storage/index.d.ts.map +0 -1
  186. package/dist/lib/storage/index.js.map +0 -1
  187. package/dist/lib/storage/schema.d.ts.map +0 -1
  188. package/dist/lib/storage/schema.js.map +0 -1
  189. package/dist/lib/storage/types.d.ts.map +0 -1
  190. package/dist/test-helpers.d.ts.map +0 -1
  191. package/dist/test-helpers.js.map +0 -1
  192. package/dist/types.d.ts.map +0 -1
  193. package/dist/types.js.map +0 -1
  194. package/dist/ui/register.d.ts.map +0 -1
  195. package/dist/ui/register.js +0 -154
  196. package/dist/ui/register.js.map +0 -1
  197. /package/dist/{lib → src/lib}/crypto/decrypt.d.ts +0 -0
  198. /package/dist/{lib → src/lib}/crypto/encrypt.d.ts +0 -0
  199. /package/dist/{lib → src/lib}/crypto/encrypt.js +0 -0
  200. /package/dist/{lib → src/lib}/crypto/types.d.ts +0 -0
  201. /package/dist/{lib → src/lib}/crypto/types.js +0 -0
  202. /package/dist/{lib → src/lib}/storage/export.d.ts +0 -0
  203. /package/dist/{lib → src/lib}/storage/schema.d.ts +0 -0
  204. /package/dist/{lib → src/lib}/storage/types.d.ts +0 -0
  205. /package/dist/{lib → src/lib}/storage/types.js +0 -0
  206. /package/dist/{types.js → src/types.js} +0 -0
  207. /package/dist/{ui → src/ui}/register.d.ts +0 -0
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Model Context Protocol (MCP) server that automatically captures and encrypts LLM conversations as legal evidence.
7
7
 
8
- ## Why EvidenceMCP?
8
+ ## Why Footprint?
9
9
 
10
10
  - **Prove IP Ownership** - Timestamped evidence of LLM-assisted work
11
11
  - **Zero Effort** - Automatic capture via MCP protocol
@@ -21,12 +21,14 @@ npm install -g @pcircle/footprint
21
21
  ## Quick Start
22
22
 
23
23
  1. **Set environment variables:**
24
+
24
25
  ```bash
25
- export EVIDENCEMCP_DB_PATH="./evidence.db"
26
- export EVIDENCEMCP_PASSWORD="your-secure-password"
26
+ export FOOTPRINT_DB_PATH="./evidence.db"
27
+ export FOOTPRINT_PASSWORD="your-secure-password"
27
28
  ```
28
29
 
29
30
  2. **Configure Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
31
+
30
32
  ```json
31
33
  {
32
34
  "mcpServers": {
@@ -34,8 +36,8 @@ export EVIDENCEMCP_PASSWORD="your-secure-password"
34
36
  "command": "npx",
35
37
  "args": ["footprint"],
36
38
  "env": {
37
- "EVIDENCEMCP_DB_PATH": "/path/to/evidence.db",
38
- "EVIDENCEMCP_PASSWORD": "your-password"
39
+ "FOOTPRINT_DB_PATH": "/path/to/evidence.db",
40
+ "FOOTPRINT_PASSWORD": "your-password"
39
41
  }
40
42
  }
41
43
  }
@@ -50,20 +52,171 @@ export EVIDENCEMCP_PASSWORD="your-secure-password"
50
52
  - 🕒 Git commit timestamps
51
53
  - 📦 Tamper-proof ZIP exports
52
54
  - 🔍 Search and retrieve evidence
55
+ - 🤖 AI-powered capture suggestions
56
+ - ✅ Integrity verification
57
+ - 🏷️ Tag management
58
+ - 📊 Interactive UI dashboard
59
+
60
+ ## Architecture
61
+
62
+ The Footprint MCP server follows a modular, layered architecture:
63
+
64
+ ```
65
+ src/
66
+ ├── index.ts # Main MCP server
67
+ ├── tools/ # MCP tool handlers (11 tools)
68
+ │ ├── capture-footprint.ts
69
+ │ ├── list-footprints.ts
70
+ │ ├── get-footprint.ts
71
+ │ ├── export-footprints.ts
72
+ │ ├── search-footprints.ts
73
+ │ ├── verify-footprint.ts
74
+ │ ├── suggest-capture.ts
75
+ │ ├── delete-footprints.ts
76
+ │ ├── rename-tag.ts
77
+ │ ├── remove-tag.ts
78
+ │ └── get-tag-stats.ts
79
+ ├── analyzers/ # Content analysis modules
80
+ │ └── content-analyzer.ts
81
+ ├── lib/
82
+ │ ├── crypto/ # Encryption & key derivation
83
+ │ ├── storage/ # Database & export
84
+ │ ├── tool-wrapper.ts # Error handling wrapper
85
+ │ └── tool-response.ts # Response formatters
86
+ └── ui/ # Interactive dashboards
87
+ ```
88
+
89
+ ### Design Principles
90
+
91
+ - **Modular**: Each tool is self-contained with schema, metadata, and handler
92
+ - **Type-Safe**: Full TypeScript with Zod schema validation
93
+ - **Testable**: Dependency injection enables isolated testing
94
+ - **Secure**: Encrypted storage with integrity verification
95
+ - **Maintainable**: Clear separation of concerns across layers
53
96
 
54
97
  ## MCP Tools
55
98
 
56
- ### capture-footprint
57
- Captures and encrypts an LLM conversation.
99
+ ### Core Tools
100
+
101
+ #### capture-footprint
102
+
103
+ Captures and encrypts an LLM conversation as evidence.
104
+
105
+ **Parameters:**
106
+
107
+ - `conversationId` - Unique identifier for the conversation
108
+ - `llmProvider` - LLM provider name (e.g., "Claude Sonnet 4.5")
109
+ - `content` - Full conversation content
110
+ - `messageCount` - Number of messages in conversation
111
+ - `tags` (optional) - Comma-separated tags
112
+
113
+ #### list-footprints
114
+
115
+ Lists all captured evidence with pagination support.
58
116
 
59
- ### list-footprints
60
- Lists all captured evidence with pagination.
117
+ **Parameters:**
118
+
119
+ - `limit` (optional) - Maximum results per page
120
+ - `offset` (optional) - Pagination offset
121
+
122
+ #### get-footprint
61
123
 
62
- ### get-footprint
63
124
  Retrieves and decrypts specific evidence by ID.
64
125
 
65
- ### export-footprints
66
- Exports evidence to encrypted ZIP archive.
126
+ **Parameters:**
127
+
128
+ - `id` - Evidence ID
129
+
130
+ #### export-footprints
131
+
132
+ Exports evidence to tamper-proof encrypted ZIP archive.
133
+
134
+ **Parameters:**
135
+
136
+ - `evidenceIds` - Array of evidence IDs to export
137
+ - `includeGitInfo` (optional) - Include git metadata
138
+
139
+ ### Search & Discovery
140
+
141
+ #### search-footprints
142
+
143
+ Search and filter evidence by query, tags, or date range.
144
+
145
+ **Parameters:**
146
+
147
+ - `query` (optional) - Search text (matches conversationId, tags)
148
+ - `tags` (optional) - Array of tags to filter by
149
+ - `dateFrom` (optional) - Start date (ISO format)
150
+ - `dateTo` (optional) - End date (ISO format)
151
+ - `limit` (optional) - Maximum results
152
+ - `offset` (optional) - Pagination offset
153
+
154
+ #### suggest-capture
155
+
156
+ Analyze conversation content and suggest whether to capture it as evidence.
157
+
158
+ **Parameters:**
159
+
160
+ - `summary` - Conversation summary or key content to analyze
161
+
162
+ **Returns:**
163
+
164
+ - `shouldCapture` - Whether to capture (based on keyword analysis)
165
+ - `reason` - Human-readable explanation
166
+ - `suggestedTags` - Recommended tags
167
+ - `suggestedConversationId` - Recommended ID
168
+ - `confidence` - Confidence score (0-1)
169
+
170
+ ### Verification
171
+
172
+ #### verify-footprint
173
+
174
+ Verify the integrity and authenticity of captured evidence.
175
+
176
+ **Parameters:**
177
+
178
+ - `id` - Evidence ID to verify
179
+
180
+ **Returns:**
181
+
182
+ - `verified` - Overall verification status
183
+ - `checks` - Detailed checks (content integrity, git timestamp, encryption)
184
+ - `legalReadiness` - Whether evidence meets legal standards
185
+
186
+ ### Management
187
+
188
+ #### delete-footprints
189
+
190
+ Delete evidence records permanently.
191
+
192
+ **Parameters:**
193
+
194
+ - `evidenceIds` - Array of evidence IDs to delete
195
+
196
+ #### rename-tag
197
+
198
+ Rename a tag across all evidence.
199
+
200
+ **Parameters:**
201
+
202
+ - `oldTag` - Current tag name
203
+ - `newTag` - New tag name
204
+
205
+ #### remove-tag
206
+
207
+ Remove a tag from all evidence.
208
+
209
+ **Parameters:**
210
+
211
+ - `tag` - Tag name to remove
212
+
213
+ #### get-tag-stats
214
+
215
+ Get statistics about tag usage.
216
+
217
+ **Returns:**
218
+
219
+ - Tag names and their usage counts
67
220
 
68
221
  ## Security
69
222
 
package/SKILL.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Footprint Agent Skill
2
2
 
3
- Capture and encrypt LLM conversations as tamper-proof legal evidence with Git timestamps.
3
+ > MCP server for capturing and encrypting AI conversations as verifiable records with Git timestamps.
4
+
5
+ **Package:** `@pcircle/footprint` (v1.1.1)
6
+ **Protocol:** Model Context Protocol (MCP)
7
+ **License:** MIT
4
8
 
5
9
  ## Decision Tree: Should I Capture This?
6
10
 
@@ -149,7 +153,7 @@ Human: We need to decide on the OAuth implementation...
149
153
  Assistant: I recommend using PKCE flow...
150
154
  ```
151
155
 
152
- ### 4. `search-evidence`
156
+ ### 4. `search-footprints`
153
157
  Find evidence by content or tags.
154
158
 
155
159
  **Input Parameters:**
@@ -161,7 +165,7 @@ Find evidence by content or tags.
161
165
  }
162
166
  ```
163
167
 
164
- ### 5. `export-evidence`
168
+ ### 5. `export-footprints`
165
169
  Export evidence as encrypted archive.
166
170
 
167
171
  **Input Parameters:**
@@ -183,6 +187,39 @@ Export evidence as encrypted archive.
183
187
  }
184
188
  ```
185
189
 
190
+ ### 6. `verify-footprint`
191
+ Verify evidence integrity (checksum + Git timestamp).
192
+
193
+ **Input Parameters:**
194
+ ```json
195
+ {
196
+ "id": "550e8400-e29b-41d4-a716-446655440000"
197
+ }
198
+ ```
199
+
200
+ **Expected Output (text):**
201
+ ```
202
+ 🔐 Evidence Verification Report
203
+ - ID: 550e8400-e29b-41d4-a716-446655440000
204
+ - Content Hash: ✅ Valid (SHA-256 matches)
205
+ - Git Timestamp: ✅ Verified (2026-01-28T14:30:45Z)
206
+ - Encryption: ✅ Decryption successful
207
+ - Status: AUTHENTIC - No tampering detected
208
+ ```
209
+
210
+ **Expected Output (structuredContent):**
211
+ ```json
212
+ {
213
+ "type": "verification_result",
214
+ "id": "550e8400-e29b-41d4-a716-446655440000",
215
+ "contentHashValid": true,
216
+ "gitTimestampVerified": true,
217
+ "decryptionSuccessful": true,
218
+ "status": "authentic",
219
+ "timestamp": "2026-01-28T14:30:45Z"
220
+ }
221
+ ```
222
+
186
223
  ## Best Practices
187
224
 
188
225
  ### Naming conversationId
@@ -216,9 +253,10 @@ Export evidence as encrypted archive.
216
253
  ### When to Use Each Tool
217
254
  - **capture-footprint**: Primary tool for saving conversations
218
255
  - **list-footprints**: Browse/overview existing evidence
219
- - **search-evidence**: Find specific content across evidence
256
+ - **search-footprints**: Find specific content across evidence
220
257
  - **get-footprint**: Retrieve full content of specific evidence
221
- - **export-evidence**: Legal/audit export needs
258
+ - **export-footprints**: Legal/audit export needs
259
+ - **verify-footprint**: Verify evidence integrity and checksums
222
260
 
223
261
  ## Token-Efficient Agent Responses
224
262
 
@@ -249,10 +287,10 @@ Tags: {tags}
249
287
 
250
288
  | Error | Likely Cause | Recovery Action |
251
289
  |-------|--------------|-----------------|
252
- | "Password required" | EVIDENCEMCP_PASSWORD not set | 1. Check env config<br>2. Restart MCP server<br>3. Verify password in env |
290
+ | "Password required" | FOOTPRINT_PASSWORD not set | 1. Check env config<br>2. Restart MCP server<br>3. Verify password in env |
253
291
  | "Evidence not found" | Invalid/wrong ID | 1. Use `list-footprints` to find correct ID<br>2. Search by conversationId<br>3. Check if user meant different evidence |
254
292
  | "Decryption failed" | Password changed/wrong | 1. Verify current password matches<br>2. Check if evidence pre-dates password change<br>3. Try with backup password if available |
255
- | "Database error" | DB path/permissions issues | 1. Check EVIDENCEMCP_DB_PATH exists<br>2. Verify file permissions<br>3. Create directory if missing |
293
+ | "Database error" | DB path/permissions issues | 1. Check FOOTPRINT_DB_PATH exists<br>2. Verify file permissions<br>3. Create directory if missing |
256
294
  | "Git repository error" | Git not initialized | 1. Initialize git in evidence directory<br>2. Set git user.name/user.email<br>3. Make initial commit |
257
295
  | "Capture timeout" | Large conversation size | 1. Split into smaller chunks<br>2. Reduce messageCount<br>3. Compress content before capture |
258
296
 
@@ -309,11 +347,12 @@ Agent:
309
347
 
310
348
  ## Security & Verification
311
349
 
312
- - **Password**: Set via `EVIDENCEMCP_PASSWORD` env var (never ask user in chat)
313
- - **Encryption**: AES-256-GCM with Argon2id key derivation
350
+ - **Password**: Set via `FOOTPRINT_PASSWORD` env var (never ask user in chat)
351
+ - **Encryption**: XChaCha20-Poly1305 (256-bit) with Argon2id key derivation
314
352
  - **Git Timestamps**: Cryptographic proof of creation time
315
353
  - **SHA-256 Checksums**: Detect any content tampering
316
354
  - **Evidence Chain**: Each capture creates immutable Git commit
355
+ - **Storage**: Local SQLite with encrypted BLOBs (no cloud, no tracking)
317
356
 
318
357
  **For legal proceedings:**
319
358
  1. Export evidence with `export-evidence`
@@ -327,23 +366,41 @@ Agent:
327
366
  This section is for humans setting up the agent environment:
328
367
 
329
368
  ```bash
330
- # Install MCP server
331
- npm install -g @pcircle/footprint-server
369
+ # Install MCP server globally
370
+ npm install -g @pcircle/footprint
332
371
 
333
- # Claude Desktop config (~/.config/claude/claude_desktop_config.json)
372
+ # Or run directly with npx
373
+ npx @pcircle/footprint
374
+ ```
375
+
376
+ **Claude Desktop config location:**
377
+
378
+ | Platform | Config Path |
379
+ |----------|-------------|
380
+ | macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
381
+ | Linux | `~/.config/Claude/claude_desktop_config.json` |
382
+ | Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
383
+
384
+ **Config content:**
385
+ ```json
334
386
  {
335
387
  "mcpServers": {
336
388
  "footprint": {
337
- "command": "footprint",
389
+ "command": "npx",
390
+ "args": ["@pcircle/footprint"],
338
391
  "env": {
339
- "EVIDENCEMCP_DB_PATH": "~/evidence/evidence.db",
340
- "EVIDENCEMCP_PASSWORD": "your-secure-password-here"
392
+ "FOOTPRINT_DB_PATH": "/path/to/evidence.db",
393
+ "FOOTPRINT_PASSWORD": "your-secure-password-here"
341
394
  }
342
395
  }
343
396
  }
344
397
  }
345
398
  ```
346
399
 
400
+ **Environment Variables:**
401
+ - `FOOTPRINT_PASSWORD` (required): Encryption passphrase
402
+ - `FOOTPRINT_DB_PATH` (optional): Path to SQLite database (default: `./evidence.db` in current directory)
403
+
347
404
  ## Performance Notes
348
405
 
349
406
  - **Capture time**: ~1-3 seconds per conversation
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Content analyzer for determining if conversation content should be captured as evidence
3
+ * Analyzes keywords, calculates confidence, and generates appropriate metadata
4
+ */
5
+ export interface AnalysisResult {
6
+ shouldCapture: boolean;
7
+ reason: string;
8
+ suggestedTags: string[];
9
+ suggestedConversationId: string;
10
+ confidence: number;
11
+ [key: string]: unknown;
12
+ }
13
+ /**
14
+ * Analyze conversation content and determine if it should be captured as evidence
15
+ *
16
+ * @param summary - Conversation summary or key content to analyze
17
+ * @returns Analysis result with capture recommendation and metadata
18
+ */
19
+ export declare function analyzeContent(summary: string): AnalysisResult;
20
+ //# sourceMappingURL=content-analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-analyzer.d.ts","sourceRoot":"","sources":["../../../src/analyzers/content-analyzer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,uBAAuB,EAAE,MAAM,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAkLD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,CAuB9D"}
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Content analyzer for determining if conversation content should be captured as evidence
3
+ * Analyzes keywords, calculates confidence, and generates appropriate metadata
4
+ */
5
+ /**
6
+ * Keyword categories for detecting important content
7
+ */
8
+ const KEYWORD_CATEGORIES = {
9
+ ip: [
10
+ "patent",
11
+ "intellectual property",
12
+ "invention",
13
+ "algorithm",
14
+ "proprietary",
15
+ "innovation",
16
+ "design",
17
+ ],
18
+ legal: [
19
+ "contract",
20
+ "agreement",
21
+ "legal",
22
+ "copyright",
23
+ "license",
24
+ "terms",
25
+ "clause",
26
+ "liability",
27
+ ],
28
+ business: [
29
+ "decision",
30
+ "milestone",
31
+ "deliverable",
32
+ "approval",
33
+ "strategy",
34
+ "roadmap",
35
+ "budget",
36
+ "timeline",
37
+ ],
38
+ research: [
39
+ "hypothesis",
40
+ "findings",
41
+ "proof",
42
+ "research",
43
+ "study",
44
+ "experiment",
45
+ "analysis",
46
+ "data",
47
+ ],
48
+ compliance: [
49
+ "audit",
50
+ "compliance",
51
+ "evidence",
52
+ "documentation",
53
+ "regulation",
54
+ "policy",
55
+ "requirement",
56
+ ],
57
+ };
58
+ /**
59
+ * Match whole words only to avoid false positives
60
+ * (e.g., "logarithm" should not match "algorithm")
61
+ */
62
+ function matchesWord(text, word) {
63
+ const regex = new RegExp(`\\b${word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i");
64
+ return regex.test(text);
65
+ }
66
+ /**
67
+ * Detect matching keyword categories in the text
68
+ */
69
+ function findKeywordMatches(text) {
70
+ const matches = [];
71
+ for (const [category, keywords] of Object.entries(KEYWORD_CATEGORIES)) {
72
+ const foundKeywords = keywords.filter((keyword) => matchesWord(text, keyword));
73
+ if (foundKeywords.length > 0) {
74
+ const weight = foundKeywords.length / keywords.length;
75
+ matches.push({ category, keywords: foundKeywords, weight });
76
+ }
77
+ }
78
+ return matches;
79
+ }
80
+ /**
81
+ * Calculate confidence score based on keyword matches and text characteristics
82
+ *
83
+ * @param matches - Keyword matches found in text
84
+ * @param wordCount - Total word count in text
85
+ * @returns Confidence score between 0 and 1
86
+ */
87
+ function calculateConfidence(matches, wordCount) {
88
+ if (matches.length === 0) {
89
+ // No keywords found = low importance confidence
90
+ // Longer text without keywords = slightly higher (might have missed something)
91
+ const lengthFactor = Math.min(wordCount / 200, 0.3); // Max 0.3 for very long text
92
+ return 0.1 + lengthFactor; // Range: 0.1 to 0.4
93
+ }
94
+ // More keywords and categories = higher importance confidence
95
+ const totalKeywords = matches.reduce((sum, match) => sum + match.keywords.length, 0);
96
+ const keywordDensity = totalKeywords / Math.max(wordCount, 1);
97
+ const categoryBonus = matches.length * 0.15;
98
+ const keywordBonus = Math.min(totalKeywords * 0.1, 0.4);
99
+ return Math.min(0.95, 0.3 + categoryBonus + keywordBonus + keywordDensity);
100
+ }
101
+ /**
102
+ * Generate human-readable reason for capture recommendation
103
+ */
104
+ function generateReason(matches) {
105
+ if (matches.length === 0) {
106
+ return "Appears to be casual conversation with no critical business, legal, or IP content";
107
+ }
108
+ const categories = matches.map((m) => m.category === "ip" ? "IP" : m.category);
109
+ if (categories.length === 1) {
110
+ return `Contains ${categories[0]} keywords: ${matches[0].keywords.join(", ")}`;
111
+ }
112
+ return `Contains multiple important categories: ${categories.join(", ")}`;
113
+ }
114
+ /**
115
+ * Generate suggested tags from keyword matches
116
+ */
117
+ function generateTags(matches) {
118
+ if (matches.length === 0) {
119
+ return [];
120
+ }
121
+ return [
122
+ ...new Set(matches.flatMap((m) => [m.category, ...m.keywords.slice(0, 2)])),
123
+ ];
124
+ }
125
+ /**
126
+ * Generate conversation ID based on matches and current date
127
+ */
128
+ function generateConversationId(matches) {
129
+ const currentDate = new Date().toISOString().slice(0, 10);
130
+ if (matches.length === 0) {
131
+ return `conversation-${currentDate}`;
132
+ }
133
+ // Extract key terms for ID generation
134
+ const primaryKeywords = matches[0].keywords.slice(0, 2);
135
+ const cleanKeywords = primaryKeywords
136
+ .map((k) => k.replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, ""))
137
+ .filter((k) => k.length > 0);
138
+ if (cleanKeywords.length > 0) {
139
+ return `${cleanKeywords.join("-")}-${currentDate}`;
140
+ }
141
+ return `${matches[0].category}-discussion-${currentDate}`;
142
+ }
143
+ /**
144
+ * Analyze conversation content and determine if it should be captured as evidence
145
+ *
146
+ * @param summary - Conversation summary or key content to analyze
147
+ * @returns Analysis result with capture recommendation and metadata
148
+ */
149
+ export function analyzeContent(summary) {
150
+ const normalizedText = summary.toLowerCase();
151
+ const wordCount = normalizedText.split(/\s+/).length;
152
+ // Find keyword matches
153
+ const matches = findKeywordMatches(normalizedText);
154
+ const shouldCapture = matches.length > 0;
155
+ // Calculate confidence
156
+ const confidence = calculateConfidence(matches, wordCount);
157
+ // Generate metadata
158
+ const reason = generateReason(matches);
159
+ const suggestedTags = generateTags(matches);
160
+ const suggestedConversationId = generateConversationId(matches);
161
+ return {
162
+ shouldCapture,
163
+ reason,
164
+ suggestedTags,
165
+ suggestedConversationId,
166
+ confidence: Math.round(confidence * 100) / 100,
167
+ };
168
+ }
169
+ //# sourceMappingURL=content-analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-analyzer.js","sourceRoot":"","sources":["../../../src/analyzers/content-analyzer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import type { ServerConfig } from "./types.js";
3
+ /**
4
+ * Footprint Server - Captures LLM conversations as encrypted evidence
5
+ * with Git timestamps and export capabilities.
6
+ */
7
+ export declare class FootprintServer {
8
+ private server;
9
+ private config;
10
+ private db;
11
+ private derivedKey;
12
+ private keyDerivationPromise;
13
+ constructor(config: ServerConfig);
14
+ /**
15
+ * Get or derive encryption key using stored salt (thread-safe)
16
+ * Caches key in memory for performance, with cleanup on shutdown
17
+ * Handles concurrent calls by ensuring only one derivation happens at a time
18
+ *
19
+ * @returns 32-byte encryption key
20
+ * @throws Error if salt storage fails
21
+ */
22
+ private getDerivedKey;
23
+ /**
24
+ * Securely clear derived key from memory
25
+ * Should be called on server shutdown
26
+ */
27
+ private clearDerivedKey;
28
+ private registerTools;
29
+ private registerResources;
30
+ start(): Promise<void>;
31
+ /**
32
+ * Cleanup server resources
33
+ * Clears derived key from memory and closes database
34
+ */
35
+ close(): void;
36
+ }
37
+ export { FootprintTestHelpers } from "./test-helpers.js";
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAuC/C;;;GAGG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,oBAAoB,CAAoC;gBAEpD,MAAM,EAAE,YAAY;IAuBhC;;;;;;;OAOG;YACW,aAAa;IAsC3B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,aAAa;IA2HrB,OAAO,CAAC,iBAAiB;IAqCnB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B;;;OAGG;IACH,KAAK,IAAI,IAAI;CAId;AA6DD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC"}