spooling 0.1.7__tar.gz → 0.2.0__tar.gz

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 (70) hide show
  1. spooling-0.2.0/PKG-INFO +635 -0
  2. {spooling-0.1.7 → spooling-0.2.0}/pyproject.toml +4 -3
  3. {spooling-0.1.7 → spooling-0.2.0}/spooling/cli.py +124 -12
  4. {spooling-0.1.7 → spooling-0.2.0}/spooling/config.py +20 -13
  5. spooling-0.2.0/spooling/db.py +164 -0
  6. {spooling-0.1.7 → spooling-0.2.0}/spooling/ingest.py +32 -14
  7. {spooling-0.1.7 → spooling-0.2.0}/spooling/mcp_server.py +51 -2
  8. spooling-0.2.0/spooling/schema.py +310 -0
  9. spooling-0.2.0/spooling/search.py +86 -0
  10. {spooling-0.1.7 → spooling-0.2.0}/spooling/server.py +11 -7
  11. {spooling-0.1.7 → spooling-0.2.0}/spooling/stats.py +70 -59
  12. {spooling-0.1.7 → spooling-0.2.0}/spooling/tunnel.py +10 -23
  13. spooling-0.2.0/spooling/tunnel_auth.py +89 -0
  14. spooling-0.2.0/spooling.egg-info/PKG-INFO +635 -0
  15. {spooling-0.1.7 → spooling-0.2.0}/spooling.egg-info/SOURCES.txt +5 -1
  16. {spooling-0.1.7 → spooling-0.2.0}/spooling.egg-info/requires.txt +2 -2
  17. spooling-0.2.0/tests/test_mcp_auth_middleware.py +119 -0
  18. spooling-0.2.0/tests/test_tunnel_auth.py +177 -0
  19. spooling-0.1.7/PKG-INFO +0 -34
  20. spooling-0.1.7/spooling/db.py +0 -21
  21. spooling-0.1.7/spooling/search.py +0 -68
  22. spooling-0.1.7/spooling.egg-info/PKG-INFO +0 -34
  23. {spooling-0.1.7 → spooling-0.2.0}/LICENSE +0 -0
  24. {spooling-0.1.7 → spooling-0.2.0}/README.md +0 -0
  25. {spooling-0.1.7 → spooling-0.2.0}/setup.cfg +0 -0
  26. {spooling-0.1.7 → spooling-0.2.0}/spooling/__init__.py +0 -0
  27. {spooling-0.1.7 → spooling-0.2.0}/spooling/agent.py +0 -0
  28. {spooling-0.1.7 → spooling-0.2.0}/spooling/classifiers.py +0 -0
  29. {spooling-0.1.7 → spooling-0.2.0}/spooling/cloud.py +0 -0
  30. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/__init__.py +0 -0
  31. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/base.py +0 -0
  32. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/bigquery.py +0 -0
  33. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/clickhouse.py +0 -0
  34. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/factory.py +0 -0
  35. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/mongodb.py +0 -0
  36. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/mysql.py +0 -0
  37. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/postgresql.py +0 -0
  38. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/rest/__init__.py +0 -0
  39. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/rest/base.py +0 -0
  40. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/rest/shopify_connectors.py +0 -0
  41. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/snowflake.py +0 -0
  42. {spooling-0.1.7 → spooling-0.2.0}/spooling/connectors/types.py +0 -0
  43. {spooling-0.1.7 → spooling-0.2.0}/spooling/embeddings.py +0 -0
  44. {spooling-0.1.7 → spooling-0.2.0}/spooling/evals.py +0 -0
  45. {spooling-0.1.7 → spooling-0.2.0}/spooling/experiments.py +0 -0
  46. {spooling-0.1.7 → spooling-0.2.0}/spooling/parser.py +0 -0
  47. {spooling-0.1.7 → spooling-0.2.0}/spooling/pricing.py +0 -0
  48. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/__init__.py +0 -0
  49. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/antigravity.py +0 -0
  50. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/base.py +0 -0
  51. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/codex.py +0 -0
  52. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/copilot.py +0 -0
  53. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/cortex_code.py +0 -0
  54. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/cursor.py +0 -0
  55. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/gemini.py +0 -0
  56. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/github.py +0 -0
  57. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/gitlab.py +0 -0
  58. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/kiro.py +0 -0
  59. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/opencode.py +0 -0
  60. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/session_file.py +0 -0
  61. {spooling-0.1.7 → spooling-0.2.0}/spooling/providers/windsurf.py +0 -0
  62. {spooling-0.1.7 → spooling-0.2.0}/spooling/redact.py +0 -0
  63. {spooling-0.1.7 → spooling-0.2.0}/spooling/remote_otel.py +0 -0
  64. {spooling-0.1.7 → spooling-0.2.0}/spooling/sdk.py +0 -0
  65. {spooling-0.1.7 → spooling-0.2.0}/spooling/subscription_pricing.py +0 -0
  66. {spooling-0.1.7 → spooling-0.2.0}/spooling/tracing.py +0 -0
  67. {spooling-0.1.7 → spooling-0.2.0}/spooling/watcher.py +0 -0
  68. {spooling-0.1.7 → spooling-0.2.0}/spooling.egg-info/dependency_links.txt +0 -0
  69. {spooling-0.1.7 → spooling-0.2.0}/spooling.egg-info/entry_points.txt +0 -0
  70. {spooling-0.1.7 → spooling-0.2.0}/spooling.egg-info/top_level.txt +0 -0
