@everme/pi

EverMe long-term memory for the Pi coding agent: profile and recall injection, automatic turn capture, and four memory tools.

Packages

Package details

extensionskill

Install @everme/pi from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@everme/pi
Package
@everme/pi
Version
0.7.2
Published
Sep 22, 2026
Downloads
677/mo · 86/wk
Author
junquan.yao
License
Apache-2.0
Types
extension, skill
Size
43.9 KB
Dependencies
1 dependency · 1 peer
Pi manifest JSON
{
  "skills": [
    "./skills"
  ],
  "extensions": [
    "./src/extension.js"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@everme/pi

EverMe long-term memory for the Pi coding agent: profile and recall injection, automatic turn capture, and four memory tools.

Verified against pi 0.80.10. Requires pi >= 0.80.4 — the agent_settled event this extension uploads on was added in that release.

Install

evercli plugin install pi

That provisions the credentials (~/.pi/agent/everme.env, mode 0600) and runs pi install npm:@everme/pi, which records the package in the packages array of ~/.pi/agent/settings.json. Start a new pi session afterwards.

To install the package without evercli and provide credentials yourself:

pi install npm:@everme/pi
printf 'EVERME_AGENT_ID=agt_...\nEVERME_AGENT_TOKEN=evt_...\n' > ~/.pi/agent/everme.env
chmod 600 ~/.pi/agent/everme.env

/everme prints the status: which agent, which credential file, whether the profile was injected, how many turns were saved, and the last error if any.

What it does

pi event what the extension does
session_start resets per-session state; on resume/reload/fork checks whether this session already carries the profile
before_agent_start injects <everme_profile> (once per session) and <everme_recall> (every turn) as a custom_message — model context, not TUI output
agent_end buffers that run's messages
agent_settled uploads the buffered turn (no flush: the gateway extracts on its own, and waiting for it is ~30x slower)

Memory write tools retain model-authored content as assistant, never as a human statement. mem_save_turn.role remains accepted for compatibility but is ignored. Both write tools require Pi's native session ID; no timestamp-based session is invented. Automatic capture retains actual user message roles.

Tools: mem_search, mem_context, mem_save_fact, mem_save_turn. The everme skill tells the model when to reach for them.

Why the buffer

Automatic and explicit turn writes use task-aware batching, as does cold import. Fitting user tasks keep original tool output. Oversized tasks try 4, 3, then 2 KiB tool-result budgets before semantic splitting; calls, arguments, source ordering, and the existing flush behavior are unchanged.

agent_end is the only event that carries messages, and it can fire several times for one user turn — pi may auto-retry, auto-compact and retry, or run a queued follow-up. agent_settled is the guarantee that nothing more will run automatically, but its payload is empty (verified in pi's own type declarations: { type: "agent_settled" } and nothing else). So the transcript is collected at agent_end and uploaded at agent_settled.

Assistant text and tool-call blocks retain their source order. A single native assistant message can become several gateway messages without changing its timestamp or tool IDs; thinking blocks are excluded. Tool results keep empty text without invented placeholders, and cold-start import does not apply an additional 8000-character tool-result cap. Normal redaction still applies.

Native tool calls require nonblank string IDs and names, and object arguments are JSON-encoded for the gateway. The literal name unknown remains valid. Malformed tool fields are excluded with bounded aggregate diagnostics; IDs are never generated or coerced. A result is excluded with a rejected call only when its native ID uniquely identifies that call. Repeated IDs are not enough to infer ownership. Valid neighboring text and tool blocks keep their order. Cold-start diagnostics are recorded in the conversation's warnings; this does not imply that the CLI currently prints those warnings to stderr.

Turn completion comes from native assistant stopReason: "stop", not from agent_settled. Only real final text in a source message without any tool-call block is marked complete. Other assistant messages are explicitly incomplete; thinking-only or empty stops do not create a closing message. The optional turnComplete field reaches the gateway for batching, never the EverOS wire.

Failure policy

Recall and profile injection are best-effort and bounded by their own deadlines (6s / 8s), well inside anything a user would wait for. On timeout or error the turn proceeds with no injection: a memory lookup must never be the reason a prompt hangs. pi's own provider layer can already stall — an openai-codex OAuth refresh was observed hanging a whole run — and this extension refuses to add to that.

Saves are reported, never faked. A failed upload surfaces in /everme and in the tool result; nothing is silently queued or dropped.

Notes for maintainers

  • The extension is plain ESM JavaScript, like every other package here. pi's loader accepts .js and .ts equally; .js needs no jiti transform and keeps this package consistent with the rest of plugins/.
  • typebox is a peer dependency: pi validates tool parameters with its own copy, and bundling a second one is what pi's packaging docs warn against. It is also a devDependency so the tests can build schemas.
  • The SDK's runHook() is deliberately not used. It arms a watchdog that calls process.exit(0) near the host's kill deadline, which is right for a hook process and fatal inside the long-lived pi TUI. This package uses the SDK primitives (client, runInject, saveAgentMemory, rune caps, redaction) and owns its own deadlines.
  • Nothing is written to process.env. pi spawns tools and user bash commands from the same environment, so an agent token placed there would leak into every child process.
  • Cold-start import for pi sessions lives in evercli (evercli import conversations run --platform pi), which reads ~/.pi/agent/sessions/** directly. The extension does not backfill history. Import follows the selected branch's original messages, including history retained on disk before compaction. Compaction and branch summaries are runtime context, not conversation messages, and are not imported.
  • Automatic saves report discarded invalid tool IDs, names, or arguments as fixed reason/count warnings, without source content or credentials. This does not enable the SDK's otherwise quiet progress logging.

Tests

npm test --workspace @everme/pi     # from plugins/

The extension tests drive the real event chain through a stand-in pi object against a local HTTP backend, asserting the injected block shapes and the upload body. The install path itself was verified on a real pi 0.80.10: pi install <path> is headless, pi list shows the package, pi remove restores settings.json byte-for-byte, and a live run reached /mem/context, /mem/search and /mem/agent-memory in that order.