Hey Pepper

Your AI chief of staffDocs

Hey Pepper
Make it yours

Keep your own data in a table

A part (your own folder in src/parts/, see Make Pepper yours) can keep its own tables in Pepper's database. This garden part records which beds were watered, and its check counts the beds when you run npm run doctor.

import { db } from "../../store/db.js";
import type { Part } from "../contract.js";

export const part: Part = {
  name: "garden",
  about: "which beds were watered",
  migrations: [
    { v: 1, name: "beds", sql: "CREATE TABLE garden_beds(name TEXT PRIMARY KEY, watered TEXT);" },
  ],
  checks: [{
    name: "garden",
    run: async () => `${(db.prepare("SELECT COUNT(*) n FROM garden_beds").get() as { n: number }).n} beds`,
  }],
};

Save it as src/parts/garden/index.ts and add garden: () => import("./garden/index.js"), to src/parts/mine.ts.

A migration is the SQL that creates or changes your tables. Every table and index name has to start with the part's name and an underscore, with any hyphen in the name written as an underscore (family-first makes family_first_...), and a migration may touch only tables and indexes with that prefix; Pepper refuses anything else, triggers and views included. Give each migration a higher v than the one before, starting at 1, and list them in that order: they run once each, in the order listed, the next time Pepper starts with the part on. To change a table, add a new migration, never edit an old one.

/forget deletes the records it knows about (what it leaves is on People), but on its own it can't know about your table. If your table holds anything about a person, say in the part's README that /forget won't delete that data, so the person running this Pepper knows.

Mark the row with cite, as this books part does when it saves a title from a message m, and /forget deletes the row along with the message, whatever your table holds:

import { cite } from "../contract.js";

const r = db.prepare("INSERT INTO books_mentions(title) VALUES(?)").run(title);
cite("books", "books_mentions", r.lastInsertRowid, [{ source: "beeper", message_id: m.message_id }]);

source and message_id are the message's own columns in the messages table; beeper is the source most chats arrive through. cite needs the row's rowid, so don't make the table WITHOUT ROWID. If a cited row can't be deleted, /forget stops without deleting anything, so Pepper never says "forgotten" while the data is still there.