Skip to content

Latest commit

 

History

History
714 lines (562 loc) · 30.3 KB

File metadata and controls

714 lines (562 loc) · 30.3 KB

Setup, usage, and use cases

ThreadKeeper is a local MCP server for durable productivity records and explicit, versioned memory. An MCP client may launch the threadkeeper binary over stdio or connect to an explicitly started, authenticated loopback Streamable HTTP endpoint. The compatible core remains a stdio server. The loopback dashboard, HTTP endpoint, optional reminder daemon, and V2C native-TLS remote service are separate processes. No hosted account or authorization server is bundled.

1. Requirements and installation

You need:

  • macOS, Linux, or Windows.
  • Go 1.26.5 or newer when building from source.
  • An MCP client that supports stdio servers.
  • Optionally, an Ollama-compatible embedding endpoint for hybrid memory search and a separately configured model for review-only candidate extraction.

Build and verify from the repository root:

go build -trimpath -o threadkeeper ./cmd/threadkeeper
./threadkeeper doctor
go test ./...

Use an absolute path to the resulting binary in client configuration. You may instead install it into your configured Go binary directory:

go install ./cmd/threadkeeper

doctor creates or opens the configured database, applies pending core and enabled-module migrations, and checks the database, FTS5, time zone, and optional embedding provider.

2. Database location

Without configuration, ThreadKeeper stores threadkeeper.db under the operating system's user configuration directory, typically:

  • macOS: ~/Library/Application Support/ThreadKeeper/threadkeeper.db
  • Linux: $XDG_CONFIG_HOME/ThreadKeeper/threadkeeper.db or ~/.config/ThreadKeeper/threadkeeper.db
  • Windows: %AppData%\ThreadKeeper\threadkeeper.db

Use the same explicit database path in every client that should share the same records:

./threadkeeper doctor --db /absolute/path/to/threadkeeper.db

Database, backup, export, and log files created by ThreadKeeper are restricted to the current user where the operating system supports Unix-style permissions.

3. Configure an MCP client

Add a stdio server entry to the client's MCP configuration. Client products name the containing field differently, but the server entry is:

{
  "mcpServers": {
    "threadkeeper": {
      "command": "/absolute/path/to/threadkeeper",
      "args": [
        "serve",
        "--db",
        "/absolute/path/to/threadkeeper.db",
        "--time-zone",
        "Asia/Kolkata"
      ]
    }
  }
}

Use an IANA time zone such as UTC, Asia/Kolkata, or America/New_York. Restart the client after changing its MCP configuration. The client should then show a server named threadkeeper with 20 core tools, four resources, and two read-only review prompts.

The client owns the process lifecycle. Running threadkeeper serve directly in a terminal is useful only for protocol testing: it waits for newline-delimited JSON-RPC messages on stdin and writes protocol responses to stdout.

Verify with MCP Inspector

With Node.js and npm available:

npx -y @modelcontextprotocol/inspector --cli \
  /absolute/path/to/threadkeeper serve \
  --db /absolute/path/to/threadkeeper.db \
  --time-zone UTC \
  --log-level error \
  --method tools/list

The result should contain exactly 20 tools. To check resources:

npx -y @modelcontextprotocol/inspector --cli \
  /absolute/path/to/threadkeeper serve \
  --db /absolute/path/to/threadkeeper.db \
  --time-zone UTC \
  --log-level error \
  --method resources/list

Local Streamable HTTP

Initialize a distinct local MCP credential once, then start the listener. Use a fixed port in client configuration; port zero is useful for temporary/manual sessions because it chooses an available port.

./threadkeeper http init \
  --db /absolute/path/to/threadkeeper.db \
  --http-token-file /absolute/private/path/threadkeeper-http.token

./threadkeeper http serve \
  --db /absolute/path/to/threadkeeper.db \
  --http-token-file /absolute/private/path/threadkeeper-http.token \
  --http-address 127.0.0.1 \
  --http-port 8787