@@ -0,0 +1,635 @@
1
+ Metadata-Version: 2.4
2
+ Name: spooling
3
+ Version: 0.2.0
4
+ Summary: Local session tracker and semantic search for AI coding assistants
5
+ Author: Parsed Analytics, Inc.
6
+ License: MIT
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.11
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: click>=8.1
14
+ Requires-Dist: sentence-transformers>=3.0
15
+ Requires-Dist: numpy>=1.24
16
+ Requires-Dist: fastapi>=0.111
17
+ Requires-Dist: uvicorn[standard]>=0.30
18
+ Requires-Dist: jinja2>=3.1
19
+ Requires-Dist: watchdog>=4.0
20
+ Requires-Dist: rich>=13.0
21
+ Requires-Dist: httpx>=0.27
22
+ Requires-Dist: anthropic>=0.40
23
+ Requires-Dist: strands-agents[ollama]>=1.35
24
+ Requires-Dist: strands-agents-evals>=0.1
25
+ Requires-Dist: mcp<2,>=1.27
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0; extra == "dev"
28
+ Requires-Dist: pytest-mock>=3.14; extra == "dev"
29
+ Provides-Extra: connectors
30
+ Requires-Dist: snowflake-connector-python>=3.0; extra == "connectors"
31
+ Requires-Dist: google-cloud-bigquery>=3.0; extra == "connectors"
32
+ Requires-Dist: mysql-connector-python>=8.0; extra == "connectors"
33
+ Requires-Dist: clickhouse-connect>=0.5; extra == "connectors"
34
+ Requires-Dist: motor>=3.0; extra == "connectors"
35
+ Dynamic: license-file
36
+
37
+ # Spooling
38
+
39
+ Local session tracker and semantic search for AI coding assistants.
40
+
41
+ Track your AI coding sessions across **OpenAI Codex CLI**, **GitHub Copilot**, **Cursor**, **Windsurf**, **Kiro**, **Google Antigravity**, and **opencode**, all in one place. Get usage stats, cost estimates, per-provider breakdowns, semantic search via pgvector, and a built-in AI chat agent to explore your history.
42
+
43
+ **Website:** [spooling.ai](https://spooling.ai)
44
+
45
+ ---
46
+
47
+ ## Prerequisites
48
+
49
+ - **Python 3.11+**
50
+ - **Node.js 18+**
51
+ - **Docker** (for PostgreSQL + pgvector)
52
+ - **pipx** or **uv** (optional, alternative install methods)
53
+ - **Ollama** (optional, for free local AI chat) or an **Anthropic API key**
54
+
55
+ ---
56
+
57
+ ## How it works
58
+
59
+ **Four commands. Zero cloud.**
60
+
61
+ ### 01 &nbsp; Clone & start the database
62
+
63
+ ```bash
64
+ git clone https://github.com/sashimiboi/spooling && cd spooling
65
+ docker compose up -d # postgres + pgvector :5434
66
+ ```
67
+
68
+ ### 02 &nbsp; Install backend + UI
69
+
70
+ Choose one:
71
+
72
+ ```bash
73
+ # pip (recommended)
74
+ python3 -m venv .venv && source .venv/bin/activate
75
+ pip install -e .
76
+
77
+ # pipx
78
+ pipx install .
79
+
80
+ # uv
81
+ uv sync
82
+ ```
83
+
84
+ Then install the UI:
85
+
86
+ ```bash
87
+ cd ui && npm install && cd ..
88
+ ```
89
+
90
+ ### 03 &nbsp; Detect providers & sync
91
+
92
+ ```bash
93
+ spooling init # scan for available providers
94
+ spooling sync # embed every session into pgvector
95
+ ```
96
+
97
+ ### 04 &nbsp; Search & explore
98
+
99
+ ```bash
100
+ spooling ui # API :3002 · MCP :3004 · GUI :3003
101
+ spooling search "that redis race condition"
102
+ ```
103
+
104
+ Open **http://localhost:3003** and you're in.
105
+
106
+ ---
107
+
108
+ ## Connect Spooling to your AI coding agent
109
+
110
+ `spooling ui` automatically exposes an MCP server at `http://127.0.0.1:3004/mcp` (HTTP streamable transport). Any MCP-speaking agent can connect to it and pull context from your local KB mid-conversation. The agent gets tools like `spooling_search`, `spooling_recent_sessions`, `spooling_get_session`, `spooling_workspace_stats`, and `spooling_top_projects`.
111
+
112
+ ### Cursor / Windsurf / Codex / Antigravity
113
+
114
+ Edit your client's MCP config (usually `~/.cursor/mcp.json`, `~/.codeium/windsurf/mcp_config.json`, or the equivalent) and add:
115
+
116
+ ```json
117
+ {
118
+ "mcpServers": {
119
+ "spooling": {
120
+ "type": "http",
121
+ "url": "http://127.0.0.1:3004/mcp"
122
+ }
123
+ }
124
+ }
125
+ ```
126
+
127
+ Restart the client. The `spooling` server and its tools should appear in the MCP panel.
128
+
129
+ ### Generic JSON-RPC smoke test
130
+
131
+ ```bash
132
+ curl -s http://127.0.0.1:3004/mcp \
133
+ -H "Content-Type: application/json" \
134
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq
135
+ ```
136
+
137
+ Should return the five `spool_*` tools. If you get "connection refused", `spooling ui` is not running (or its ports got squatted, run `lsof -ti :3004 | xargs kill -9` and retry).
138
+
139
+ ---
140
+
141
+ ## CLI Usage
142
+
143
+ All CLI commands require the venv to be active and the database running.
144
+
145
+ ```bash
146
+ source .venv/bin/activate
147
+ ```
148
+
149
+ ### `spooling init`
150
+
151
+ Check database connection and show which AI coding tool providers are detected on your system. This scans default paths for Codex CLI, GitHub Copilot, Cursor, and Windsurf session data.
152
+
153
+ ```bash
154
+ spooling init
155
+ ```
156
+
157
+ ### `spooling sync`
158
+
159
+ Parse and ingest sessions from all connected providers into the database. Chunks and embeds message content into pgvector for semantic search.
160
+
161
+ ```bash
162
+ spooling sync # Full sync with embeddings
163
+ spooling sync --no-embed # Skip embeddings (faster initial sync)
164
+ spooling sync -p cursor # Sync only Cursor sessions
165
+ spooling sync -p codex # Sync only Codex CLI sessions
166
+ ```
167
+
168
+ ### `spooling stats`
169
+
170
+ Show usage statistics - sessions, messages, tool calls, tokens, costs, broken down by project and day.
171
+
172
+ ```bash
173
+ spooling stats # Overview + last 7 days
174
+ spooling stats --week # Weekly breakdown
175
+ spooling stats --days 30 # Last 30 days
176
+ ```
177
+
178
+ ### `spooling search <query>`
179
+
180
+ Semantic search across all your session history using natural language.
181
+
182
+ ```bash
183
+ spooling search "snowflake connector"
184
+ spooling search "authentication bug" -n 5
185
+ spooling search "database migration" -p ~/myproject
186
+ ```
187
+
188
+ Options:
189
+ - `-n, --limit` - Number of results (default: 10)
190
+ - `-p, --project` - Filter by project name
191
+
192
+ ### `spooling watch`
193
+
194
+ Watch all connected provider directories for new session data and auto-sync in real time.
195
+
196
+ ```bash
197
+ spooling watch
198
+ ```
199
+
200
+ ### `spooling serve`
201
+
202
+ Start the API server only (for when you want to run the GUI separately).
203
+
204
+ ```bash
205
+ spooling serve # Default: http://127.0.0.1:3002
206
+ spooling serve --port 8080 # Custom port
207
+ spooling serve --host 0.0.0.0 # Bind to all interfaces
208
+ ```
209
+
210
+ ### `spooling ui`
211
+
212
+ Start the API server, the MCP HTTP server, and the Next.js UI together.
213
+
214
+ ```bash
215
+ spooling ui
216
+ ```
217
+
218
+ ### `spooling mcp`
219
+
220
+ Start the Spooling MCP server on its own. Defaults to streamable-HTTP at
221
+ `http://127.0.0.1:3004/mcp`, which any MCP-compatible agent can connect to
222
+ by URL. `spooling ui` already launches this alongside the API, so you only
223
+ need to run it directly when you want the MCP server without the GUI.
224
+
225
+ ```bash
226
+ spooling mcp # streamable-HTTP at http://127.0.0.1:3004/mcp (default)
227
+ spooling mcp --stdio # stdio transport, for stdio-only clients
228
+ ```
229
+
230
+ ### `spooling tunnel`
231
+
232
+ Create a Cloudflare quick tunnel (no account required) to expose your local MCP server to the internet. Once started, it prints a public HTTPS URL you can drop straight into any remote MCP client config. Requires [`cloudflared`](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) to be installed.
233
+
234
+ ```bash
235
+ spooling tunnel # Expose Spooling MCP (port 3004, default)
236
+ spooling tunnel --port 8090 # Expose a custom local port
237
+ spooling tunnel -p 3000 -n my-api # Named tunnel on port 3000
238
+ ```
239
+
240
+ Options:
241
+ - `-p, --port` - Local port to expose (default: 3004)
242
+ - `-n, --name` - Label for display purposes
243
+
244
+ After the tunnel starts, it prints the public URL and an MCP config snippet ready to paste:
245
+
246
+ ```json
247
+ {"mcpServers": {"spooling": {"type": "http", "url": "https://<random>.trycloudflare.com/mcp"}}}
248
+ ```
249
+
250
+ Install `cloudflared` if not already present:
251
+
252
+ ```bash
253
+ # macOS
254
+ brew install cloudflared
255
+
256
+ # Linux
257
+ curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 \
258
+ -o /usr/local/bin/cloudflared && chmod +x /usr/local/bin/cloudflared
259
+
260
+ # Windows
261
+ winget install cloudflare.cloudflared
262
+ ```
263
+
264
+ ### `spooling cost`
265
+
266
+ Detailed cost tracking and spend analysis. All subcommands read from the local database — no network calls.
267
+
268
+ ```bash
269
+ spooling cost overview # Total spend: input/output/cache breakdown
270
+ spooling cost overview --provider cursor # Filter to one provider
271
+ spooling cost overview --days 7 # Last 7 days only
272
+
273
+ spooling cost breakdown # Cost by provider (default)
274
+ spooling cost breakdown --by model # Cost by model
275
+ spooling cost breakdown --by project # Cost by project
276
+ spooling cost breakdown --by model --days 30 # Model breakdown, last 30 days
277
+
278
+ spooling cost daily # Daily trend (last 30 days)
279
+ spooling cost daily --days 14 # Last 14 days
280
+ spooling cost daily --provider codex # Filter by provider
281
+
282
+ spooling cost monthly # Monthly trend (last 12 months)
283
+ spooling cost monthly --months 6 # Last 6 months
284
+
285
+ spooling cost session <session-id> # Detailed cost for a single session
286
+
287
+ spooling cost recalc # Dry-run: re-price all sessions against current rates
288
+ spooling cost recalc --apply # Actually persist the repriced values
289
+ spooling cost recalc --session <id> --apply # Reprice one session
290
+ spooling cost recalc --provider cursor --apply # Reprice all sessions for a provider
291
+ ```
292
+
293
+ ### `spooling eval`
294
+
295
+ Run LLM-as-judge rubrics against your session traces.
296
+
297
+ ```bash
298
+ spooling eval list # List all configured rubrics
299
+ spooling eval run --rubric <id> --trace <id> # Score one trace
300
+ spooling eval run --rubric <id> --days 7 # Batch-score traces from the last 7 days
301
+ ```
302
+
303
+ ### `spooling experiment`
304
+
305
+ Create and run Strands-style experiments — a set of test cases evaluated by one or more rubrics.
306
+
307
+ ```bash
308
+ spooling experiment list # List all experiments
309
+ spooling experiment create --file spec.json # Register an experiment from a JSON spec
310
+ spooling experiment run --id <experiment-id> # Run an experiment and persist the report
311
+ spooling experiment show --run <run-id> # Show the results of a past run
312
+ ```
313
+
314
+ ### `spooling otel`
315
+
316
+ Ingest OpenTelemetry / Strands span exports from external sources into Spooling.
317
+
318
+ ```bash
319
+ spooling otel ingest --file spans.json # Ingest an OTLP JSON export
320
+ spooling otel ingest --file spans.json --provider my-agent # Tag with a custom provider id
321
+ spooling otel ingest --file spans.json --project myproject # Tag with a project name
322
+ ```
323
+
324
+ ### `spooling pricing`
325
+
326
+ Manage the LiteLLM-backed model pricing table used for cost calculations.
327
+
328
+ ```bash
329
+ spooling pricing show # Show cache status and source info
330
+ spooling pricing show claude-sonnet-4-5 # Show per-component rates for a model ($/Mtok)
331
+ spooling pricing refresh # Force-fetch latest rates into ~/.spool/model_prices.json
332
+ ```
333
+
334
+ ---
335
+
336
+ ## Spooling Cloud (optional)
337
+
338
+ By default Spooling stays 100% local. If you also want your sessions in the
339
+ hosted workspace at [spooling.ai](https://spooling.ai) (so teammates can
340
+ search the same pool, or you can chat with sessions from any browser),
341
+ the CLI ships with a `spooling cloud` subcommand.
342
+
343
+ ### One-time setup
344
+
345
+ 1. Mint an API key in the GUI at `app.spooling.ai/settings/api-keys`
346
+ (looks like `sk_live_...`).
347
+ 2. Save it locally:
348
+
349
+ ```bash
350
+ spooling cloud login --key sk_live_...
351
+ ```
352
+
353
+ The key is stored at `~/.config/spooling/cloud.json` with `0600` perms.
354
+ You can override the API base with `--api-url` or the
355
+ `SPOOLING_CLOUD_URL` env var (default: `https://api.spooling.ai`).
356
+
357
+ ### Push once
358
+
359
+ Send the most recent local sessions up to the cloud:
360
+
361
+ ```bash
362
+ spooling push # 100 sessions, batches of 20
363
+ spooling push --limit 500 # bigger backfill
364
+ ```
365
+
366
+ The server upserts by session id, so re-running is safe.
367
+
368
+ ### Watch (continuous push)
369
+
370
+ Stream new and updated sessions to the cloud on a timer. Stop with
371
+ Ctrl+C.
372
+
373
+ ```bash
374
+ spooling cloud watch # every 60s, 1000 sessions/cycle
375
+ spooling cloud watch --interval 30 # tighter cadence
376
+ spooling cloud watch --lookback 60 # widen the overlap window if you edit old sessions
377
+ ```
378
+
379
+ What it does each cycle:
380
+
381
+ 1. Reads `last_push_at` from `~/.config/spooling/cloud.json`.
382
+ 2. Queries local sessions where `started_at >= last_push_at - lookback`
383
+ (default lookback: 10 minutes, so messages appended to an in-progress
384
+ session get re-uploaded).
385
+ 3. POSTs to `/v1/sessions/batch` in chunks of `--batch` (default 20).
386
+ 4. Advances `last_push_at` to the cycle start on success.
387
+
388
+ Cycles with no new work are silent. If a push fails the watermark is
389
+ not advanced, so the next cycle retries the same window.
390
+
391
+ ### Cloud API endpoints (programmatic access)
392
+
393
+ The cloud API at `api.spooling.ai` uses `/v1/` endpoints. Requests require a Bearer token via the `Authorization` header:
394
+
395
+ ```bash
396
+ # Stats
397
+ curl -s "https://api.spooling.ai/v1/stats" \
398
+ -H "Authorization: Bearer $SPOOLING_KEY"
399
+
400
+ # Search (when deployed — falls back to local search on self-hosted)
401
+ curl -s "https://api.spooling.ai/api/search?q=migration&limit=10" \
402
+ -H "Authorization: Bearer $SPOOLING_KEY"
403
+ ```
404
+
405
+ **Important**: `app.spooling.ai` is the Next.js frontend. For API access, use `api.spooling.ai` directly or set `API_URL=https://api.spooling.ai` when deploying the frontend so its `/api/*` rewrites reach the backend.
406
+
407
+ ### Status / logout
408
+
409
+ ```bash
410
+ spooling cloud status # show what is in the cloud + stored API base
411
+ spooling cloud logout # remove the stored API key
412
+ ```
413
+
414
+ ### Auto-start at login (macOS)
415
+
416
+ Run `spooling cloud watch` as a launchd agent so it survives reboots:
417
+
418
+ ```bash
419
+ cat > ~/Library/LaunchAgents/ai.spooling.cloud-watch.plist <<'PLIST'
420
+ <?xml version="1.0" encoding="UTF-8"?>
421
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
422
+ <plist version="1.0">
423
+ <dict>
424
+ <key>Label</key><string>ai.spooling.cloud-watch</string>
425
+ <key>ProgramArguments</key>
426
+ <array>
427
+ <string>/usr/local/bin/spooling</string>
428
+ <string>cloud</string>
429
+ <string>watch</string>
430
+ </array>
431
+ <key>RunAtLoad</key><true/>
432
+ <key>KeepAlive</key><true/>
433
+ <key>StandardOutPath</key><string>/tmp/spooling-cloud-watch.log</string>
434
+ <key>StandardErrorPath</key><string>/tmp/spooling-cloud-watch.log</string>
435
+ </dict>
436
+ </plist>
437
+ PLIST
438
+ launchctl load ~/Library/LaunchAgents/ai.spooling.cloud-watch.plist
439
+ ```
440
+
441
+ (Adjust the `spooling` path with `which spooling` if it lives elsewhere.)
442
+
443
+ ---
444
+
445
+ ## MCP Endpoint
446
+
447
+ Spooling exposes an MCP server so any AI agent can query your session history
448
+ as a context source. The server runs over **streamable-HTTP** at
449
+ `http://127.0.0.1:3004/mcp` and is started automatically alongside `spooling
450
+ ui`.
451
+
452
+ Drop this into your MCP client config (`~/.mcp.json`, Cursor,
453
+ Codex, or any other streamable-HTTP capable agent):
454
+
455
+ ```json
456
+ {
457
+ "mcpServers": {
458
+ "spooling": {
459
+ "url": "http://127.0.0.1:3004/mcp"
460
+ }
461
+ }
462
+ }
463
+ ```
464
+
465
+ Or register it with an MCP client's config file.
466
+
467
+ The **Settings** page in the GUI shows the endpoint URL, a copy button, and
468
+ the full config snippet so you don't have to remember it.
469
+
470
+ ### Tools exposed
471
+
472
+ | Tool | Purpose |
473
+ |------|---------|
474
+ | `list_traces` | Recent Spooling traces, filterable by provider/project |
475
+ | `get_trace` | Full detail for one trace: header, spans, eval scores |
476
+ | `search_sessions` | Semantic search over embedded session chunks |
477
+ | `get_stats` | Top-line stats: traces, tokens, cost, errors |
478
+ | `get_top_vendors` | Most-used external vendors by tool-call count |
479
+ | `list_evals` | Recent eval runs, optionally filtered by rubric |
480
+ | `list_rubrics` | All configured Strands eval rubrics |
481
+ | `run_eval` | Run a rubric against a trace and persist the result |
482
+
483
+ ### Stdio (legacy clients)
484
+
485
+ For MCP clients that only speak stdio, run `spooling mcp --stdio` and register
486
+ it with the command-based form:
487
+
488
+ ```bash
489
+ # MCP config for stdio transport
490
+ ```
491
+
492
+ ---
493
+
494
+ ## GUI
495
+
496
+ The Spooling GUI runs on **http://localhost:3003** and includes:
497
+
498
+ | Page | Description |
499
+ |------|-------------|
500
+ | **Dashboard** | Overview stats, per-provider breakdown, daily activity chart, projects, top tools, recent sessions |
501
+ | **Sessions** | Browse all sessions with provider labels, filtering, click into any session for full conversation view |
502
+ | **Search** | Semantic search across all session history with similarity scores |
503
+ | **Analytics** | Charts for daily usage, cost trends, token usage, tool distribution, filterable by provider (AG Charts) |
504
+ | **Chat** | AI assistant that can answer questions about your session data (RAG-powered) |
505
+ | **Connections** | Connect/disconnect AI coding tools (Codex, Copilot, Cursor, Windsurf) |
506
+ | **Settings** | Configure the AI chat provider (Ollama or Anthropic) |
507
+
508
+ ### Running the GUI
509
+
510
+ ```bash
511
+ # Terminal 1: API server
512
+ source .venv/bin/activate
513
+ spooling serve
514
+
515
+ # Terminal 2: Next.js dev server
516
+ cd ui
517
+ npm run dev
518
+ ```
519
+
520
+ Or use `spooling ui` to start both at once.
521
+
522
+ ---
523
+
524
+ ## Chat Agent Setup
525
+
526
+ The chat page lets you ask questions about your coding sessions in natural language. It uses RAG - retrieves relevant context from pgvector before answering.
527
+
528
+ ### Option A: Ollama (free, local)
529
+
530
+ ```bash
531
+ # Install Ollama
532
+ brew install ollama
533
+
534
+ # Start the server
535
+ ollama serve
536
+
537
+ # Pull a model
538
+ ollama pull gemma3:4b
539
+ ```
540
+
541
+ Go to **Settings** in the GUI and select Ollama. The model will auto-detect.
542
+
543
+ ### Option B: Anthropic API (bring your own key)
544
+
545
+ Go to **Settings** in the GUI, select Anthropic, and paste your API key from [console.anthropic.com](https://console.anthropic.com).
546
+
547
+ Available models: Sonnet, Haiku, Opus.
548
+
549
+ ---
550
+
551
+ ## Architecture
552
+
553
+ ```
554
+ spooling/
555
+ ├── docker-compose.yml # PostgreSQL + pgvector
556
+ ├── init.sql # Database schema
557
+ ├── pyproject.toml # Python package config
558
+ ├── spooling/ # Python backend
559
+ │ ├── cli.py # Click CLI
560
+ │ ├── config.py # Configuration
561
+ │ ├── db.py # Database connection
562
+ │ ├── providers/ # Provider plugins (codex, copilot, cursor, windsurf)
563
+ │ ├── parser.py # Session JSONL parser
564
+ │ ├── embeddings.py # sentence-transformers (all-MiniLM-L6-v2)
565
+ │ ├── ingest.py # Sync pipeline
566
+ │ ├── search.py # pgvector semantic search
567
+ │ ├── stats.py # Usage statistics
568
+ │ ├── watcher.py # File watcher (watchdog)
569
+ │ ├── agent.py # Chat agent (Ollama + Anthropic)
570
+ │ ├── tunnel.py # Cloudflare quick tunnel support
571
+ │ └── server.py # FastAPI API server
572
+ └── ui/ # Next.js frontend
573
+ ├── next.config.js # API proxy to :3002
574
+ └── src/
575
+ ├── components/ # shadcn/ui components
576
+ ├── lib/ # API helpers
577
+ └── app/(app)/ # Pages (dashboard, sessions, search, etc.)
578
+ ```
579
+
580
+ ### Stack
581
+
582
+ | Layer | Technology |
583
+ |-------|-----------|
584
+ | Database | PostgreSQL 16 + pgvector (Docker) |
585
+ | Embeddings | sentence-transformers / all-MiniLM-L6-v2 (local) |
586
+ | Backend | Python, FastAPI, Click |
587
+ | Frontend | Next.js 14, shadcn/ui, Tailwind CSS, AG Charts |
588
+ | Chat AI | Ollama (local) or Anthropic API |
589
+
590
+ ### Ports
591
+
592
+ | Service | Port |
593
+ |---------|------|
594
+ | PostgreSQL | 5434 |
595
+ | API Server | 3002 |
596
+ | GUI | 3003 |
597
+ | MCP Server (streamable-HTTP) | 3004 |
598
+
599
+ ---
600
+
601
+ ## Environment Variables
602
+
603
+ All optional - defaults work out of the box for local development.
604
+
605
+ | Variable | Default | Description |
606
+ |----------|---------|-------------|
607
+ | `SPOOLING_DB_HOST` | `localhost` | Database host |
608
+ | `SPOOLING_DB_PORT` | `5434` | Database port |
609
+ | `SPOOLING_DB_NAME` | `spooling` | Database name |
610
+ | `SPOOLING_DB_USER` | `spooling` | Database user |
611
+ | `SPOOLING_DB_PASSWORD` | `spooling` | Database password |
612
+ | `SPOOLING_EMBEDDING_MODEL` | `all-MiniLM-L6-v2` | Sentence transformer model |
613
+ | `SPOOLING_UI_HOST` | `127.0.0.1` | API server host |
614
+ | `ANTHROPIC_API_KEY` | - | Anthropic API key (alternative to setting in UI) |
615
+ | `API_URL` | `http://127.0.0.1:3002` | Backend API URL for Next.js rewrites (`/api/*`→`<API_URL>/api/*`). Set to `https://api.spooling.ai` in production. |
616
+
617
+ ---
618
+
619
+ ## Supported Providers
620
+
621
+ | Provider | Data Location | Format |
622
+ |----------|--------------|--------|
623
+ | **JSONL Sessions** | `~/.sessions/projects/` | UUID-named JSONL files with conversation history, tool calls, git context |
624
+ | **OpenAI Codex CLI** | `~/.codex/sessions/` | `rollout-*.jsonl` files organized by date |
625
+ | **GitHub Copilot** | `~/Library/Application Support/Code/User/workspaceStorage/` | Chat session JSON from VS Code |
626
+ | **Cursor** | `~/Library/Application Support/Cursor/User/workspaceStorage/` | Chat and composer sessions from SQLite |
627
+ | **Windsurf** | `~/Library/Application Support/Windsurf/User/workspaceStorage/` | Chat and Cascade sessions from SQLite |
628
+ | **Kiro** | `~/Library/Application Support/Kiro/User/workspaceStorage/` | AWS Kiro chat and agent sessions from SQLite |
629
+ | **Google Antigravity** | `~/Library/Application Support/Antigravity/User/workspaceStorage/` | Antigravity chat and agent sessions from SQLite |
630
+ | **opencode** | `~/.local/share/opencode/opencode.db` | sst/opencode SQLite database with session/message/part tables (Vercel AI SDK part shape) |
631
+
632
+ Run `spooling init` to see which providers are detected on your system.
633
+
634
+ No data is sent to external servers. Everything runs locally.
635
+
@@ -1,7 +1,8 @@
1
1
  [project]
2
2
  name = "spooling"
3
- version = "0.1.7"
3
+ version = "0.2.0"
4
4
  description = "Local session tracker and semantic search for AI coding assistants"
5
+ readme = "README.md"
5
6
  authors = [{ name = "Parsed Analytics, Inc." }]
6
7
  license = { text = "MIT" }
7
8
  requires-python = ">=3.11"
@@ -12,8 +13,8 @@ classifiers = [
12
13
  ]
13
14
  dependencies = [
14
15
  "click>=8.1",
15
- "psycopg[binary]>=3.1",
16
16
  "sentence-transformers>=3.0",
17
+ "numpy>=1.24",
17
18
  "fastapi>=0.111",
18
19
  "uvicorn[standard]>=0.30",
19
20
  "jinja2>=3.1",
@@ -23,7 +24,7 @@ dependencies = [
23
24
  "anthropic>=0.40",
24
25
  "strands-agents[ollama]>=1.35",
25
26
  "strands-agents-evals>=0.1",
26
- "mcp>=1.27",
27
+ "mcp>=1.27,<2",
27
28
  ]
28
29
 
29
30
  [project.optional-dependencies]