Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions scripts/install-skills.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# Install (or uninstall) agent-memory skills for Claude Code, Codex, Cursor, and Agent CLI.
# Install (or uninstall) agent-memory skills for Claude Code, Codex, Cursor, Agent CLI, pi, and Qoder.
# Usage: bash scripts/install-skills.sh [--uninstall]

set -euo pipefail
Expand Down Expand Up @@ -63,12 +63,14 @@ SKILL_DIRS=(
"$HOME/.codex/skills/agent-memory"
"$HOME/.cursor/skills/agent-memory"
"$HOME/.agents/skills/agent-memory"
"$HOME/.qoder/skills/agent-memory"
)
SKILL_LABELS=(
"Claude Code skill"
"Codex skill"
"Cursor skill"
"Agent CLI skill"
"Qoder skill"
)

if $UNINSTALL; then
Expand All @@ -77,13 +79,39 @@ if $UNINSTALL; then
for i in "${!SKILL_DIRS[@]}"; do
uninstall_skill "${SKILL_LABELS[$i]}" "${SKILL_DIRS[$i]}"
done
# pi extension (has .ts not .md)
if [ -f "$HOME/.pi/extensions/agent-memory.ts" ]; then
rm "$HOME/.pi/extensions/agent-memory.ts"
echo "Uninstalled pi extension: $HOME/.pi/extensions/agent-memory.ts"
else
echo "Skipping pi extension (not installed)"
fi
echo ""
echo "Done."
else
install_skill "Claude Code skill" "$PROJECT_DIR/skills/claude-code" "$HOME/.claude/skills/agent-memory" "$HOME/.claude" '[ -f "$HOME/.claude/settings.json" ] || [ -f "$HOME/.claude/settings.local.json" ] || command_exists claude'
install_skill "Codex skill" "$PROJECT_DIR/skills/codex" "$HOME/.codex/skills/agent-memory" "$HOME/.codex" '[ -f "$HOME/.codex/config.toml" ] || command_exists codex'
install_skill "Cursor skill" "$PROJECT_DIR/skills/cursor" "$HOME/.cursor/skills/agent-memory" "$HOME/.cursor"
install_skill "Agent CLI skill" "$PROJECT_DIR/skills/agent" "$HOME/.agents/skills/agent-memory" "$HOME/.agents"
install_skill "Qoder skill" "$PROJECT_DIR/skills/qoder" "$HOME/.qoder/skills/agent-memory" "$HOME/.qoder" '[ -f "$HOME/.qoder/settings.json" ] || [ -f "$HOME/.qoder/settings.local.json" ] || command_exists qoder'

# pi extension (copies extension.ts → agent-memory.ts)
echo "Detecting pi extension..."
if [ ! -d "$HOME/.pi" ]; then
echo "Not found ($HOME/.pi not found)"
elif [ -z "$(command_exists pi)" ] && [ ! -d "$HOME/.pi/extensions" ]; then
echo "Not found (not detected)"
else
echo "Found"
if [ -d "$PROJECT_DIR/skills/pi" ]; then
mkdir -p "$HOME/.pi/extensions"
cp "$PROJECT_DIR/skills/pi/extension.ts" "$HOME/.pi/extensions/agent-memory.ts"
echo "Installed pi extension: $HOME/.pi/extensions/agent-memory.ts"
else
echo "Skipping pi extension ($PROJECT_DIR/skills/pi not found)"
fi
fi

echo ""
echo "Done."
fi
Expand All @@ -110,4 +138,4 @@ else
echo " $AGENT_MEMORY_BIN"
fi
echo ""
echo "Initialize memory: agent-memory init"
echo "Initialize memory: agent-memory init"
22 changes: 22 additions & 0 deletions skills/pi/extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";

/**
* AgentMemory extension for Pi Coding Agent.
*
* Subscribes to session_start and runs `agent-memory context` to inject
* persistent memory at the start of every session.
*/
export default function (pi: ExtensionAPI) {
pi.on("session_start", async (_event, ctx) => {
try {
const result = await pi.exec("agent-memory", ["context"], {
timeout: 10000,
});
if (result.stdout?.trim()) {
ctx.ui.notify(`Memory loaded: ${result.stdout.split("\n").length} lines`, "info");
}
} catch {
// agent-memory not installed or not on PATH — skip silently
}
});
}
164 changes: 164 additions & 0 deletions skills/qoder/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
---
name: agent-memory
description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and semantic search.
---

# Agent Memory

You have a persistent memory system. Use it **proactively** — don't wait to be asked.

## Current Memory Context

Run this to load memory context at session start:

```bash
agent-memory context --no-search 2>/dev/null
```

## Session Lifecycle

### On session start
1. Run `agent-memory context` to load memory — especially check **open scratchpad items** (pick up where you left off)
2. If the user's task relates to prior work, search for relevant memories:
```bash
agent-memory search --query "<topic>" --mode keyword
```

### On session end (after significant work)
1. Log what was accomplished in the daily log
2. Mark completed scratchpad items as done; add new follow-ups
3. Only write to long-term memory if you discovered a **durable fact** that doesn't already exist there

## Where to Write — Decision Guide

**Default to daily. Long-term is rare.**

| What happened | Write to | Why |
|---|---|---|
| Made progress, fixed a bug, investigated something | `daily` | Session-specific — searchable later via qmd |
| Tracking a topic or event across days | `topic` | Builds a per-topic file with backlinks to daily logs |
| User said "remember this" about a preference or decision | `long_term` | Durable fact, needs to be in every session's context |
| Discovered a recurring pattern (3rd time seeing it) | `long_term` | Graduated from daily observations to established fact |
| Found a gotcha, workaround, or non-obvious behavior | `daily` first | If it keeps coming up, *then* promote to long-term |
| TODO or follow-up for any task (persistent todo) | `scratchpad` | Persistent, cross-session task tracking |

**MEMORY.md is a curated wiki, not a log.** It should stay under ~50 lines of high-signal content. If you're appending to it frequently, you're probably writing to the wrong target.

## Memory Commands

### Write to daily log (default — no --target needed)

```bash
# Session notes, progress, bugs found, decisions made
agent-memory write --content "Fixed auth bug in login.ts — token refresh was missing"
agent-memory write --content "Investigated slow queries — N+1 in getUserOrders, added .include(:orders)"
```

### Write to long-term memory (rare, curated)

```bash
# Only for durable facts that belong in every session's context
agent-memory write --target long_term --content "Project uses Drizzle ORM with PostgreSQL. Migrations in db/migrations/. #architecture"

# Overwrite MEMORY.md entirely (for curation — rewrite, don't append)
agent-memory write --target long_term --content "..." --mode overwrite
```

When writing to long-term, prefer **overwrite mode** to curate the whole file rather than blindly appending. Read it first, then rewrite with the new fact incorporated.

### Write to a topic/event file

```bash
# Event- or theme-based log with backlinks to the daily entry
agent-memory write --target topic --topic "auth" --content "JWT refresh rolled out to edge #auth"
```

### Read

```bash
agent-memory read --target daily # Today's log
agent-memory read --target daily --date 2026-02-15 # Specific day
agent-memory read --target list # All daily log files
agent-memory read --target topic --topic "auth"
agent-memory read --target topics # All topic files
agent-memory read --target long_term # MEMORY.md
agent-memory read --target scratchpad # Scratchpad checklist
```

### Scratchpad (persistent TODOs)

```bash
agent-memory scratchpad add --text "Review PR #42"
agent-memory scratchpad list
agent-memory scratchpad done --text "PR #42" # Matches by substring
agent-memory scratchpad undo --text "PR #42"
agent-memory scratchpad clear_done # Remove completed items
```

### Search — recall past work

Search is how you find things written to daily logs. Use it before duplicating effort.

```bash
agent-memory search --query "database choice" --mode keyword # Fast keyword
agent-memory search --query "how we handle auth" --mode semantic # Finds related concepts
agent-memory search --query "performance" --mode deep --limit 10 # Hybrid + reranking
```

If qmd is not installed, fall back to reading files directly:
```bash
agent-memory read --target long_term
agent-memory read --target daily
```

### Setup