The endpoint is http://127.0.0.1:8787/mcp. Clients send the token as Authorization: Bearer <token>. ThreadKeeper stores only its SHA-256 hash in SQLite; the portable fallback file is created atomically with user-only permissions and the token is never printed. A client may import that plaintext token into its OS keychain and then restrict or remove its own fallback copy.

Verify the authenticated endpoint with the pinned official Inspector:

IFS= read -r THREADKEEPER_LOCAL_TOKEN < /absolute/private/path/threadkeeper-http.token
npx -y @modelcontextprotocol/inspector@0.22.0 --cli \
  http://127.0.0.1:8787/mcp \
  --transport http \
  --method tools/list \
  --header "Authorization: Bearer ${THREADKEEPER_LOCAL_TOKEN}"
unset THREADKEEPER_LOCAL_TOKEN

Credential lifecycle commands are explicit and survive process restarts:

./threadkeeper http status --db /absolute/path/to/threadkeeper.db --http-token-file /absolute/private/path/threadkeeper-http.token
./threadkeeper http init --db /absolute/path/to/threadkeeper.db --http-token-file /absolute/private/path/threadkeeper-http.token --rotate
./threadkeeper http revoke --db /absolute/path/to/threadkeeper.db --confirmation

Rotation revokes the previous bearer immediately. Revocation intentionally leaves the now-invalid fallback file in place; use http init --rotate to replace it safely. The listener accepts only explicit loopback IPs, rejects forwarded and cross-origin requests, exposes no permissive CORS, and applies body/header/rate/concurrency/connection/time limits. /health/live and /health/ready reveal only bounded status. The dashboard does not accept this credential and MCP HTTP does not accept dashboard launch/session credentials.

Remote OAuth service

Remote mode is not an extension of localhost HTTP and never accepts its token. It requires a trusted external OAuth issuer, registered ThreadKeeper grant, native TLS, exact public resource URL, managed encrypted storage, and an operator go-live review. It maps issuer/subject to an internal owner and opens only that owner's physical database.

Follow remote deployment for provisioning and startup, then keep the incident, backup, and deletion runbooks with the deployment. Offline clients use authenticated /sync/changes, /sync/mutations, and /sync/snapshot; they never copy or merge a SQLite file. After applying a full snapshot, resume /sync/changes after the cursor in the snapshot response's X-ThreadKeeper-Change-Cursor header.

4. How to use ThreadKeeper

Normally, speak to the MCP-enabled agent in plain language. The agent chooses a tool, asks for missing destructive-action confirmation when necessary, and returns the structured result. You do not need to write JSON.

Good prompts are explicit about the desired durable action:

  • “Capture this idea in my inbox: build a weekly review workflow.”
  • “Create a high-priority task to draft the launch post by Friday at 5 PM.”
  • “Remind me every week on Monday at 9 AM to review project alpha.”
  • “Start a 45-minute focus session for project alpha.”
  • “Save the current context for project alpha; the next action is to test sync.”
  • “Record that we chose SQLite because the product is local-first.”
  • “Remember that I prefer concise status summaries.”
  • “Show my daily brief for tomorrow in Asia/Kolkata.”
  • “Search all my ThreadKeeper data for database migration.”

Use “capture,” “create a task,” “remind me,” “save project context,” “record a decision,” and “remember this preference” deliberately: each stores a different kind of durable record.

5. Tool and use-case map

Need Tool Example request
Capture an unprocessed thought inbox_capture “Capture this idea: add offline export.”
Create a concrete action task_create “Create a task to test exports tomorrow.”
Review or filter tasks task_list “List overdue pending tasks for project alpha.”
Finish a task task_complete “Mark that export test task complete.”
Schedule a stored reminder reminder_create “Remind me daily at 6 PM to write notes.”
Review reminders reminder_list “List reminders due this week.”
Complete, cancel, or snooze reminder_resolve “Snooze that reminder until 4 PM.”
Start focused work focus_start “Start a 25-minute focus session for alpha.”
End focused work focus_end “End the session as completed; tests pass.”
Save a resumable project snapshot context_save “Save where we stopped on alpha.”
Resume a project context_get “Get the latest context for alpha.”
Preserve a reasoned choice decision_record “Record why we selected SQLite.”
Find prior choices decision_search “Find decisions about persistence.”
Assemble today's structured agenda daily_brief “Give me today's brief in Asia/Kolkata.”
Search every selected domain global_search “Search tasks, contexts, and memories for FTS.”
Store explicit durable memory memory_remember “Remember that I prefer dark mode.”
Retrieve relevant memory memory_recall “What interface preferences have I told you?”
Correct memory without losing history memory_correct “Correct that: I now prefer light mode.”
Permanently remove exact memory memory_forget “Forget that preference; yes, permanently delete it.”
Explain provenance and validity memory_explain “Explain where that preference came from.”

The complete contracts, limits, and fields are declared to MCP clients at runtime and stored under schemas/. See the tool catalogue for the frozen V1 list.

6. Common workflows

Capture now, process later

  1. Ask the agent to capture an idea with inbox_capture.
  2. Later, ask it to create a task from the inbox item with task_create.
  3. Search the original idea with global_search when needed.

Inbox capture is intentionally lightweight. Use a task only when the item has a defined action, priority, or due time.

Plan and execute a day

  1. Request daily_brief for a date and time zone.
  2. Review overdue tasks, today's tasks, upcoming reminders, active focus, project contexts, inbox count, and relevant memories.
  3. Start work with focus_start and end it with focus_end.
  4. Complete tasks and resolve reminders as work finishes.

The brief is structured data, not generated prose; the client may summarize it.

Pause and resume a project across conversations

Before stopping:

  1. Save a context snapshot containing the current state, next action, blockers, and safe references.
  2. Record important choices separately as decisions.

In a later conversation, ask for the latest project context and related decisions. Context snapshots are immutable, so older snapshots remain available for historical lookup.

Preserve a decision trail

Use decision_record for a choice plus its reasoning and alternatives. Use decision_search rather than memory when you need the authoritative decision record. A memory can reference a decision, but it does not replace it.

Store, correct, and forget memory

Memory is explicit in V1:

  1. “Remember that I prefer morning meetings.” creates sourced memory.
  2. memory_recall finds it in a later session using keyword search or optional hybrid search.
  3. A correction creates a new version and closes the old version's validity interval; historical asOf recall can still return the former version.
  4. Forgetting requires the exact memory ID and confirmation: true. It removes canonical content, provenance, FTS data, embeddings, and feedback for that memory while retaining a content-free deletion audit.

Do not use memory for passwords, API keys, OTPs, private keys, session tokens, or other authentication material. ThreadKeeper rejects likely secrets, but its detection is heuristic rather than a password manager.

Search versus recall

  • Use global_search to find literal matches across operational records and memories, grouped by domain.
  • Use decision_search for authoritative decisions.
  • Use context_get for the latest resumable state of one project.
  • Use memory_recall for relevant personal or project knowledge with temporal validity, confidence, importance, provenance, and explanations.

7. Read-only resources

Clients may read these without selecting a tool:

Resource Contents
threadkeeper://today Today's structured daily brief.
threadkeeper://inbox Latest active inbox items.
threadkeeper://memory/recent Recent active, non-sensitive memories.
threadkeeper://system/status Version, schema, capabilities, metrics, index health, and backup status.
threadkeeper://system/modules Enabled/installed V2A modules, migrations, contributed tools, and health; advertised only with a V2A profile.

Resources are bounded and read-only. ThreadKeeper does not advertise resource subscriptions in V1.

8. Configuration

Precedence is command-line flags, environment variables, user config.json, then defaults.

