docs: add session-hygiene intent/approach/work docs and synod research
This commit is contained in:
parent
0c37d3f2f9
commit
90114b451a
File diff suppressed because one or more lines are too long
158
docs/approach/2026-01-24-session-hygiene.md
Normal file
158
docs/approach/2026-01-24-session-hygiene.md
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
# 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**:
|
||||||
|
|
||||||
|
1. **Widget vs Status**: Widget (multi-character, always visible) vs setStatus (footer slot, subtle)
|
||||||
|
→ **Widget** — needs to be glanceable without hunting for it
|
||||||
|
|
||||||
|
2. **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.
|
||||||
|
|
||||||
|
3. **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.
|
||||||
|
|
||||||
|
4. **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.
|
||||||
|
|
||||||
|
5. **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.
|
||||||
|
|
||||||
|
6. **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 `/commit` if needed.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### New Components
|
||||||
|
|
||||||
|
```
|
||||||
|
~/.pi/agent/extensions/session-hygiene/
|
||||||
|
├── index.ts # Extension entry point
|
||||||
|
└── git.ts # Git helpers (status, commit, etc.)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Extension Structure
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// 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:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
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**: `setWidget` defaults to above editor. Need to verify `belowEditor` placement 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 status` returns non-zero. Extension silently does nothing (no widget, `/commit` shows error).
|
||||||
|
- **Detached HEAD / merge conflict**: Unusual git states. `/commit` should detect and warn rather than corrupt state.
|
||||||
|
- **Empty commit**: All changes already staged and committed. `/commit` should 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_commit` tool registered (LLM can use it anytime)
|
||||||
|
|
||||||
|
### Phase 2: /commit Command
|
||||||
|
- `/commit` command 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)
|
||||||
38
docs/intent/2026-01-24-session-hygiene.md
Normal file
38
docs/intent/2026-01-24-session-hygiene.md
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Intent: Session Hygiene Extension
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
Working in pi across long sessions, it's easy to lose track of what's changed. You finish a session with dozens of uncommitted files, unclear what goes with what, and the commit history becomes a mess of grab-bag commits. The problem isn't catastrophic — nothing is lost — but it erodes organization over time.
|
||||||
|
|
||||||
|
## Need
|
||||||
|
|
||||||
|
Ambient awareness of git state while working, so commits happen naturally at good moments rather than as panicked cleanup at session end.
|
||||||
|
|
||||||
|
## Use-Cases
|
||||||
|
|
||||||
|
- **Mid-session glance**: You're deep in a refactor, glance at the footer, see "14 files" — mental note that there's a chunk of work building up. You might commit now, or keep going. Either way, you're aware.
|
||||||
|
|
||||||
|
- **Natural stopping point**: You finish a logical unit of work. The footer reminds you there's uncommitted work. You run `/commit`, get a suggested message based on what we discussed, and commit cleanly.
|
||||||
|
|
||||||
|
- **Session end**: You're about to close pi. Footer shows dirty state. You either commit, stash, or consciously leave it — but you're not surprised by 48 files later.
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- Footer widget shows uncommitted file count for current repo at all times
|
||||||
|
- `/commit` command triggers guided flow with auto-drafted commit message from conversation context
|
||||||
|
- User never feels nagged, blocked, or guilty — just informed
|
||||||
|
- Commits end up logical and well-messaged because awareness came early
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- Single repo only (the one we're in)
|
||||||
|
- Must work as a pi extension (TypeScript, pi extension API)
|
||||||
|
- No external dependencies beyond git
|
||||||
|
|
||||||
|
## Anti-Goals
|
||||||
|
|
||||||
|
- **No auto-commit**: Never commit without explicit user action
|
||||||
|
- **No blocking prompts**: Never interrupt flow with modal dialogs
|
||||||
|
- **No guilt mechanics**: No "you should commit" nudges, red warnings, or escalating alerts
|
||||||
|
- **No multi-repo tracking**: Don't watch repos outside current working directory
|
||||||
|
- **No push**: This is about local commits only
|
||||||
49
docs/work/2026-01-24-session-hygiene.md
Normal file
49
docs/work/2026-01-24-session-hygiene.md
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Work: Session Hygiene Extension
|
||||||
|
|
||||||
|
## Intent
|
||||||
|
Link to: [docs/intent/2026-01-24-session-hygiene.md](../intent/2026-01-24-session-hygiene.md)
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
Link to: [docs/approach/2026-01-24-session-hygiene.md](../approach/2026-01-24-session-hygiene.md)
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
### Phase 1: Widget + git_commit Tool
|
||||||
|
|
||||||
|
- [x] **W001**: Create extension directory structure
|
||||||
|
- Verification: `ls ~/.pi/agent/extensions/session-hygiene/index.ts`
|
||||||
|
|
||||||
|
- [x] **W002**: Implement git status helper
|
||||||
|
- Verification: `pi -e ~/.pi/agent/extensions/session-hygiene -p "test" 2>&1 | head -5` (no syntax errors)
|
||||||
|
|
||||||
|
- [ ] **W003**: Implement footer widget showing dirty file count
|
||||||
|
- Verification: Start pi in a dirty repo, observe widget shows file count
|
||||||
|
|
||||||
|
- [ ] **W004**: Hook tool_result to update widget after bash/write/edit
|
||||||
|
- Verification: In pi, write a file, observe widget count increases
|
||||||
|
|
||||||
|
- [ ] **W005**: Implement git_commit tool (stage files + commit)
|
||||||
|
- Verification: `pi -p "Use git_commit to commit README.md with message 'test: verify tool'"` in test repo
|
||||||
|
|
||||||
|
### Phase 2: /commit Command
|
||||||
|
|
||||||
|
- [ ] **W006**: Implement session context extraction (recent messages, file touchpoints)
|
||||||
|
- Verification: `/commit` in pi shows context being gathered (log or notify)
|
||||||
|
|
||||||
|
- [ ] **W007**: Implement /commit command that injects context and triggers LLM
|
||||||
|
- Verification: `/commit` in dirty repo triggers LLM response with grouping proposal
|
||||||
|
|
||||||
|
- [ ] **W008**: Verify full flow: /commit → LLM groups → git_commit calls → widget updates
|
||||||
|
- Verification: End-to-end test in a repo with 5+ changed files across different paths
|
||||||
|
|
||||||
|
## Verification Evidence
|
||||||
|
|
||||||
|
- (2026-01-24 23:xx) W001: `ls ~/.pi/agent/extensions/session-hygiene/index.ts` → exists
|
||||||
|
- (2026-01-24 23:xx) W002: jiti load fails on missing module (expected) — syntax valid
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Extension location: `~/.pi/agent/extensions/session-hygiene/`
|
||||||
|
- Will use `belowEditor` widget placement — need to verify it looks right
|
||||||
|
- For /commit context injection, use `pi.sendUserMessage()` or `before_agent_start` message injection
|
||||||
|
- Model for grouping: use whatever model is currently active (no separate API key needed)
|
||||||
Loading…
Reference in a new issue