@ghostpaw/questlog 0.5.1
Your agent said it was done. Was it?
An agent that ticks its own box gets to grade its own homework, so questlog makes it write the homework down: no quest is done without an outcome, and work that waits on other work stays blocked until that work is done.
Install
Try to finish a quest Read the source on GitHub
Free and MIT licensed for Node.js 24 or newer, with zero runtime dependencies and the tables in a SQLite database you open.

0runtime dependencies
Three quests from the README
Try to finish one with the outcome left blank.
This is the Vendor Renewal example from the README, replayed in your browser from a real run: we made the same calls against questlog 0.5.1 on 2026-10-24 with a fixed clock, and every error and every list you see here is what came back, so press Start, leave the outcome empty, press Finish, then finish #1 for real and watch #3, and jump a week to see the due date go overdue. The live demo runs the library itself.
! available #1
Collect redlines
Obtain the latest legal markup.
! available #2
Review pricing delta
Compare current vs. proposed cost.
? incomplete #3
Obtain finance approval
Sign-off on the new terms. Due Thu 29 Oct.
blocked by #1overdue
What your code sees
read.listAvailableQuests(db);
// [2, 1]
read.listBlockedQuests(db);
// [3]
read.listDueSoonQuests(db, 7 * DAY);
// [3]
A done quest stays done, and a second finishQuest throws "Resolved quests cannot be resolved again."
Blocked is a view, not a lock: questlog leaves #3 off the available list, but a direct startQuest call on it would still go through.
Where your TODO.md headings go
## Todo
- Collect redlines
- Obtain finance approval (after redlines)
## Doing
- Review pricing delta
## Done
- Sent the renewal notice
- Todo
- Open quests. The ones nothing waits on carry "!" and show up in
listAvailableQuests. - (after …)
- An unlock. The quest sits in
listBlockedQuestsuntil its prerequisite finishes with success. - Doing
startQuestsets a start time. The marker turns to "?".- Done
finishQuestwith an outcome string.abandonQuestrecords a failure, also with a reason.- The note in the margin
- A rumor.
captureRumorholds it until you know what the work is, thensettleRumorturns it into a questline and quests.
None of these states is stored.
questlog works them out from the timestamps and the unlocks every time you read. A list cannot go stale, because there is no list.
Deadlines, appointments, repeats
Same table, same quest, and the fields decide what it is.
- A deadline
- A quest with
dueAt. It moves from due soon to overdue without anyone touching it. - An appointment
- A quest with
scheduledStartAtandscheduledEndAt. Missed windows have their own list. - Not before
notBeforeAtkeeps a quest off the available list until that date.- Every Monday
- A repeatable quest with a standard RRULE string spawns a fresh quest each time it comes due.
If agent task trackers have burned you
Some agent issue trackers run to hundreds of thousands of lines, and people went back to a markdown file, which is fair enough.
- One package, one bundled file, no runtime dependencies. The numbers are below.
- An outcome is text. It records what the agent claims; it does not run your tests.
- No scheduler and no server. Your code or your agent harness decides when to read.
- No MCP server in the package. It ships twelve tools with JSON Schemas for your own harness.
- Node.js 24 or newer, because it uses the built-in
node:sqlite.
What it costs to add
- Runtime dependencies
- 0
- Node.js
- 24 or newer (node:sqlite)
- Size of dist/index.js, gzip
- 42.6 KB
- Import time
- about 4.4 ms
- Tests
- 326 passing
- Line coverage
- 96.0%
- Agent tools
- 12
Measured 2026-10-24 on the maintainer's machine with Node.js 24.14.0 against questlog 0.5.1.
Start from the README
import { DatabaseSync } from 'node:sqlite';
import { initQuestlogTables, read, write } from '@ghostpaw/questlog';
const db = new DatabaseSync(':memory:');
initQuestlogTables(db);
const rumor = write.captureRumor(db, {
title: 'Legal says the vendor terms changed',
details: 'Need to understand pricing delta and termination clause.',
});
write.settleRumor(db, rumor.id, {
settledAt: Date.now(),
questline: {
title: 'Vendor Renewal',
description: 'Commercial, legal, and approval work.',
},
quests: [
{ title: 'Collect redlines', objective: 'Obtain the latest legal markup.' },
{ title: 'Review pricing delta', objective: 'Compare current vs. proposed cost.' },
],
});
const available = read.listAvailableQuests(db);
const dueSoon = read.listDueSoonQuests(db, 7 * 24 * 60 * 60 * 1000);
Agents get twelve tools, among them review_questlog, capture_rumor, shape_work, run_quest and reward_work, and each one returns success, no_op, needs_clarification or error with a hint for the next step.