Setting CLI flag Environment Config key Default
Database --db THREADKEEPER_DB databasePath OS user config directory
Time zone --time-zone THREADKEEPER_TIME_ZONE timeZone UTC
Embedding endpoint --embedding-endpoint THREADKEEPER_EMBED_ENDPOINT embeddingEndpoint disabled
Embedding model --embedding-model THREADKEEPER_EMBED_MODEL embeddingModel disabled
Embedding dimensions --embedding-dimensions THREADKEEPER_EMBED_DIMENSIONS embeddingDimensions disabled
Export allowlist --export-dir THREADKEEPER_EXPORT_DIR exportDirectory database directory
Migration backups --backup-retention THREADKEEPER_BACKUP_RETENTION backupRetention 3
Log level --log-level THREADKEEPER_LOG_LEVEL logLevel info
Log file --log-file THREADKEEPER_LOG_FILE logFile stderr
In-flight requests --max-concurrency THREADKEEPER_MAX_CONCURRENCY maxConcurrency 4
Tool profiles --profiles THREADKEEPER_PROFILES profiles core
Candidate endpoint --candidate-endpoint THREADKEEPER_CANDIDATE_ENDPOINT candidateEndpoint disabled
Candidate model --candidate-model THREADKEEPER_CANDIDATE_MODEL candidateModel disabled
Candidate batch --candidate-batch-size THREADKEEPER_CANDIDATE_BATCH_SIZE candidateBatchSize 64
Scheduled candidates --candidate-auto THREADKEEPER_CANDIDATE_AUTO candidateAuto false
Candidate interval --candidate-interval-minutes THREADKEEPER_CANDIDATE_INTERVAL_MINUTES candidateIntervalMinutes 60
Daemon polling --daemon-poll-seconds THREADKEEPER_DAEMON_POLL_SECONDS daemonPollSeconds 30
Missed-reminder grace --daemon-grace-minutes THREADKEEPER_DAEMON_GRACE_MINUTES daemonGraceMinutes 1440
Inspector port --dashboard-port THREADKEEPER_DASHBOARD_PORT dashboardPort available loopback port
MCP HTTP address --http-address THREADKEEPER_HTTP_ADDRESS httpAddress 127.0.0.1
MCP HTTP port --http-port THREADKEEPER_HTTP_PORT httpPort available loopback port
MCP token file --http-token-file THREADKEEPER_HTTP_TOKEN_FILE httpTokenFile database path plus .http-token
MCP HTTP connections --http-max-connections THREADKEEPER_HTTP_MAX_CONNECTIONS httpMaxConnections 32
MCP HTTP requests/minute --http-rate-per-minute THREADKEEPER_HTTP_RATE_PER_MINUTE httpRatePerMinute 120
MCP HTTP body bytes --http-body-bytes THREADKEEPER_HTTP_BODY_BYTES httpBodyBytes 1048576
MCP idle session --http-session-minutes THREADKEEPER_HTTP_SESSION_MINUTES httpSessionMinutes 30

Retrieval weights use --score-semantic, --score-keyword, --score-recency, --score-importance, and --score-confidence; matching environment variables are THREADKEEPER_SCORE_SEMANTIC, THREADKEEPER_SCORE_KEYWORD, THREADKEEPER_SCORE_RECENCY, THREADKEEPER_SCORE_IMPORTANCE, and THREADKEEPER_SCORE_CONFIDENCE.

The configuration file is ThreadKeeper/config.json inside the same OS user configuration directory used for the default database. A complete example:

{
  "databasePath": "/absolute/path/to/threadkeeper.db",
  "timeZone": "Asia/Kolkata",
  "embeddingEndpoint": "http://127.0.0.1:11434",
  "embeddingModel": "nomic-embed-text",
  "embeddingDimensions": 768,
  "candidateEndpoint": "http://127.0.0.1:11434",
  "candidateModel": "qwen3:8b",
  "candidateBatchSize": 64,
  "candidateAuto": false,
  "candidateIntervalMinutes": 60,
  "exportDirectory": "/absolute/path/to/threadkeeper-exports",
  "backupRetention": 3,
  "retrievalWeights": {
    "semantic": 0.45,
    "keyword": 0.25,
    "recency": 0.10,
    "importance": 0.10,
    "confidence": 0.10
  },
  "logLevel": "info",
  "logFile": "/absolute/path/to/threadkeeper.log",
  "maxConcurrency": 4,
  "profiles": ["core", "memory_intelligence", "review"],
  "daemonPollSeconds": 30,
  "daemonGraceMinutes": 1440,
  "dashboardPort": 0,
  "httpAddress": "127.0.0.1",
  "httpPort": 8787,
  "httpTokenFile": "/absolute/private/path/threadkeeper-http.token",
  "httpMaxConnections": 32,
  "httpRatePerMinute": 120,
  "httpBodyBytes": 1048576,
  "httpSessionMinutes": 30,
  "pendingCandidateDays": 90,
  "rejectedCandidateDays": 30,
  "extractionInputDays": 30,
  "activityEventDays": 180,
  "retrievalDetailDays": 30
}

