omp packages

al-jaffee0.1.0

Fold-in compaction for pi — mark a point, run a self-contained tangent, fold it into a summary receipt, unfold on demand.

gopherbone Published 1 month ago MIT ~214 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

al-jaffee

Fold-in compaction for pi, named after MAD magazine's Al Jaffee and his fold-ins: the page folds to a marker, only the summary shows, and you can fold it back out when you need the whole picture.

The agent marks a point in the conversation (set_fold_marker), runs a self-contained tangent, then calls fold(summary). At the end of that turn the session tree branches back to the marker and the summary is written as the marker call's new result — the tangent leaves the live context entirely, and the agent continues the main line as if the tangent had been one tool call.

The folded transcript is not deleted — sessions are append-only trees, so the tangent stays on a branch. return_to_fold(prompt, fold?) navigates back to it with an agent-provided prompt; /tree shows the folds as labeled branches.

Model-facing semantics

The mechanics are the easy half. The hard half is what the folded context looks like to the model resuming from it:

  • The receipt is second-person with excision metadata. A model reading set_fold_marker → FOLD COMPLETE has no in-context evidence it ever ran the tangent or called fold — "I did this work and it was spliced out" and "this never happened" must not be indistinguishable. The receipt states how many entries were folded away, whether user messages were swept up, and says explicitly: you did that work before the fold — you won't remember doing it, and that is expected, not an error — plus trust-but-verify guidance (re-check files/output before asserting them) and "do not re-do the work."

    … main conversation …
    assistant: set_fold_marker({ task: "archive inventory" })
    toolResult: [al-jaffee] FOLD COMPLETE — tangent folded into this marker.
                Task: archive inventory
                Folded away: 9 conversation entries … you won't remember doing
                it, and that is expected, not an error. Treat the summary below
                as your own notes…
                Summary (yours, written at fold time): read a.md (kickoff, plan
                B), b.md (budget $12.4k), c.md (roadmap)…
    assistant: (continues the main line from here — tangent tokens gone from context)
    
  • The plugin never impersonates the user. All model-directed traffic (fold cues, corrections, unfold prompts) goes through pi.sendMessage custom messages — labeled al-jaffee, never pi.sendUserMessage, which appends a message that appears as if typed by the user. The unfold prompt is re-sent as a visible labeled plugin message at the tangent tip.

  • Refusals reach the model, not just the TUI. A queued fold/unfold promised a commit; if the commit cannot happen (conversation moved past the fold, navigation cancelled, dispatch failed), the model receives a visible correction message (with triggerTurn) saying NOTHING was folded and it may retry — instead of silently believing its summary is safely at the marker.

  • User words are flagged before they leave. If user messages sit between the marker and the fold, fold warns at queue time ("N user message(s) will be folded too — make sure the summary covers them") and the receipt records the count; the words stay restorable on the branch.

  • Machine notes: the summary's ground-truth counterpart. The summary is self-reported, and after the fold it is the only part of the tangent left in context — a single point of failure, since sloppy notes get relayed with full confidence and cannot be detected from inside. So the commit appends an auto-generated footer: set_fold_marker snapshots the working directory (walk + sha1 hashes + line counts), the commit snapshots it again, and the diff plus every bash call seen between marker and fold (via a tool_result listener) land in the receipt:

    Summary (yours, written at fold time):
    Inventoried archive/: a.md (meeting notes)…
    
    Machine notes (auto-generated — ground truth for files/commands, not my notes):
    cwd: /Users/nick/proj
    Files vs marker snapshot (2 changed):
      + notes.md (created, 1 line)
      ~ draft.md (modified, 3 → 5 lines)
    Bash: 1 call — all exit 0; last: python3 -m py_compile draft.md
    Worktree: 1 dirty (git) — 0 already dirty at marker
    (cwd snapshot: 34 files hashed)
    

    The receipt's trust-but-verify line points at the notes ("the machine notes at the end are auto-generated ground truth for files and commands — re-verify anything else critical"). Paths and counts only — never file contents or command output; the whole footer is priced at a few lines.

  • One surgery per turn. Queuing a fold while an unfold is pending (or vice versa) fails loudly instead of silently dropping the first intent.

Why it's cache-friendly

  • Fold preserves the transcript byte-for-byte up to the marker tool call, so the provider prompt-cache prefix survives; only the marker result forward is new tokens. Compare /compact, which rewrites the head and forfeits nearly all cached tokens.
  • Unfold is the mirror win: the tangent tail was the live context minutes ago, so returning usually hits the still-warm provider cache. In the e2e test, the unfold request read 3,840 cached tokens and sent only 278 uncached.

