5.3 KiB
Approach: Session Hygiene Extension
Strategy
Core philosophy: Ambient awareness, not active management.
The extension provides a persistent footer widget showing git state. The user glances at it when they want to. A /commit command offers a guided flow with auto-drafted messages when they're ready to commit. No nudges, no prompts, no interruptions.
Key Decisions:
-
Widget vs Status: Widget (multi-character, always visible) vs setStatus (footer slot, subtle) → Widget — needs to be glanceable without hunting for it
-
Polling vs Events: Poll git status periodically vs hook into tool_result events → Hook tool_result — only re-check after bash/write/edit tools that might change files. Avoids polling overhead.
-
Grouping strategy: No grouping vs LLM-driven grouping → LLM-driven grouping — LLM sees changed files + session context, proposes logical groups with conventional commit messages. Always runs, even for 1-3 files.
-
Confirmation flow: Always confirm vs LLM discretion → LLM discretion — LLM decides when to ask questions (ambiguous grouping, orphan files) vs proceed. User already invoked
/commit, so trust the intent. -
Orphan files: Auto-bucket into "misc" vs ask → Ask — if a file doesn't fit any logical group, LLM should ask user where it belongs.
-
Staging: Auto-stage all vs let user stage manually → Auto-stage all (
git add -A) — matches "just commit everything" simplicity. User can unstage manually before/commitif needed.
Architecture
New Components
~/.pi/agent/extensions/session-hygiene/
├── index.ts # Extension entry point
└── git.ts # Git helpers (status, commit, etc.)
Extension Structure
// index.ts
export default function(pi: ExtensionAPI) {
// State
let dirtyCount = 0;
// 1. Widget: show dirty count in footer
pi.on("session_start", updateWidget);
pi.on("tool_result", maybeUpdateWidget); // Only after bash/write/edit
// 2. Command: /commit
pi.registerCommand("commit", { handler: commitFlow });
}
Data Flow
[tool_result event]
│
▼
is bash/write/edit?
│ yes
▼
git status --porcelain
│
▼
count changed files
│
▼
ctx.ui.setWidget("hygiene", ["● 14 files"])
[/commit command]
│
▼
git status --porcelain → list of changed files
│
▼
extract session context:
- recent messages (user prompts, assistant responses)
- file touchpoints (which files were read/written/edited when)
│
▼
LLM prompt:
"Here are the changed files and session context.
Group into logical commits. For each group:
- list files
- conventional commit message
If a file doesn't fit, ask the user.
If grouping is ambiguous, ask.
Otherwise, proceed and execute commits."
│
▼
LLM executes commits via tool calls (git add <files>, git commit -m "...")
│
▼
update widget (now shows 0 or remaining)
Commit Tool
The /commit command injects context and lets the LLM drive. It needs a git_commit tool:
pi.registerTool({
name: "git_commit",
description: "Stage specific files and commit with a message",
parameters: Type.Object({
files: Type.Array(Type.String(), { description: "Files to stage (relative paths)" }),
message: Type.String({ description: "Commit message (conventional format)" }),
}),
async execute(toolCallId, params, onUpdate, ctx, signal) {
// git add <files...>
// git commit -m <message>
// return success/failure
},
});
This lets the LLM make multiple commits in sequence, asking questions in between if needed.
Risks
Known Unknowns
- Widget placement:
setWidgetdefaults to above editor. Need to verifybelowEditorplacement looks right for a small status indicator. - LLM latency: Drafting commit message adds a few seconds. Acceptable? Could show "Drafting..." in UI.
- Model availability: Need a model for commit message drafting. What if user doesn't have API key for it?
Failure Modes
- Not a git repo:
git statusreturns non-zero. Extension silently does nothing (no widget,/commitshows error). - Detached HEAD / merge conflict: Unusual git states.
/commitshould detect and warn rather than corrupt state. - Empty commit: All changes already staged and committed.
/commitshould detect "nothing to commit" and notify.
Blast Radius
- Minimal: Extension only reads git state and runs
git add -A+git commit. No force pushes, no rebase, no destructive operations. - Worst case: User commits something they didn't want to. Recoverable via
git reset HEAD~1.
Phases
Phase 1: Widget + git_commit Tool
- Footer widget showing dirty file count
- Updates after file-mutating tools
git_committool registered (LLM can use it anytime)
Phase 2: /commit Command
/commitcommand injects context and triggers LLM-driven grouping- LLM proposes groups, asks questions if uncertain, executes commits
- Widget updates as commits land
Phase 3: Polish (Future)
- Stash support (
/stash) - Undo last commit (
/uncommit) - Integration with worklog skill (prompt to commit after worklog)