Retrieval weights must be non-negative, total exactly 1 within floating-point tolerance, and leave at least one non-semantic signal available for keyword-only operation. Unknown config keys are rejected.

threadkeeper config-show prints the effective feature, provider, retention, daemon, HTTP, and limit settings as JSON for support; threadkeeper remote config-show does the same for the remote profile. Database/export/log/token paths, provider endpoints, identity values, and all secrets are omitted or marked redacted.

9. Optional hybrid memory retrieval

ThreadKeeper works fully with SQLite FTS5 and no embedding service. To add hybrid retrieval, configure all three values for an Ollama-compatible endpoint:

{
  "command": "/absolute/path/to/threadkeeper",
  "args": [
    "serve",
    "--embedding-endpoint", "http://127.0.0.1:11434",
    "--embedding-model", "nomic-embed-text",
    "--embedding-dimensions", "768"
  ]
}

The configured dimensions must match the model's actual vector size and are bounded from 1 to 65,536. Provider URLs cannot contain userinfo, query-string credentials, or fragments. The endpoint stays local unless you explicitly point it elsewhere. ThreadKeeper does not accept API keys in config. Rebuild derived vectors after changing the model:

./threadkeeper reindex --embeddings \
  --embedding-endpoint http://127.0.0.1:11434 \
  --embedding-model nomic-embed-text \
  --embedding-dimensions 768

Embedding vectors are derived data and are excluded from normal exports.

10. V1.1 local intelligence and operations

Enable the additive memory/review tools without changing the 20-tool core:

./threadkeeper serve --profiles core,memory_intelligence,review

Candidate extraction is manual unless scheduling is explicitly enabled. It reads only eligible activity and inbox items marked candidateEligible, sends bounded safe summaries to the configured extractor, validates structured output, and creates proposals—not memories:

./threadkeeper extract-candidates \
  --candidate-endpoint http://127.0.0.1:11434 \
  --candidate-model qwen3:8b

Use memory_candidate_list and memory_candidate_review to inspect evidence and approve, edit, reject, defer, or resolve conflicts. Merges require memory_merge_preview followed by exact confirmation. The weekly_review tool and daily_review/weekly_review MCP prompts are deterministic and read-only.

Copy-paste V1.1 prompts (replace values in <angle brackets>):

Tool Example prompt
memory_candidate_list “Show my pending personal memory candidates, include their evidence, and limit the result to 10.”
memory_candidate_review “Approve memory candidate <candidate-id> because the evidence confirms this is a stable preference.”
memory_merge_preview “Preview merging memories <memory-id-a> and <memory-id-b> into ‘I prefer concise status summaries’; reason: they are duplicates. Do not execute the merge.”
memory_merge “Execute merge preview <preview-token>. I confirm this exact merge.”
memory_feedback “Mark memory <memory-id> from retrieval <retrieval-id> as incorrect; note that the preference is outdated.”
weekly_review “Give me the weekly review ending 2026-07-18 in Asia/Kolkata, compare the previous week, include memory candidates, and omit bookmark backlog.”

Launch the inspector on IPv4 and IPv6 loopback:

./threadkeeper dashboard --dashboard-port 0

