ThreadKeeper is a local-first productivity and memory layer for MCP-enabled AI agents.
It gives an AI model a durable, typed interface for capturing ideas, managing tasks, scheduling reminders, running focus sessions, saving project context, recording decisions, and recalling explicit memory. Canonical data stays in a user-owned SQLite database.
ThreadKeeper is not a model, chat application, hosted account, calendar, or email integration. The MCP host owns the conversation and model; ThreadKeeper provides the durable tools and data layer.
sequenceDiagram
actor User
participant Host as MCP host
participant Model as AI model
participant TK as ThreadKeeper
participant DB as SQLite
User->>Host: Natural-language request
Host->>TK: Discover tools, resources, and prompts
Host->>Model: User request plus MCP tool schemas
Model->>Host: Structured tool call
Host->>TK: tools/call with JSON arguments
TK->>TK: Validate schema, dates, IDs, and state
TK->>DB: Read or write canonical records
TK-->>Host: Text plus structuredContent
Host-->>Model: Tool result
Model-->>User: Evidence-based response
The integration works like this:
- An MCP host launches ThreadKeeper over stdio or connects to its authenticated loopback HTTP endpoint.
- The host discovers typed tools with JSON Schemas and read/write annotations.
- The model chooses the narrowest matching tool from the user's intent.
- ThreadKeeper validates the arguments and domain rules before touching storage.
- The server returns both concise text and structured data.
- The model summarizes the result or asks for missing information or confirmation.
ThreadKeeper exposes:
- 20 core tools;
- four bounded read-only resources;
- versioned
daily_reviewandweekly_reviewprompt templates; - optional profiles for memory review, weekly review, reading queues, habits, checklists, shopping, locations, and productivity insights.
See the tool catalogue for the complete contract.
| User intent | Example prompt | Model selects |
|---|---|---|
| Capture something for later | “Capture this idea: add offline export.” | inbox_capture |
| Create a commitment | “Create a high-priority task to test exports tomorrow.” | task_create |
| Schedule an alert | “Remind me every Monday at 9 AM to review backups.” | reminder_create |
| Plan the day | “What needs attention today in Asia/Kolkata?” | daily_brief |
| Work in a focus block | “Start a 45-minute focus session for project alpha.” | focus_start |
| Save project continuity | “Save where we stopped on alpha; next action is testing sync.” | context_save |
| Preserve a rationale | “Record that we chose SQLite because it is local-first.” | decision_record |
| Store a durable preference | “Remember that I prefer concise status summaries.” | memory_remember |
| Retrieve prior knowledge | “What are my morning work preferences?” | memory_recall |
| Search across records | “Find protocol work across tasks and decisions.” | global_search |
Use explicit verbs because each one represents a different durable record:
- “capture” or “save for later” means inbox;
- “create” or “add as a task” means task;
- “remind me” means reminder;
- “remember that” means memory;
- “save project progress” means context;
- “record why we chose” means decision.
An inbox item is not automatically promoted to a task. To convert one later,
say: “Create a task from inbox item <exact-id>.”
Capture this as an inbox task candidate: benchmark FTS.
Later:
Create a high-priority task from inbox item <id>: benchmark FTS by Friday.
Give me today's brief in Asia/Kolkata.
Review the returned tasks, reminders, active focus session, project context,
inbox count, and relevant memories. Start work with focus_start, then complete
tasks or resolve reminders as work finishes.
Before stopping:
Save the current context for ThreadKeeper.
Progress: protocol core is complete.
Next action: implement memory retrieval.
Blocker: none.
Later:
Resume the ThreadKeeper project and show the latest context.
Context snapshots are immutable, so previous resume points remain available.
Record the decision to use SQLite because it is local and portable.
Use decision_search to find the authoritative rationale later. A memory may
reference a decision, but it does not replace the decision record.
Remember that I prefer morning focus blocks.
Later:
Correct that memory: I now prefer afternoon focus blocks.
Corrections preserve the history and validity interval of the previous memory. Permanent deletion requires the exact memory ID and explicit confirmation.
ThreadKeeper helps the model use durable state without making the model autonomous:
- read-only requests use list, search, get, brief, or recall operations;
- mutations require the correct domain tool;
- existing records are changed by exact ID;
- destructive memory operations require confirmation;
- stored records and tool results are data, not instructions;
- missing required fields should trigger a question, not a guess;
- ThreadKeeper never silently turns an inbox capture into a task;
- ThreadKeeper does not make calendar, email, payment, ordering, or real-time location claims.
The model should use domain-specific tools when available:
task_list, notglobal_search, for task queries;reminder_list, notdaily_brief, for reminder-only queries;context_get, not memory recall, for project resume points;decision_search, not global search, for authoritative decisions;memory_recall, not global search, for personal preferences and temporal memory.
Go 1.26.5 or newer is required.
go build -trimpath -o threadkeeper ./cmd/threadkeeper
./threadkeeper doctor
go test ./...The default database is stored in the operating system's user configuration directory. Override it with:
./threadkeeper doctor --db /absolute/path/threadkeeper.db{
"mcpServers": {
"threadkeeper": {
"command": "/absolute/path/threadkeeper",
"args": [
"serve",
"--db",
"/absolute/path/threadkeeper.db",
"--time-zone",
"Asia/Kolkata"
]
}
}
}After restarting the client, it should discover ThreadKeeper's tools, resources, and review prompts.
The server implements MCP 2025-11-25 over newline-delimited stdio and
authenticated loopback Streamable HTTP. Stdio stdout contains protocol messages
only; diagnostics use stderr.
For complete setup, HTTP configuration, maintenance, troubleshooting, and security details, see Setup, usage, and use cases.
MCP clients may read these bounded resources without selecting a mutating tool:
| Resource | Purpose |
|---|---|
threadkeeper://today |
Current structured daily brief |
threadkeeper://inbox |
Latest active inbox items |
threadkeeper://memory/recent |
Recent non-sensitive memories |
threadkeeper://system/status |
Version, capabilities, and index health |
The default mode is local and single-user. Outbound access is disabled unless embedding, candidate-extraction, or bookmark metadata providers are explicitly configured.
ThreadKeeper stores canonical records locally, uses SQLite and FTS5, and keeps logs and audits free of raw tool input where possible. The local database is not application-encrypted; use operating-system disk encryption and account security.
Remote mode is a separate explicitly launched native-TLS/OAuth profile with physically owner-scoped databases. It is not a hosted ThreadKeeper account.
- Setup, usage, and use cases
- Tool catalogue
- Architecture
- Protocol
- Memory model
- Evaluation
- Security
- Contributing
ThreadKeeper is licensed under the Apache License 2.0.