Measured on the e2e run (synthetic / GLM-5.3-Flash, ~7 KB of tangent file content folded):

request input cacheRead
tangent turns 1597→80 704→2496
post-fold continuation 1327 2560
next turn (folded) 96 3584
unfold (back to full) 278 3840

Tools

tool when
set_fold_marker(task) right before starting a self-contained tangent
fold(summary) right when the tangent is done; summary is written for future-you
return_to_fold(prompt, fold?) when a completed fold's details are needed again; fold targets a specific fold by task substring (default: latest)

All three are always active (stable tool list = stable cache prefix). Nested markers work; fold applies to the most recent. /al-jaffee-status lists the folds on record with their excision counts.

Commands

  • /al-jaffee-status — active marker, folds on record, pending surgery, machine-notes state for the active marker
  • /al-jaffee-commit, /al-jaffee-return — internal; also usable manually to retry a failed dispatch

Tests

node test/mechanics.test.mjs   # SessionManager-level surgery — no LLM
node test/snapshot.test.mjs    # machine-notes pipeline — no LLM
node test/e2e.test.mjs         # full RPC fold/unfold cycle — real provider

The harnesses resolve pi's global install via npm root -g (homebrew fallback in test/paths.mjs). The e2e run uses the real Synthetic.new provider through ~/.pi/agent/npm/.../pi-synthetic-provider — point AL_JAFFEE_SYNTHETIC_PROVIDER at the extensions dir if it lives elsewhere.

Install

ln -s /path/to/al-jaffee ~/.pi/agent/extensions/al-jaffee
# or project-local:
ln -s /path/to/al-jaffee .pi/extensions/al-jaffee

Notes & limits

  • The commit runs at turn end (tree navigation is unsafe mid-stream by design). Tools queue intent with terminate: true; a command dispatched from agent_settled performs the surgery. The dispatch channel is a self-rescheduling retry chain (exponential backoff, ~12s budget) that never depends on agent_settled refires — a swallowed dispatch with no further session activity retries anyway, and on give-up notifies both the user (TUI) and the model (correction message). The model experiences a successful fold as one seamless continuation.
  • Folding folds everything after the marker, including any conversation that happened past the tangent — flagged at queue time and in the receipt; /tree can always walk back (the branch is intact).
  • fold/unfold need an interactive session (TUI or RPC). In print mode the tools fail gracefully.
  • pi API trap: getBranch() returns ROOT→LEAF (oldest first — it walks entry→root then reverses), so "first match found" is the oldest entry. Nested-marker resolution and fold-record listing compensate by iterating to the match closest to the leaf. The region scan skips until the marker's assistant entry, then counts to the leaf.
  • Machine notes budgets (snapshot.ts): the cwd walk caps at 5,000 files and a 5s budget; files over 8MB aren't hashed (size-only comparison, documented best-effort) and over 1MB get no line count. Common noise dirs are excluded (.git, node_modules, __pycache__, dist, build, caches — see EXCLUDED_DIRS). A truncated snapshot never reports a confident "none": the footer flags it ("snapshots truncated — some changes may be untracked"). Degrades honestly everywhere else too: no marker snapshot (taken before a /reload that lost the in-memory store — though the store persists to a temp file for exactly that), not a git repo, failed walk — each becomes an "n/a" line, never a fabrication. Per-marker state survives /reload via os.tmpdir()/al-jaffee-snapshots/ (pruned after 7 days) and is cleaned up at commit.
  • One line of non-public API: appendMessage() via a type cast on ctx.sessionManager (no sanctioned API appends arbitrary toolResults). Everything else — navigateTree branching + agent-state resync, custom messages, labels, command dispatch — is public API.
  • test/mechanics.test.mjs — SessionManager-level surgery tests (no LLM), including the second-person receipt, excision metadata, the machine-notes footer, and the labeled plugin-message unfold prompt. test/snapshot.test.mjs — the machine-notes pipeline (no LLM): walk/excludes/line-counts, diff, bash status parsing, footer formatting, and honest degradation. Both load TS directly (jiti). test/e2e.test.mjs — full RPC-driven fold/unfold cycle with token accounting (node e2e.test.mjs, uses the real Synthetic.new provider — allow for inference latency variance); asserts the receipt semantics (including the auto machine notes) and that the unfold prompt is NOT a fake user message. All three resolve pi via test/paths.mjs.

License

MIT