punched-memory1.0.6
Persistent per-directory project memory for the pi coding agent. Keeps a structured pi.md file in each cwd, private & gitignored, that captures scope / decisions / gotchas / todos / session history across sessions.
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.
Reports 0
No reports yet.
Readme
πͺ‘ punched-memory
Persistent per-directory project memory for the pi coding agent.
A structured pi.md in every working directory β private, gitignored, recoverable across sessions.
punched-memory (alias: punched) keeps a structured pi.md file in
every working directory you use with pi. The file is private β it is
auto-added to .gitignore whenever the directory is a git repo β and
stores the entire project memory across sessions: scope, decisions,
gotchas, TODO checklist and a per-session working log. Content is written
in the user's interaction language (auto-detected or explicitly chosen)
and includes session IDs, timestamps, and structured sub-sections so a
fresh session can recover context immediately.
When you re-enter a directory, punched keeps the existing pi.md so
context is available, but it does not interrupt you with a recall
prompt by default. When you want to browse or inject a past session
summary into the editor, run /punched session (or pick the Recall
previous sessions entry from the main menu). You can flip the
auto-prompt back on via /punched-memory config β Recall prompt.
π‘οΈ Safety guard:
pi.mdis a per-working-directory file. If pi is started from the filesystem root (/) β or the configured filename tries to escape the cwd (../x.md, absolute paths, nested paths) βpunchedrefuses to touch that location and disables itself for the session with a warning instead of crashing on anEACCESwrite. Start pi from a real project directory to get memory.
β¨ Features
πͺ‘ pi.md per cwd |
one file, stable structured format with YAML front-matter and well-known sections |
| π§ Decisions log | date, why, trade-offs and alternatives (as a markdown list) |
| β οΈ Gotchas | title + description + date, easy to grep later |
| β TODO checklist | split into Pending / Done, toggleable by id |
| π Session log | id, start/end timestamps, title, summary, decisions, files, open questions |
| π i18n | 9 languages (en, es, fr, de, it, pt, ja, zh, ru); auto-detect or explicit |
| π¨ Visual TUI | animated banner, needle spinner, boxed menus, recall view, config |
| π Private by default | auto-patches .gitignore in git repos (also for .punched-memory.json) |
| π€ LLM tools | punched_log, punched_todo, punched_session, punched_recall |
| πΎ Layered config | global ~/.pi/agent/punched-memory/config.json + per-project .punched-memory.json |
| πͺ Manual recall | /punched session opens the recall view, no auto-interrupt |
| π‘οΈ Strict TypeScript | full strict mode, zero any in public APIs |
π¦ Install
One-line install
pi install git:github.com/noguerol/punched
That's it. Reload pi with /reload and punched will be active on
the next session start.
From a local clone (development)
git clone https://github.com/noguerol/punched
cd punched
npm install
ln -sfn "$(pwd)" ~/.pi/agent/extensions/punched-memory
Then /reload in pi.
From npm (when published)
pi install npm:punched-memory
π― Commands
All commands also work under the /punched alias.
| Command | Description |
|---|---|
/punched-memory |
Open the visual main menu (status, recall, log, todos, config) |
/punched-memory config |
Open the configuration menu (toggles, language, filename) |
/punched-memory status |
Show pi.md stats (sessions, decisions, todos, language) |
/punched-memory session |
Open the recall view β browse previous sessions and inject any into the editor |
/punched-memory recall |
Alias for session |
/punched-memory log <note> |
Append a free-form note to the current session |
/punched-memory language <code> |
Set language: auto, en, es, fr, de, it, pt, ja, zh, ru |
/punched-memory forget |
Permanently delete pi.md (with confirmation) |
/punched-memory help |
Show command help |
π€ LLM-callable tools
The extension registers four tools the model can call proactively. They have custom TUI renderers so you can see at a glance what the model added.
punched_log
Append a structured entry. Type can be:
| Type | Required | Optional | Description |
|---|---|---|---|
decision |
title |
body (why), alternatives |
a key design decision |
gotcha |
title |
body (description) |
a trap to remember |
task |
body |
a new TODO item | |
done |
body |
mark a matching TODO as done | |
note |
body |
a note appended to the current session | |
question |
body |
an open question for the current session | |
scope |
body |
append/merge to the project scope | |
goal |
list |
replace |
append or replace the goals list |
non_goal |
list |
replace |
append or replace the non-goals list |
tech |
list |
replace |
append or replace the tech-stack list |
component |
list |
replace |
append or replace the components list |
punched_todo
Manage the project TODO checklist: add (text), toggle (id),
list, clear.
punched_session
Update the current session: checkpoint / end / update, with
optional title, summary, decisions, files, questions,
notes.
punched_recall
Read the project's pi.md so the model can recover context between
sessions. Returns a structured markdown view.
βοΈ Configuration
Configuration is layered β per-project overrides win over global:
- Global:
~/.pi/agent/punched-memory/config.json - Per-project:
<cwd>/.punched-memory.json(always gitignored)
Open /punched-memory config to edit visually.
| Setting | Default | Description |
|---|---|---|
enabled |
true |
Master switch β when off the extension is dormant |
showBanner |
true |
Show the πͺ‘ banner on session start |
promptRecall |
false |
When true, prompt to recall previous sessions on session start. Off by default β use /punched session instead. |
autoGitignore |
true |
Patch .gitignore when in a git repo (covers pi.md and .punched-memory.json) |
autoLog |
true |
Persist session markers automatically |
footerStatus |
true |
Show a πͺ‘ indicator in the footer |
llmToolsEnabled |
true |
Allow the model to call the punched_* tools |
language |
auto |
auto (detect from your messages) or an explicit code |
mdStyle |
full |
full or compact markdown rendering |
maxSessionHistory |
50 |
Number of sessions kept on disk |
filename |
pi.md |
On-disk memory file name (don't change unless you must) |
π On-disk format
The on-disk file is plain Markdown β easy to cat, grep, search, or
read directly. punched_recall parses it back into structured form
for the LLM.
---
punched-version: 1
project: my-cool-app
language: en
created: 2025-01-15T10:00:00.000Z
lastUpdated: 2025-01-15T16:45:00.000Z
sessions:
- id: 9c3a1e8b-β¦
started: 2025-01-15T10:00:00.000Z
ended: 2025-01-15T16:45:00.000Z
title: "Refactor auth flow"
---
# πͺ‘ pi.md β Project Memory
> Persistent project memory generated by `punched-memory`. This file is **private**β¦
## π Project Scope
Real-time chat with WebSockets, E2E encryption, offline-first sync.
### Goals
- ship v1 to 1000 users
- p99 latency < 100ms
### Non-goals
- native mobile in v1
## ποΈ Architecture & Stack
### Tech Stack
- Rust, WebSockets, SQLite, WASM
### Key Components
- chat-server, crypto-layer, sync-engine
## π§ Decisions Log
### 2025-01-15 β E2E via libsodium
**Why:** privacy is hard requirement
**Alternatives considered:**
- TLS only
- custom AES
## β οΈ Gotchas & Pitfalls
- **WS reconnect storms**: on network flap, clients retry too aggressively; add jittered backoff (`2025-01-15`)
## β
Tasks & TODO Checklist
### Pending
- [ ] benchmark p99 latency
### Done
- [x] write protobuf schema
## π Working Session Log
### πͺ‘ Session <id> β 2025-01-15 10:00 β 16:45
**Title:** Refactor auth flow
**Summary:**
β¦
#### Decisions made this session
#### Files touched
#### Open questions
## βοΈ Manual notes
Anything here is kept verbatim and in place.
Note: section headings are always written in English so the parser can reliably round-trip the file. Prose inside sections (decisions, gotchas, summaries, β¦) is written in your language.
βοΈ Hand-editing pi.md
pi.md is safe to edit by hand. The parser preserves what it does not
understand instead of silently dropping it:
- Any unknown
## H2section is kept verbatim and re-emitted at (or near) the position it had β a βread this firstβ brief stays above the generated sections instead of being pushed below the session log. - Unknown content under a known section (a
#### note, loose prose, an extra list) is retained under that same section. - Session sub-blocks (
#### Decisions made this session,#### Files touched,#### Open questions) now survive any number of read/write cycles (previously they were destroyed on the first write). - Reserved section:
## βοΈ Manual notesis first-class β copied verbatim, in place, and never reformatted. Use it for a curated state brief, architecture invariants, or a phase-status block that you want to read first on the next session.
The invariant enforced by the test suite is
readDoc(writeDoc(readDoc(x))) == readDoc(x): writing removes nothing from
x except the tool-owned front-matter fields (lastUpdated, sessions).
π¨ Visual TUI
The extension goes out of its way to feel warm and friendly:
- πͺ‘ Needle-and-paper spinner during every save
(
["πͺ‘","βͺ","πͺ‘","βͺ","π΄","βͺ"]) - π¨ Boxed banner on session start with project name, session count, language, last-updated timestamp and status pill (πͺ‘ (on) / πͺ‘ off)
- π§ Recall view β scrollable cards for each past session with title, dates, summary, decisions. Press Enter to inject the selected session into the editor
- π Visual menus β main menu, status panel, recall list, config menu with emoji-labelled toggles
- πͺπΈ / π¬π§ / π«π· / β¦ β banner headings and intro adapt to the active language
- β¨ Compact footer indicator (
πͺ‘ (on)/πͺ‘ off) β same emoji, tiny on/off label; showsoffwhen the extension is disabled or nopi.mdexists yet
π Privacy & safety
pi.mdis never committed to git β the extension patches.gitignoreautomatically the first time you open a git repo. The per-project override file.punched-memory.jsonis similarly guarded.- All content stays on your machine. No network calls, no telemetry.
- The global config lives at
~/.pi/agent/punched-memory/config.json, inside your trusted pi config dir. - The extension only reads/writes files inside the working directory and your pi config dir.
π οΈ Development
git clone https://github.com/noguerol/punched
cd punched
npm install # for type-checking only β jiti runs TS directly
npx tsc --noEmit # full strict type-check
To hot-reload after edits, run /reload in pi. The extension has
three runtime dependencies (@earendil-works/pi-*, typebox) and
zero on any other package.
Source layout
src/
βββ index.ts β main entry: command registration, session lifecycle
βββ config.ts β global + per-project config (load / save / patch)
βββ pimd.ts β read / parse / serialize the pi.md document
βββ language.ts β lightweight language detector (no external deps)
βββ i18n.ts β localized strings for the TUI & on-disk headings
βββ gitignore.ts β auto-guard pi.md inside git repos
βββ tools.ts β LLM-callable punched_* tools
βββ ui/
βββ banner.ts β animated banner (box-drawing + emojis)
βββ spinner.ts β needle-and-paper spinner
βββ main-menu.ts β visual main menu (custom component)
βββ recall-view.ts β scrollable recall cards
βββ config-menu.ts β toggles, language, filename, etc.
π€ Contributing
Issues and PRs welcome. Please:
- Open an issue first to discuss non-trivial changes
- Keep
tsc --noEmitclean - Add or update tests when relevant
- Match the existing code style (strict TS, no
any, named exports)
π License
MIT β Β© 2026 punched-memory contributors
π§΅ Credits
Inspired by classic "punched tape" memories β the project memory is stitched together session by session, one needle-and-thread stitch at a time. πͺ‘
Built for the pi coding agent.