Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
This course is not a grab bag of tricks. It's built around two design patterns that recur through every module, and if you internalize them here you'll know why each subsequent module makes the choices it does. The grace window gates OUTBOUND actions — the bot drafts, notifies you, waits N minutes, then sends unless you override. This is how the bot earns the right to speak for you: not by asking permission every time (that's just a slow email client) and not by never asking (that's a lawsuit), but by giving you a bounded window to catch mistakes. The verify-before-use pattern gates KNOWLEDGE entering the bot's authoritative store — the bot researches something, drafts a high-value answer in your voice, and you approve, edit, or reject before it becomes citable memory. These two patterns generalize: grace-window for anything the bot does to the world, verify-before-use for anything the bot will remember and repeat later. The rest of the course is instantiating them in specific domains.
Pseudocode-shape for both patterns as reusable primitives. The grace window is a scheduled job with an override channel; verify-before-use is an approval workflow that mutates memory only on explicit accept.
// The two patterns as small reusable primitives.
// -- 1) Grace window: schedule a send, allow override during the window.
type GraceJob = {
id: string;
draft: string;
target: string;
scheduledFor: Date;
status: "pending" | "sent" | "canceled" | "edited";
};
const queue = new Map<string, GraceJob>();
function scheduleGraceSend(job: Omit<GraceJob, "id" | "status">) {
const id = crypto.randomUUID();
const fullJob: GraceJob = { ...job, id, status: "pending" };
queue.set(id, fullJob);
const delayMs = job.scheduledFor.getTime() - Date.now();
setTimeout(async () => {
const current = queue.get(id);
if (!current || current.status !== "pending") return; // overridden
await sendMessage(current.target, current.draft);
current.status = "sent";
}, delayMs);
return id;
}
function overrideGraceJob(id: string, action: "cancel" | "edit", newDraft?: string) {
const job = queue.get(id);
if (!job || job.status !== "pending") throw new Error("Not overridable");
if (action === "cancel") job.status = "canceled";
if (action === "edit" && newDraft) { job.draft = newDraft; job.status = "edited"; }
}
// -- 2) Verify-before-use: mark memory authoritative only after explicit accept.
type Memory = {
id: string;
content: string;
source: string;
verified: boolean;
verifiedAt?: Date;
};
async function proposeMemory(content: string, source: string): Promise<Memory> {
const mem: Memory = { id: crypto.randomUUID(), content, source, verified: false };
await db.memories.insert(mem);
await notifyForApproval(mem);
return mem;
}
async function acceptMemory(id: string, edited?: string) {
await db.memories.update(id, {
content: edited ?? undefined,
verified: true,
verifiedAt: new Date(),
});
}
// Retrieval later prefers verified memory; falls back to unverified with a hedge.
async function retrieve(query: string) {
const results = await db.memories.search(query);
return results.map(r => ({
...r,
confidence: r.verified ? "high" : "hedge",
}));
}
async function sendMessage(target: string, draft: string): Promise<void> {}
async function notifyForApproval(mem: Memory): Promise<void> {}
declare const db: any;node main.js