```bash
agent-memory init # Create dirs, detect qmd, setup collection
agent-memory sync # Re-index and embed all files (requires qmd)
agent-memory status # Show config, file counts, qmd status
```

## Writing Good Entries

### Daily log entries
Describe what you did and what you learned. Include `#tags`.

**Recommended tags** (use what fits, invent your own as needed):
`#architecture` `#auth` `#bugfix` `#database` `#deploy` `#docs` `#ops` `#perf` `#refactor` `#security` `#testing` `#ui`

```bash
# Good — specific, searchable, tagged
agent-memory write --content "Refactored auth middleware to use jose instead of jsonwebtoken. Reduced bundle by 40KB. #refactor #auth"

# Bad — too vague, no tags
agent-memory write --content "worked on auth stuff"
```

### Long-term entries
Only facts that should appear in **every** session's context. Use `#tags` and `[[links]]`.

```bash
# Good — this belongs in every session
agent-memory write --target long_term --content "Deploy: 'bun run deploy:prod', requires AWS_PROFILE=prod. #ops [[deploy]]"

# Bad — this is a daily log entry, not a durable fact
agent-memory write --target long_term --content "Fixed the deploy script today"
```

## Memory Hygiene

- **Daily is the default** — when in doubt, write to daily (no `--target` needed)
- **MEMORY.md is a wiki** — curate it by reading + rewriting, not by appending endlessly
- **Keep MEMORY.md under ~50 lines** — it's injected into every session, so only high-signal facts belong there
- **Search before writing long-term** — the fact may already exist in a daily log, searchable via qmd
- **Promote deliberately** — if a pattern appears in daily logs 3+ times, that's when it earns a spot in MEMORY.md

## Guidelines

- When someone says "remember this", decide: is it a durable fact (long-term) or a session note (daily)?
- Default to daily for almost everything (just `--content "..."` — no `--target` needed)
- Use `--target long_term` sparingly: architecture, preferences, key commands, hard-won lessons
- Prefer the scratchpad for any TODOs or follow-ups (persistent, cross-session tracking)
- Use `#tags` and `[[links]]` in content to improve search recall
- Use `agent-memory search` to recall past work before starting related tasks
26 changes: 23 additions & 3 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,24 @@ export function installSkills(): InstallSkillsReport {
destDir: path.join(homeDir, ".cursor", "skills", "agent-memory"),
homeMarker: path.join(homeDir, ".cursor"),
},
{
label: "pi extension",
srcDir: path.join(skillsDir, "pi"),
destDir: path.join(homeDir, ".pi", "extensions"),
homeMarker: path.join(homeDir, ".pi"),
detectCommand: "pi",
},
{
label: "Qoder skill",
srcDir: path.join(skillsDir, "qoder"),
destDir: path.join(homeDir, ".qoder", "skills", "agent-memory"),
homeMarker: path.join(homeDir, ".qoder"),
detectFiles: [
path.join(homeDir, ".qoder", "settings.json"),
path.join(homeDir, ".qoder", "settings.local.json"),
],
detectCommand: "qoder",
},
{
label: "Agent CLI skill",
srcDir: path.join(skillsDir, "agent"),
Expand Down Expand Up @@ -1016,15 +1034,17 @@ export function installSkills(): InstallSkillsReport {
detected.push({ label: target.label, homeMarker: target.homeMarker });
checked.push({ label: target.label, status: "detected" });

const skillFile = path.join(target.srcDir, "SKILL.md");
const isPiExt = target.label === "pi extension";
const skillFile = path.join(target.srcDir, isPiExt ? "extension.ts" : "SKILL.md");
if (!fs.existsSync(skillFile)) {
skipped.push({ label: target.label, reason: `${skillFile} not found` });
continue;
}

fs.mkdirSync(target.destDir, { recursive: true });
fs.copyFileSync(skillFile, path.join(target.destDir, "SKILL.md"));
installed.push({ label: target.label, path: path.join(target.destDir, "SKILL.md") });
const destFile = path.join(target.destDir, isPiExt ? "agent-memory.ts" : "SKILL.md");
fs.copyFileSync(skillFile, destFile);
installed.push({ label: target.label, path: destFile });
}

return {
Expand Down
Loading