Change what Pepper decides
What leads your brief and what counts as a task are the choices people most want to make their own. Try a setting first. Use code only when a setting can't do what you need.
npm run pepper -- settings # everything, with its value
npm run pepper -- settings briefMaxItems 8 # at most this many in Yours, and this many in Needs you
npm run pepper -- settings briefWeights '{"dueToday":5,"dueSoon":2,"vip":9,"promise":1,"agePerDay":0.2}'
npm run pepper -- settings taskCapture prefixed # only lines starting "todo:", "task:" or "remind me:" become tasks
npm run pepper -- settings taskNudges false # no message when a task comes due
npm run pepper -- settings taskCheckInMax 0 # no check-in in the evening briefbriefWeights is what puts an item at the top. An item earns points for being overdue or due within a day, for being due
within three days, for coming from a VIP, for being a promise you made, and a little for each day it has waited, up to
two weeks. Raise vip and VIP items climb. Mark a person with /vip <name> in Telegram.
A part, your own folder in src/parts/ (see Make Pepper yours), can replace either decision: what leads
your brief, or what counts as a task. Only one part may replace each decision, and one part may replace both, as the
example below does. The code that replaces a decision is called a policy. A policy stays small on purpose: it gets the
facts and returns an answer. It is given no database, keys or way to send messages, and it shouldn't import them.
Pepper's own code keeps the rest: the numbering, so a reply like "2 done" always lands on the right item; the minimum
confidence and the duplicate check on new tasks; and delivery.
import type { Part } from "../contract.js";
const FAMILY = new Set(["Mina Holt", "Tavi Reed"]);
export const part: Part = {
name: "family-first",
about: "family first in Needs you; task nudges wait until 16:00 UTC",
briefPolicy: {
pick: (items, { max }) => [...items].sort((a, b) => Number(FAMILY.has(b.person ?? "")) - Number(FAMILY.has(a.person ?? ""))).slice(0, max),
},
taskPolicy: {
looksLikeTask: (text, shipped) => shipped && !/^fyi\b/i.test(text),
keep: (draft) => draft.confidence >= 0.7,
nudge: (task, at) => at.getUTCHours() >= 16,
},
};Save it as src/parts/family-first/index.ts, then add one line to src/parts/mine.ts:
"family-first": () => import("./family-first/index.js"),.
pick gets the open items you owe that Pepper found in your chats, ordered by your weights with the best first. The
tasks you gave Pepper yourself, what you're waiting on from others and the evening check-ins are not in it. Return the
ones you want, in your order. Leave one out and it stays off the brief but still shows on the dashboard.
looksLikeTask runs on each message you send Pepper, before the model is asked; shipped is Pepper's own answer, for
you to build on. looksLikeTask is not used while taskCapture is prefixed, so set taskCapture back to anything
first. keep sees each task the model drafted, with its confidence from 0 to 1, once it has passed Pepper's own
minimum. nudge is asked when a task comes due, with the time in UTC; return false to leave it for a later check.
If a policy fails, the brief still goes out in Pepper's usual order and says so at the foot, and tasks fall back to
Pepper's usual rules. Once your policy makes a choice, later changes to how Pepper makes that same choice reach you
only through the shipped answer and the order your policy builds on. Every other fix still arrives.
Add a source of messages
A source brings messages into Pepper. Once they are in Pepper's database (the store), the brief, Ask and the dashboard read them like any others, and they go through the same extraction as the chats…
Overview
A connection is one link between Pepper and something outside it, like Beeper or the Telegram bot. Each one that's built has a secret, the token or saved sign-in that lets Pepper in, and a health…