
GhostPaw Questlog
io.github.GhostPawJSPublished by GitHub account GhostPawJSv0.13.0Updated Nov 5, 2026
Local tasks, calendar commitments, and recurring work.
Overview
Local SQLite-backed task and calendar server that lets an assistant capture, plan, run and finish quests with written outcomes.
- What you can do
- Search and review the log: full-text search across entities and filtered views such as available, overdue or due soon, plus detailed inspection of any item
- Capture and shape work: record incoming rumors, create quests and questlines, and settle rumors into structured work
- Plan and run quests: set due, defer and scheduled windows, start, finish, abandon or log effort, with unlock prerequisites enforced
- Organize and classify: move quests between questlines, manage recurring templates, apply tags, attach or claim rewards, archive or soft-delete
- Maintain recurring work and rewards through dedicated tools for repeatable templates and reward lifecycles
- When to use it
- Useful when you want an assistant to keep a persistent personal task and calendar log on your own machine, turning conversations into tracked commitments that only close with a recorded outcome, including recurring work and prerequisite chains.
- Requirements
- Runs as a local stdio process, either the release binary or the npm package (Node 24+). Data is stored in a SQLite file at ~/.ghostpaw/questlog.db by default, overridable with the GHOSTPAW_QUESTLOG_DB environment variable or a --db path. No account or API key is declared.
Installation
In SourceWeft
- Open GhostPaw Questlog in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
[GhostPaw questlog: Your agent said it was done. Was it?]
@ghostpaw/questlog
[npm] [CI] [site] [runtime deps] [MCP Registry] [node] [license]
Agent tasks as quests that finish only with a written outcome.
A unified task and calendar model for Node.js, built on SQLite.
Questlog treats tasks, events, deadlines, recurring commitments, and loose intake as one coherent data model instead of separate systems. It ships as a single prebundled blob with zero runtime dependencies, designed for two audiences at once: human developers working directly in code, and LLM agents operating through a structured tool facade.
MCP server
Every client below starts the same stdio server: ghostpaw-questlog mcp.
For npm-based environments, use npx -y @ghostpaw/questlog mcp (Node 24+).
Data lives in ~/.ghostpaw/questlog.db unless the GHOSTPAW_QUESTLOG_DB
environment variable (absolute path) or --db <path> says otherwise.
Claude Code
or as a plugin, which also installs the skill:
Codex CLI (~/.codex/config.toml)
Cursor (.cursor/mcp.json), Claude Desktop (claude_desktop_config.json)
or a project .mcp.json:
Claude Desktop users can also install server.mcpb from the
latest GitHub release.
A Dockerfile is included for container hosts:
docker build -t ghostpaw-questlog . && docker run -i --rm -v questlog:/data ghostpaw-questlog.
The server speaks MCP 2026-07-28 (stateless, server/discover) and the
initialize-based revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05.
CLI
Install the release binary for ghostpaw-questlog (questlog is an alias).
add accepts comma-separated tags (--tag a,b) and repeated --tag flags, --objective (defaults to the title),
--questline <id>, and --due as YYYY-MM-DD, DD.MM.YYYY, today, tomorrow,
+3d, an ISO date-time with timezone, or milliseconds since epoch. Date-only
values use local end of day.
--objective is the one flag that reads a file: @path, @- for stdin, and
@@text for a literal @text (help marks it (@file, @- stdin, @@ literal @)). Every
other value, including titles, --outcome and per-tool flags, is literal.
list --tag work --tag urgent requires all tags and supports quest views; unknown tags return an empty list.
list defaults to available quests; list --help lists all supported views.
Its --limit and --offset paginate text and JSON. JSON data includes total, offset, limit, and hasMore.
search --fts enables raw FTS5 syntax; search text is literal by default.
search --limit caps matches in both formats. show prints full quest detail.
Lists show local due dates, overdue markers, and recorded outcomes. Plain JSON
adds ISO UTC siblings for numeric timestamp fields ending in At.
done stores --outcome with the finished quest; without it the command asks for one and exits 3.
Revise a title with questlog quest revise <id> --title "New title".
Count filtered quests with questlog list --count-by tag|prefix.
Find similar open quest titles with questlog list --view quests.duplicates.
Commands print text by default, including hooks, delivery views and each watch tick; call and direct tool commands return the raw tool result as JSON. Use --json for the full tool result
and --compact for compact JSON. --db path works before or after the command.
Each command accepts --help. Exit codes are 0 for success, 1 for invalid input
or a tool error, 2 for usage errors, and 3 when clarification is needed or a quest, delivery, or hook target is not found.
An empty hook list prints No hooks ([] with --json). Delivery text timestamps use local time; JSON retains UTC/epoch timestamps. hook label names the database, not an individual target.
questlog skill --short prints the compact cheat sheet; questlog skill --list lists guides.
ISO date-times without a zone (for example 2026-10-29T09:00) use the local time zone.
The call command and the per-tool form still reach every tool and parameter:
questlog mcp starts the stdio server.
The default database is ~/.ghostpaw/questlog.db. Override it with --db <path>
or GHOSTPAW_QUESTLOG_DB; top-level help shows the selected path. New database
files are reported on stderr. The npm entry requires Node 24+ and exits 2 with
an installation hint on older Node versions, including for help and version.
Agent Skill
SKILL.md (repo root) and skills/questlog/SKILL.md follow the
Agent Skills format and ship in the npm package.
Copy skills/questlog/ into your agent's skills folder, or print it:
Install
Release binary (default)
Each line downloads the latest release asset, checks it against the release’s SHA256SUMS and installs it on the PATH (~/.local/bin on Linux/macOS; the Windows script adds its folder to the user PATH).
These lines never edit ~/.profile or other shell startup files: export PATH applies to the current shell only. To keep it in new shells, use the ~/.profile line below.
linux-x64:
linux-arm64:
darwin-arm64:
darwin-x64:
windows-x64 (PowerShell; persistently adds its folder to the user PATH):
Pinned to a release:
Also adding ~/.local/bin to ~/.profile (edits ~/.profile once; skipped if it already mentions ~/.local/bin; zsh login shells read ~/.zprofile instead, so use that file name there):
To skip the persistent Windows user PATH edit (the installer still installs and prints the folder to add):
Scripts that compare versions should use --version --short or --version --json.
Standalone binaries are available from GitHub Releases.
A session with the 0.9.1 linux-x64 binary against a fresh database:
[questlog 0.9.1: --version, three add calls, list, search, done with an outcome, and show]
The same session as an animated GIF.
Other release installers:
For aqua, define a
github_release package in aqua.yaml:
questlog-registry.yaml:
Install scripts verify SHA256SUMS. To verify a downloaded archive's build attestation:
Set GHOSTPAW_VERIFY=attestation for attestation verification in install.sh.
Binaries are unsigned; macOS binaries carry an ad-hoc signature. For a browser
download on macOS, remove quarantine with
xattr -d com.apple.quarantine /path/to/ghostpaw-questlog.
Linux binaries require glibc 2.28+; use npx on Alpine.
See the binary build workflow.
npx / npm (for npm-based environments)
The npm package requires Node 24+:
Library (for harnesses embedding it in code)
See library usage. The library uses built-in node:sqlite with zero runtime dependencies.
Quick Start
Docs
The live demo runs the library in your browser against an in-memory SQLite database. Each view below opens a different part of it:
- Dashboard: open, available, overdue and pending work
- Intake: capture rumors and triage them into quests
- Quests: start, block and finish quests with an outcome
- Planning: questlines and scheduling
- Search: full-text search across the log
The Model
Seven concepts, strict separation of concerns:
The unified model means one entity type covers every temporal intention:
State is derived, not toggled. A quest's availability comes from its lifecycle, timing fields, and unlock graph — computed at read time, never stored as a status flag.
Lifecycle at a glance
Questlog computes WoW-style markers on every read. They change as work moves through its lifecycle:
Intake
Quest progression
Other markers
Marker IDs are semantic strings (attention.available, progress.complete, ...) computed at read time, never stored. The markers namespace maps each to its symbol, color, label, and CSS class for consistent rendering across HTML, TTY, and plain text.
Two Audiences
Human developers
Use the read and write namespaces for direct-code access to every domain operation:
See HUMAN.md for the full human-facing guide with worked examples.
LLM agents
Use the tools, skills, and soul namespaces for a structured runtime surface designed to minimize LLM cognitive load:
Every tool returns a discriminated result with outcome: 'success' | 'no_op' | 'needs_clarification' | 'error', structured entities, next-step hints, and actionable recovery advice. No thrown exceptions to parse, no ambiguous prose.
See LLM.md for the full AI-facing guide covering soul, tools, and skills.
Tools
Twelve tools shaped around operator intent, not raw storage operations:
Each tool exports runtime metadata — name, description, JSON Schema, input descriptions, side-effect level — so agent harnesses can wire them without reading docs.
The run_quest tool refuses to start a quest with unmet unlock prerequisites and returns the blocking quests with inspection hints. Set force: true to start anyway with a warning. The library startQuest function remains permissive.
Key Properties
- Zero runtime dependencies. Only
node:sqlite(built into Node 24+). - Single prebundled blob. One ESM + one CJS entry in
dist/. No subpath exports, no code splitting. - Pure SQLite storage. FTS5 full-text search, CHECK-constrained state transitions, trigger-maintained indexes. Bring your own
DatabaseSyncinstance. - Derived state. Availability, blocking, deferral, overdue, and markers are computed at read time from fields and relationships, never stored as flags.
- Intention-shaped writes.
captureRumor,settleRumor,startQuest,finishQuest,abandonQuest— operations that say what happened, not generic CRUD. - RFC 5545 recurrence. Standard RRULE strings for recurring work. No custom recurrence format.
- WoW-style markers. Semantic marker IDs (
attention.available,progress.complete, ...) computed on every read, renderable to any channel. - Colocated tests. Every non-type module has a colocated
.test.tsfile. The behavior described in docs is backed by executable coverage.
Performance
Measured with npm run bench on Node 24.14.0, Linux, Intel Xeon (shared
cloud vCPU), 10,000 quests in a file-backed database:
The library search returns every match with a highlighted snippet, so a query
that matches the whole log pays for building all of those rows. Cold start
(process spawn to first response, median) is about 30 ms for --version and
the MCP server.
Package Surface
All domain types are also available at the root for TypeScript consumers:
Documentation
Development
The repo is pinned to Node 24.14.0 via .nvmrc / .node-version / .tool-versions / mise.toml / Volta. Use whichever version manager you prefer.
Support
If this package helps your project, consider sponsoring its maintenance:
Webhooks
Configure opt-in outbound wakes with the release binary. No server or scheduler is started. With no targets, tick makes no network calls. Targets and retry state live in the database.
Save the signing secret printed once by hook add (including its --json result).
--secret-stdin reads a supplied secret from standard input; there is no secret flag.
Secrets and custom header values are stored in the database. On POSIX, new database files
and their WAL/SHM siblings use mode 0600, and directories created for them use 0700.
Existing database permissions are preserved; Windows uses its existing access controls.
Prefer --header-stdin for real keys (one Name: value line per header), keeping
values out of shell history and process arguments:
questlog hook add https://example.org/wake --header-stdin < /secure/headers.txt.
Keep that file private (0600 on POSIX). Repeatable --header "Name: value" remains
available, but exposes values in process arguments.
Headers accompany every delivery and test. Header names are shown with values replaced by
***; values are never included in list, show, test, tick, watch, or tool output.
Names must be HTTP tokens; host, content-length, content-type, and x-questlog-*
are reserved (case insensitive). To change headers, remove the hook and add it again.
Use separate invocations for --header-stdin and --secret-stdin.
URL userinfo is rejected; use a custom header or query key instead.
questlog show d_… prints delivery status, attempts, HTTP status, next attempt,
redacted target URL, and event ids; add --json for JSON.
List output redacts URL userinfo and query strings. Removal deletes the target and its deliveries.
A target covers the database unless --tag restricts it to quests with that tag;
rumors have no tags and reach database targets only. --events defaults to all five events.
The label defaults to the database filename without directory or extension (questlog for memory).
Only use labels suitable for disclosure to the receiver.
For cron:
Cron's PATH may need $HOME/.local/bin/questlog tick --db /path/to/quests.db.
watch repeats tick (default 60 seconds, minimum 5), finishing its current tick on SIGINT/SIGTERM.
Tick exits 0 after running even when deliveries need retrying. Dry runs roll back all changes,
including repeatable materialization, and make no network calls.
Events are detected from the model at tick time:
quest.due: an unresolved, undeleted quest reaches its effective due time (owndue_at, otherwise its undeleted questline's due time).quest.overdue: that effective deadline is strictly earlier than now and the quest remains unresolved.quest.unblocked: an unresolved quest is available, all active prerequisites have succeeded or been deleted, and at least one prerequisite succeeded after its unlock was installed. Occurrence time is the latest active prerequisite success or not-before time, whichever is later.repeatable.spawned: a concrete repeatable instance was created; occurrence time is its creation time. Tick first materializes due anchors through the existing spawn operation.rumor.captured: an undeleted rumor was created; occurrence time is its creation time, even if subsequently settled or dismissed.
Each type, entity and occurrence timestamp has a persistent unique event key. Repeated ticks and restarts do not create another occurrence. Changes removed before any tick cannot be reconstructed. Occurrences earlier than target creation are excluded, preventing backlog floods. Tags are evaluated when assigning an event. Already assigned events retain their batch membership.
One POST batch per target per tick contains only identifiers, types, timestamps, and the DB label:
Headers are content-type: application/json, user-agent: questlog/<version>,
x-questlog-delivery: <deliveryId>, x-questlog-timestamp: <unix seconds>, and
x-questlog-signature: sha256=<hex HMAC-SHA256(secret, timestamp + "." + rawBody)>.
No titles, objectives, details, or tag text are sent. hook test sends a logged hook.test
event immediately, ignoring the min gap. Add and test are CLI-only in the tool facade;
manage_hooks supports list, remove, tick (with dry_run), and deliveries.
2xx delivers the batch. Requests time out after 5 seconds. Other responses, timeouts, and network errors retry after 30 seconds, 1 minute, 2 minutes, 4 minutes, and so on, capped at 1 hour, plus less than 1 second jitter. The target's min gap also applies to retries. Eight unsuccessful attempts mark a delivery failed. Retries retain the delivery id and events. Pending batches wait behind retries. Only the last 500 delivered entries per target are kept; pending and failed entries are retained. Transactions and two-minute leases prevent overlapping ticks from claiming the same delivery. A crash after receipt but before recording success can cause another request: receivers must dedupe by delivery id.
Verifying a delivery
Compute HMAC-SHA256 over timestamp + "." + rawBody with the secret and compare in constant
time. Reject timestamps older than 5 minutes (and timestamps too far in the future), then
dedupe on x-questlog-delivery. Use durable deduplication storage in a production receiver.
This 15-line Node example uses an in-memory set:
Repeatables accept an optional IANA time zone, such as Europe/Berlin, via
repeatableQuest.tz in manage_repeatable create input. Zoned RRULEs retain local
wall-clock time across DST. Omitted or null zones keep existing UTC behavior.
Ambiguous local times use the earlier instant; nonexistent times move forward.
The facade accepts action: "revise" (or "update") with
repeatableQuestId and tz; null clears the zone. Existing spawned quests are
unchanged. Invalid zones are rejected; the plain CLI exits 2.
Set GHOSTPAW_OUTPUT=json to select CLI JSON output as with --json.
Other values leave the default output unchanged.
When opening the default database, the CLI prints using default db <path> to stderr. Suppress this notice with --quiet or GHOSTPAW_QUIET=1.
Due selection and consumer claims
questlog due [--within 15m] [--tag work --tag team] [--limit 100] [--json]
selects open overdue/due quests and recurring occurrences through the inclusive
horizon (default 0m). Durations use integer m, h, or d; limits are 1–1000.
Tags require every named tag. JSON data contains items and hasMore.
Each item has kind, key, questId or repeatableId + occurrenceAt,
title, epoch-millisecond dueAt, overdue, and tags. Text prints one line per item: key, due status, local date/time (as in list/show),
then title and space-separated #tags, omitted when empty. For example:
The occurrence example uses Europe/Berlin local time. Recurring occurrences use the stored time zone and due offset (default zero), and retain their occurrence key after materialization. Resolved/deleted instances are excluded.
questlog due --claim worker atomically records consumer-specific claims;
reruns return only unclaimed items. Other consumers are independent.
Release with questlog due --release 12 --claim worker, or
questlog due --release occurrence:3:1792882920000 --claim worker using an item's key.
Release only removes the mark; a subsequent due call selects it again if still open.
Claims on resolved/deleted items need no cleanup.
questlog tick --claim worker [--within 2h] claims up to 100 due items and sends
one quest.due event per new claim through normal webhook batching/retries.
Its payload adds the item fields above and consumer; this opt-in payload includes
titles and tags. Plain tick retains its existing behavior. Dry-run rolls claims back.
The MCP/tool due accepts within, tags, limit, claim, and release;
it is marked as writing state because claim/release persist marks.
Source: README.md at commit 9e02b81
Tools
0Version history
5- v0.13.0LatestNov 5, 2026
- v0.12.0Nov 5, 2026
- v0.11.3Oct 30, 2026
- v0.11.1Oct 29, 2026
- v0.6.2Oct 25, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts