cd /news/ai-tools/pi-asynchronous-exit-summaries · home topics ai-tools article
[ARTICLE · art-85809] src=perrotta.dev ↗ pub= topic=ai-tools verified=true sentiment=· neutral

pi: asynchronous exit summaries

Pi, a terminal-based AI assistant, now exits instantly on Ctrl+D instead of waiting several seconds for a session summary, after developer Thiago Perrotta forked the pi-memory package into pi-memory-async. The fix writes a durable JSON job synchronously during shutdown and processes it asynchronously in the next session, eliminating the blocking LLM request and qmd update. The change preserves the original daily log entry while keeping the upstream package intact.

read1 min views2 publishedJul 27, 2026

Problem statement: ctrl+d

in pi took several seconds to quit.

The culprit was pi-memory’s

session_shutdown

handler. It sent one last LLM request to summarize the session, wrote its answer to the daily log, then ran qmd update

. Pi awaits all shutdown handlers, correctly, so quitting waited for everything:

pi.on("session_shutdown", async (event, ctx) => {
  const result = await generateExitSummary(ctx);
  fs.writeFileSync(filePath, entry, "utf-8");
  await runQmdUpdateNow();
});

Making that promise fire-and-forget would not work: Pi exits immediately after shutdown, and either the in-flight request keeps Node alive or gets killed before it can write anything.

Instead, I made the shutdown path write a durable job, synchronously:

const job: ExitSummaryJob = {
  version: 1,
  id: randomUUID(),
  createdAt: new Date().toISOString(),
  date: todayStr(),
  reason,
  sessionId: shortSessionId(ctx.sessionManager.getSessionId()),
  conversationText: truncated.text,
  truncated: truncated.truncated,
  totalChars: truncated.totalChars,
};

const jobPath = path.join(
  EXIT_SUMMARY_JOBS_DIR,
  `${job.createdAt.replace(/[:.]/g, "-")}-${job.id}.json`,
);
fs.writeFileSync(jobPath, `${JSON.stringify(job)}\n`, { encoding: "utf-8", flag: "wx" });

The next interactive session starts an unref’ed worker. It atomically renames one job to claim it, generates summary with active model, writes it back to original day’s daily log, and deletes job. Failed jobs return to queue. A stale claimed job retries after ten minutes.

I kept upstream package intact by replacing it with a local package, effectively forking it:

% pi remove npm:pi-memory
Removed npm:pi-memory
% pi install ~/.pi/agent/local/pi-memory-async
Installed /Users/thiago.perrotta/.pi/agent/local/pi-memory-async
% pi list
User packages:
  local/pi-memory-async
    /Users/thiago.perrotta/.pi/agent/local/pi-memory-async

Jobs live in ~/.pi/agent/memory/exit-summary-jobs/

. ctrl+d

only writes one JSON file now; summary happens during next session, without blocking exits.

Source code: pi-memory-async.

🤖 *Drafted with *

/bloggify

.— § —

Reply via [email](mailto:serendipity@perrotta.dev?subject=Reply to: pi: asynchronous exit summaries)

── more in #ai-tools 4 stories · sorted by recency
── more on @pi 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/pi-asynchronous-exit…] indexed:0 read:1min 2026-07-27 ·