Pin — Session Decision Board
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.
Auto-Invoke Rules
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:
- User: "yes go with bun" → respond normally, then
/pin ✅ use bun
- User: "what about the latency impact?" → respond normally, then
/pin ❓ split services — latency impact?
- User: "no skip auth for now" → respond normally, then
/pin ❌ auth layer — skip for MVP
- User: "MVP only, max 3 files" → respond normally, then
/pin 📌 MVP only, max 3 files
- User: "no I meant artisans not developers" → respond normally, then
/pin 🔧 target = artisans, not developers
Do NOT pin:
- Casual conversation, greetings
- Implementation details (code changes, file edits)
- Things already pinned (check board first)
Commands
| 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 📌/❌/🔧 |
State File
Path: $PRAXIS_DIR/.session-logs/<slug>/pins.json
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 (/pin <emoji> <text>)
Parse the emoji prefix to determine type. Text after emoji is content. If text contains —, split into content and detail.
- Derive
PINS_FILE path (see State File above)
mkdir -p the directory
- Read existing file or init
{"items":[],"next_id":1}
- Check if content already pinned (exact match on content field) → if so, respond
⚠️ Already pinned. and stop
- Check limits: 5 items per type, 20 total. If category full, drop oldest item of that type.
- Append new item with
id=next_id, increment next_id
- Write file
- Respond:
📌 Pinned #N: <emoji> <content> — one line only, then resume prior work
Show (/pin show or /pin)
- Read
PINS_FILE
- If file missing or items empty:
📋 Pin board is empty.
- Display:
📋 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
Remove (/pin rm <n>)
If no number: ⚠️ Usage: /pin rm <number>
- Read
PINS_FILE, find item with id === n
- If not found:
⚠️ Pin #N not found.
- Remove item, write file
- Respond:
🗑️ Pin #N removed.
Clear (/pin clear)
- Reset file to
{"items":[],"next_id":<keep current next_id>}
- Respond:
🗑️ Pin board cleared.
Clear Triage (/pin clear triage)
- Remove items where type is
approved or pending
- Keep items where type is
killed, scope, or correction
- Write file
- Respond:
🗑️ Triage cleared. <N> pins remaining.
Limits
- 5 items per type, 20 total
- When a category is full, drop the oldest item of that type (lowest id)
Key Behaviors
- One-line responses only. Never add commentary about pin content.
- Resume immediately. After any pin command, pick up the prior conversation exactly where it left off.
- Store verbatim. No cleanup, no categorization, no reformulation of user's words.
- Stable numbering. Gaps stay after deletion.
next_id always increments, never reuses.
1---2name: pin3description: Pin session decisions, questions, objections, scope constraints, and corrections to a persistent board that survives context compaction. Use PROACTIVELY when: (1) user approves/rejects a recommendation, (2) user asks a clarifying question about a proposal, (3) user states a scope constraint, (4) user corrects a misunderstanding. Also use when user says "pin", "track this", "mark as approved", "board", "show pins". This skill should be auto-invoked by the model without user asking — whenever a decision, question, or constraint is detected in conversation, pin it immediately after responding.4---56# Pin — Session Decision Board78Persist 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.910## Auto-Invoke Rules1112After 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.1314Examples of auto-invoke triggers:15- User: "yes go with bun" → respond normally, then `/pin ✅ use bun`16- User: "what about the latency impact?" → respond normally, then `/pin ❓ split services — latency impact?`17- User: "no skip auth for now" → respond normally, then `/pin ❌ auth layer — skip for MVP`18- User: "MVP only, max 3 files" → respond normally, then `/pin 📌 MVP only, max 3 files`19- User: "no I meant artisans not developers" → respond normally, then `/pin 🔧 target = artisans, not developers`2021Do NOT pin:22- Casual conversation, greetings23- Implementation details (code changes, file edits)24- Things already pinned (check board first)2526## Commands2728| Command | Action |29|---|---|30| `/pin ✅ <text>` | Pin approved item |31| `/pin ❓ <text>` | Pin pending question |32| `/pin ❌ <text>` | Pin killed/rejected item |33| `/pin 📌 <text>` | Pin scope constraint |34| `/pin 🔧 <text>` | Pin correction |35| `/pin show` or `/pin` | Display current board |36| `/pin rm <n>` | Remove pin by number |37| `/pin clear` | Clear all pins |38| `/pin clear triage` | Clear ✅/❓ only, keep 📌/❌/🔧 |3940## State File4142Path: `$PRAXIS_DIR/.session-logs/<slug>/pins.json`4344Derive slug from CWD:4546```bash47GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)48REL_PATH="${PWD#$GIT_ROOT/}"49SLUG=$(echo "$REL_PATH" | tr '/' '-')50PINS_DIR="$PRAXIS_DIR/.session-logs/$SLUG"51PINS_FILE="$PINS_DIR/pins.json"52```5354Schema:5556```json57{58 "items": [59 {60 "id": 1,61 "type": "approved",62 "emoji": "✅",63 "content": "use bun everywhere",64 "detail": "",65 "ts": "2026-04-01T14:30:00Z"66 }67 ],68 "next_id": 269}70```7172Type mapping: ✅=approved, ❓=pending, ❌=killed, 📌=scope, 🔧=correction7374## Pin (`/pin <emoji> <text>`)7576Parse the emoji prefix to determine type. Text after emoji is content. If text contains ` — `, split into content and detail.77781. Derive `PINS_FILE` path (see State File above)792. `mkdir -p` the directory803. Read existing file or init `{"items":[],"next_id":1}`814. Check if content already pinned (exact match on content field) → if so, respond `⚠️ Already pinned.` and stop825. Check limits: 5 items per type, 20 total. If category full, drop oldest item of that type.836. Append new item with `id=next_id`, increment `next_id`847. Write file858. Respond: `📌 Pinned #N: <emoji> <content>` — one line only, then resume prior work8687## Show (`/pin show` or `/pin`)88891. Read `PINS_FILE`902. If file missing or items empty: `📋 Pin board is empty.`913. Display:9293```94📋 Pin Board (5 items)95 1. ✅ use bun everywhere (minor: keep fallback for CI)96 2. ✅ split the PR into 297 3. ❓ split services — latency impact?98 4. ❌ auth rewrite — out of MVP scope99 5. 📌 MVP only, max 3 files100```101102## Remove (`/pin rm <n>`)103104If no number: `⚠️ Usage: /pin rm <number>`1051061. Read `PINS_FILE`, find item with `id === n`1072. If not found: `⚠️ Pin #N not found.`1083. Remove item, write file1094. Respond: `🗑️ Pin #N removed.`110111## Clear (`/pin clear`)1121131. Reset file to `{"items":[],"next_id":<keep current next_id>}`1142. Respond: `🗑️ Pin board cleared.`115116## Clear Triage (`/pin clear triage`)1171181. Remove items where type is `approved` or `pending`1192. Keep items where type is `killed`, `scope`, or `correction`1203. Write file1214. Respond: `🗑️ Triage cleared. <N> pins remaining.`122123## Limits124125- 5 items per type, 20 total126- When a category is full, drop the oldest item of that type (lowest id)127128## Key Behaviors129130- **One-line responses only.** Never add commentary about pin content.131- **Resume immediately.** After any pin command, pick up the prior conversation exactly where it left off.132- **Store verbatim.** No cleanup, no categorization, no reformulation of user's words.133- **Stable numbering.** Gaps stay after deletion. `next_id` always increments, never reuses.