@grundlag/extension-todo (0.1.0)
Installation
@grundlag:registry=npm config set @grundlag:registry=npm install @grundlag/extension-todo@0.1.0"@grundlag/extension-todo": "0.1.0"About this package
@grundlag/extension-todo
Todos with GTD-style contexts, and the reference for how grundlag extensions are built.
import { todoExtension } from '@grundlag/extension-todo';
const uninstall = kernel.install(todoExtension); // registers everything or nothing; uninstall() unregisters it, data stays
What it contributes
| Kernel concept | Contribution |
|---|---|
| Domain | todo, on everything below, so one policy statement (domain:todo) covers the extension |
| Indexed resource | todo.item, canonical: the index is where todos live; the kernel exposes it as a resource |
| Index type | task, generic on purpose so other task sources can share it ({ type: 'task' } spans them) |
| Database | todo, the extension's own, holding contexts |
| Resource | todo.context, a plain resource over that database |
| Tools | todo.create/update/complete/reopen/delete/find, todo.context.create/list/delete |
| Events | todo.created/updated/completed/reopened/deleted, filterable by tags and priority |
| Knowledge | todo.usage (ambient), todo.review (skill) |
Layout
Everything lives in one module, src/todo/, with todo.ts as its public API:
todo.schemas.ts: Zod schemas and types. Everything handed out is JSON, so one schema serves tools and events.todo.items.ts/todo.database.ts: storage (the index definition, the extension database).todo.service.ts/todo.contexts.ts: behaviour, as service classes resolved fromServices.todo.tools.ts,todo.events.ts,todo.knowledge.ts: thin definitions on top of the services.todo.extension.ts: the extension definition, listing everything it contributes; the kernel does the registering.
Import z, sql and the Kysely types from @grundlag/kernel too; the kernel is a peer dependency, so there is only
one copy of each.
Testing
todo.testing.ts builds a real kernel with the extension installed, through createTestHost from
@grundlag/kernel/testing (in-memory PGlite, the fake embedder), torn down when the test finishes; errors the kernel
reports (a failing subscriber, say) land in errors.
runTool calls a tool the way a host would, through kernel.tools.run under an optional policy, with input and
output crossing a JSON boundary.
const { kernel } = createTodoKernel();
const todo = await runTool(kernel, createTodoTool, { title: 'Call mum' });
await kernel.index.embedPending(); // before semantic search
Dependencies
Development dependencies
| ID | Version |
|---|---|
| @electric-sql/pglite | ^0.5.8 |
| @electric-sql/pglite-pgvector | ^0.0.9 |
| @grundlag/config | 0.1.0 |
| @grundlag/kernel | 0.1.0 |
| @types/node | ^24.0.3 |
| typescript | ^5.9.2 |
| vitest | ^3.2.3 |
Peer dependencies
| ID | Version |
|---|---|
| @grundlag/kernel | ^0.1.0 |