Pin session decisions, questions, constraints, and corrections to a persistent board that survives context compaction.
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
High
Do not use without reviewing
Persist decisions, questions, constraints, and corrections to a JSON file that survives context compaction. A companion hook injects the board into every tool call so the model never forgets.
After responding to any user message where a decision was made, a question was asked about a proposal, or a constraint was stated, IMMEDIATELY invoke /pin with the appropriate category. Do not ask permission — just pin it.
Examples of auto-invoke triggers:
/pin ✅ use bun/pin ❓ split services — latency impact?/pin ❌ auth layer — skip for MVP/pin 📌 MVP only, max 3 files/pin 🔧 target = artisans, not developersDo NOT pin:
| Command | Action |
|---|---|
/pin ✅ <text> | Pin approved item |
/pin ❓ <text> | Pin pending question |
/pin ❌ <text> | Pin killed/rejected item |
/pin 📌 <text> | Pin scope constraint |
/pin 🔧 <text> | Pin correction |
/pin show or /pin | Display current board |
/pin rm <n> | Remove pin by number |
/pin clear | Clear all pins |
/pin clear triage | Clear ✅/❓ only, keep 📌/❌/🔧 |
Path: a session-scoped .session-logs/<slug>/pins.json file under a configurable base directory.
Derive slug from CWD:
GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
REL_PATH="${PWD#$GIT_ROOT/}"
SLUG=$(echo "$REL_PATH" | tr '/' '-')
PINS_DIR="$PRAXIS_DIR/.session-logs/$SLUG"
PINS_FILE="$PINS_DIR/pins.json"Schema:
{
"items": [
{
"id": 1,
"type": "approved",
"emoji": "✅",
"content": "use bun everywhere",
"detail": "",
"ts": "2026-04-01T14:30:00Z"
}
],
"next_id": 2
}Type mapping: ✅=approved, ❓=pending, ❌=killed, 📌=scope, 🔧=correction
/pin <emoji> <text>)Parse the emoji prefix to determine type. Text after emoji is content. If text contains —, split into content and detail.
PINS_FILE path (see State File above)mkdir -p the directory{"items":[],"next_id":1}⚠️ Already pinned. and stopid=next_id, increment next_id📌 Pinned #N: <emoji> <content> — one line only, then resume prior work/pin show or /pin)PINS_FILE📋 Pin board is empty.📋 Pin Board (5 items)
1. ✅ use bun everywhere (minor: keep fallback for CI)
2. ✅ split the PR into 2
3. ❓ split services — latency impact?
4. ❌ auth rewrite — out of MVP scope
5. 📌 MVP only, max 3 files/pin rm <n>)If no number: ⚠️ Usage: /pin rm <number>
PINS_FILE, find item with id === n⚠️ Pin #N not found.🗑️ Pin #N removed./pin clear){"items":[],"next_id":<keep current next_id>}🗑️ Pin board cleared./pin clear triage)approved or pendingkilled, scope, or correction🗑️ Triage cleared. <N> pins remaining.The pin board is a capture tool, not a management tool. Its only job is to hold decisions and constraints in a persistent, queryable form so that context compaction does not erase them. ALWAYS treat the board as a write-once, append-only record during a session — edits and removals are operations of last resort, not routine cleanup. A well-run session generates fewer than 20 pins; if you hit the limit frequently, the signals are too granular.
next_id always increments, never reuses.📌 MVP only, max 3 files has the emoji as a 2-byte or 4-byte sequence; naive cut -d' ' will misparse on some shells.next_id always increments forward. Why: Stable numbering prevents confusion when users reference pins by number across a session; id recycling silently corrupts that contract.Pinning a scope constraint mid-session:
# User says: "Keep this MVP only, no more than 3 new files"
/pin 📌 MVP only, max 3 files
# Response: 📌 Pinned #1: 📌 MVP only, max 3 files
# Session resumes immediately from where it left offPinning a decision reversal and viewing the board:
# User says: "Actually use PostgreSQL, not SQLite"
/pin 🔧 target database = PostgreSQL, not SQLite
# Response: 📌 Pinned #2: 🔧 target database = PostgreSQL, not SQLite
# Later: review all active pins
/pin show
# Response:
# 📋 Pin Board (2 items)
# 1. 📌 MVP only, max 3 files
# 2. 🔧 target database = PostgreSQL, not SQLitePinning an unresolved question and clearing triage items after resolution:
# Unresolved question surfaces during design
/pin ❓ split services — will latency exceed 200ms SLA?
# Response: 📌 Pinned #3: ❓ split services — will latency exceed 200ms SLA?
# After the question is answered, clear only approved/pending pins
/pin clear triage
# Response: 🗑️ Triage cleared. 1 pin remaining.