GhostPaw

@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.

A ghost paw drawn in cyan light pressing a glowing hexagonal exclamation mark, violet sparks around it.

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.

Today: Sat 24 Oct

! 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 #1

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

Hexagon nodes joined by lines of light: two lit cyan, one locked in violet, the rest faint.
## 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 listBlockedQuests until its prerequisite finishes with success.
Doing
startQuest sets a start time. The marker turns to "?".
Done
finishQuest with an outcome string. abandonQuest records a failure, also with a reason.
The note in the margin
A rumor. captureRumor holds it until you know what the work is, then settleRumor turns 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 scheduledStartAt and scheduledEndAt. Missed windows have their own list.
Not before
notBeforeAt keeps 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.