The command prints a one-time launch token to stderr. Paste it into the local unlock screen; it is exchanged for a short-lived HttpOnly session and is never placed in a URL. The inspector provides masked memory/provenance views, candidate review, retrieval score diagnostics, merge/retention previews, embedding generations, restore verification, jobs, audit, and system status.

Run reminders in the foreground or install the documented macOS user agent:

./threadkeeper daemon status
./threadkeeper daemon run

See reminder daemon on macOS. The daemon refuses missing, unmigrated, or checksum-changed databases and never applies a migration.

Retention is always previewed and exact-token confirmed:

./threadkeeper retention-preview
./threadkeeper retention-execute --preview-token <preview-uuid> --confirmation

V2A optional modules

Enable only the domains you want. For example:

./threadkeeper doctor --profiles core,reading,habits,checklists
./threadkeeper serve --profiles core,reading,habits,checklists

Available profiles are reading, habits, checklists, shopping, locations, and intelligence. The first doctor or serve with a profile takes an online backup and applies only that module's seed-free migration. Removing a profile hides its tools and jobs but preserves its tables and data. Run the same profile set for daemon after migration; the daemon refuses to apply migrations itself.

Copy-paste V2A prompts (replace values in <angle brackets>):

Tool Example prompt
bookmark_save “Save https://example.com/sqlite-notes to my unread reading queue for project alpha with tag database; do not fetch metadata.”
bookmark_search “Find unread bookmarks about SQLite tagged database in project alpha.”
bookmark_update “Mark bookmark <bookmark-id> as read and note ‘Useful migration checklist’.”
habit_create “Create a daily boolean habit named ‘Write project notes’ in Asia/Kolkata with target 1, starting 2026-07-18.”
habit_log “Log habit <habit-id> as completed with value 1 for local date 2026-07-18.”
habit_summary “Summarize habit <habit-id> from 2026-07-01 through 2026-07-31, including streaks but not individual logs.”
checklist_create “Create a checklist named ‘Release ThreadKeeper’ with required items keyed run-tests, build-binary, and verify-backup, in that order.”
checklist_start “Start checklist <checklist-id> with title ‘ThreadKeeper 2.0 release’ for project alpha.”
checklist_update “Complete item run-tests in checklist run <run-id> with note ‘All tests passed’.”
checklist_status “Show the current status and items for checklist run <run-id>.”
shopping_update “Add 2 kilograms of rice to my Groceries list, category pantry.”
shopping_list “Show active items on my Groceries list grouped by category.”
item_location_update “Save item ‘Passport’ at location ‘Home / Office / Locked drawer’ with note ‘Blue folder’.”
item_location_find “Where did I last report the passport? Include its location history.”
productivity_insights “Show evidence-backed work-pattern and estimate-calibration insights for project alpha from 2026-06-01 through 2026-07-18, using at least 10 observations.”

Bookmark saving performs no network request by default. fetchMetadata: true queues a background fetch for threadkeeper daemon run. The worker pins a validated public DNS answer, revalidates every redirect, rejects private, loopback, link-local, carrier-grade NAT, and metadata targets, and accepts at most 1 MiB of HTML within ten seconds. It stores selected inert metadata, never page bodies or executable content.

Daily and weekly review include enabled habit, active-checklist, and bounded shopping sections. Bookmark backlog appears only with includeBookmarkBacklog: true; physical-item locations never appear in review. The read-only productivity_insights tool requires at least ten observations for work-pattern and estimate-calibration output.

11. Maintenance and recovery

Health check

./threadkeeper doctor --db /absolute/path/to/threadkeeper.db

Export

The output must be a new absolute file inside the allowed export directory:

./threadkeeper export \
  --db /absolute/path/to/threadkeeper.db \
  --format json \
  --export-dir /absolute/path/to/exports \
  --output /absolute/path/to/exports/threadkeeper.json

./threadkeeper export \
  --db /absolute/path/to/threadkeeper.db \
  --format ndjson \
  --export-dir /absolute/path/to/exports \
  --output /absolute/path/to/exports/threadkeeper.ndjson

Exports include canonical operational records, active and superseded memories, provenance, tags, schema version, and separate checksummed streams for installed module records. They exclude fetched page bodies, module job leases, vectors, idempotency rows, provider payloads, and raw audit data.

Backup

./threadkeeper backup \
  --db /absolute/path/to/threadkeeper.db \
  --export-dir /absolute/path/to/backups \
  --output /absolute/path/to/backups/threadkeeper-backup.db

Backup uses SQLite's online backup API. See backup and recovery before replacing a database. Every CLI backup is copied to an isolated temporary restore, opened against the exact migration set, and checked for SQLite integrity and foreign-key violations before success is reported.

Rebuild indexes

./threadkeeper reindex --db /absolute/path/to/threadkeeper.db --fts

Add --embeddings and the provider settings to rebuild vectors. Reindexing changes only derived indexes, not canonical records.

Inspect content-free traces

./threadkeeper traces --db /absolute/path/to/threadkeeper.db --limit 25

Traces contain request IDs, tool names, input hashes, entity IDs, status, error codes, durations, retrieval mode, and result counts. They do not contain raw tool input or memory content.

12. Troubleshooting

The client does not show ThreadKeeper

  • Use an absolute binary path.
  • Confirm the binary is executable.
  • Run doctor with the same arguments used by the client.
  • Validate the client configuration as JSON and restart the client.
  • Check stderr or the configured JSON log file.

INVALID_ARGUMENTS

The call failed its JSON Schema contract, often because of an unknown field, invalid UUID, timestamp without an offset, invalid project slug, or value over a documented limit. Let the client refresh tools/list and retry with the declared schema.

INVALID_ARGUMENT

The JSON shape was valid but a domain rule failed, such as blank text, reversed time bounds, or an invalid state transition.

ACTIVE_FOCUS_SESSION

Only one focus session may be active. End the returned session ID before starting another.

IDEMPOTENCY_CONFLICT

An idempotency key was reused for the same tool with different arguments. Reuse the key only for an exact retry, or send a new key for a new operation.

PROHIBITED_SECRET

The memory resembles authentication material. Store it in a password manager, not ThreadKeeper.

EMBEDDING_FAILED

Check that the endpoint is reachable, the model is installed, and the configured dimensions match. Remove embedding configuration to return to keyword-only retrieval.

A reminder did not display an OS notification

Run threadkeeper daemon status against the same database. On macOS, verify the notification permission, LaunchAgent state, missed-reminder grace, and daemon stderr. The stdio server does not deliver OS notifications by itself.

The server exits without an error

Normal stdio servers exit when their client closes stdin. The MCP client should launch it again when needed.

13. Privacy and operating limits

  • Canonical data remains in the configured local SQLite database.
  • Outbound network access occurs only for explicitly configured embedding or candidate providers and opt-in bookmark metadata fetches. Local HTTP remains on the loopback interface.
  • Logs and traces contain metadata and hashes, not raw inputs.
  • Normal resources exclude sensitive memories.
  • The database is not application-encrypted; use OS disk encryption and account security.
  • V2B is single-user and local-only: no non-loopback HTTP, accounts, OAuth, cloud sync, or calendar/email integration. Both HTTP listeners bind loopback and use distinct credentials.
  • Reminder recurrence supports none, daily, and weekly rules. New reminders may carry an IANA zone so local wall time survives daylight-saving changes; old fixed-offset reminders remain compatible.

14. Demo and development checks

Run the complete cross-session demo against a new database path:

bash scripts/demo.sh ./threadkeeper /tmp/threadkeeper-demo.db

It captures an idea, creates and completes a task, runs focus, saves context, records a decision, stores and recalls memory in a new process, corrects and forgets memory, and prints content-free traces.

Release checks:

go test ./...
go vet ./...
go test -race ./...
go run ./cmd/eval

For architecture, protocol details, the memory model, security boundaries, and release evidence, continue with architecture, protocol, memory model, threat model, V1 acceptance, and V1.1 acceptance.