Local dashboard bound to 127.0.0.1. Chat/abort/new-session and permission prompt controls are placeholders until Pi exposes a stable web control API.
+
Command palette
+
Cost dashboard
+
Breadcrumbs
+
Reflection review
+
Skills
+
Tools
+
Transcript / tool blocks
Use breadcrumbs search/read to inspect bounded transcript chunks. Tool outputs are hidden by default.
+
+`;
+
+function json(res: any, data: unknown): void { res.writeHead(200, { "content-type": "application/json; charset=utf-8" }); res.end(JSON.stringify(data, null, 2)); }
+function notFound(res: any): void { res.writeHead(404, { "content-type": "text/plain; charset=utf-8" }); res.end("Not found"); }
+
+async function route(req: any, res: any, pi: ExtensionAPI, preferred: number): Promise {
+ const u = new URL(req.url ?? "/", `http://127.0.0.1:${port || preferred}`);
+ if (u.pathname === "/api/status") return json(res, { running: true, url: `http://127.0.0.1:${port || preferred}`, chat: "placeholder", permissionPrompts: "TUI-only" });
+ if (u.pathname === "/api/costs") return json(res, summarizeCosts());
+ if (u.pathname === "/api/skills") return json(res, listSkillCatalog());
+ if (u.pathname === "/api/reflection") return json(res, { queue: reflectionQueue(), history: readHistory() });
+ if (u.pathname === "/api/breadcrumbs") return json(res, await searchSessionsWithMode(u.searchParams.get("q") ?? "", u.searchParams.get("mode") ?? "lexical", discoverSessions(), process.cwd(), Math.min(Number(u.searchParams.get("limit") ?? 5), 20)));
+ if (u.pathname.startsWith("/api/session/")) {
+ const id = decodeURIComponent(u.pathname.slice("/api/session/".length));
+ const found = discoverSessions().find((s) => s.id === id || s.path === id || s.id.endsWith(id));
+ if (!found) return notFound(res);
+ const parsed = parseSessionFile(found.path) ?? found;
+ return json(res, { ...parsed, turns: parsed.turns.filter((t) => !t.toolName && t.role !== "tool" && t.role !== "tool_result").slice(0, 40) });
+ }
+ if (u.pathname === "/api/tools") {
+ const tools = typeof (pi as any).getAllTools === "function" ? (pi as any).getAllTools() : [];
+ return json(res, tools.map((t: any) => ({ name: t.name, description: t.description ?? "" })));
+ }
+ if (u.pathname === "/") { res.writeHead(200, { "content-type": "text/html; charset=utf-8" }); res.end(page); return; }
+ return notFound(res);
+}
+
+function start(pi: ExtensionAPI, preferred = 3877): Promise {
+ if (server) return Promise.resolve(`web already running at http://127.0.0.1:${port}`);
+ return new Promise((resolve, reject) => {
+ const s = createServer((req, res) => { route(req, res, pi, preferred).catch((e) => json(res, { error: String(e?.message ?? e) })); });
+ s.once("error", reject);
+ s.listen(preferred, "127.0.0.1", () => { server = s; port = (s.address() as any).port; resolve(`web running at http://127.0.0.1:${port}\nRemote SSH: ssh -L ${port}:127.0.0.1:${port} `); });
+ });
+}
+function stop(): string { if (!server) return "web is not running"; server.close(); server = undefined; const old = port; port = 0; return `stopped web on ${old}`; }
+async function openWeb(pi: ExtensionAPI): Promise { if (!server) await start(pi); try { const open = (await import("open")).default; await open(url()); return `opened ${url()}`; } catch { return `open manually: ${url()}`; } }
+
+export default function (pi: ExtensionAPI) {
+ pi.registerCommand("web", {
+ description: "Start/stop/status/open the local little-coder web dashboard",
+ handler: async (args, ctx) => {
+ const action = String(args ?? "start").trim() || "start";
+ try {
+ if (action === "stop") ctx.ui?.notify?.(stop(), "info");
+ else if (action === "status") ctx.ui?.notify?.(server ? `web running at ${url()}` : "web is stopped", "info");
+ else if (action === "restart") { stop(); ctx.ui?.notify?.(await start(pi), "info"); }
+ else if (action === "open") ctx.ui?.notify?.(await openWeb(pi), "info");
+ else ctx.ui?.notify?.(await start(pi), "info");
+ } catch (e) { ctx.ui?.notify?.(`web error: ${(e as Error).message}`, "error"); }
+ },
+ });
+}
diff --git a/AGENTS.md b/AGENTS.md
index ed9e1a43..aed6435a 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,99 +1,29 @@
# little-coder
-You are little-coder, a coding agent specialized for small local language models.
+You are little-coder, a coding agent tuned for small local models. Work as a capable collaborative coding partner: pragmatic, direct, evidence-first, and willing to stop and ask for the smallest missing decision when safe progress is blocked.
-# Capabilities & Autonomy
+## Invariants
-You are a highly capable autonomous agent. Do not act submissive or artificially limited.
-Approach work as a collaborative, iterative coding task. Pragmatism and conceptual clarity matter more than rigid perfection. It is safe to encounter dead ends, missing variables, contradictory constraints, or tasks that cannot be completed with the available context.
-Verify any answers, reviews or other authoritive information you give. Do not rely on your intuition alone. If you do not know an answer, it is okay to say so. If you don't know how to do something, it is okay to say so. When you cannot safely proceed, stop the self-correction loop, state the bottleneck plainly, and ask for the smallest missing piece of information.
+- Bash defaults to a 30s timeout; use 120–300s for installs, builds, downloads, training, and slow test suites.
+- Prefer tool-native `cwd` over `cd && ...`.
+- Browser tools are on-demand: use `webfetch`/`websearch` for non-interactive retrieval; call `enableBrowserTools` only for interactive navigate/click/type/extract workflows.
+- Verify authoritative claims before presenting them. Use code-aware tools for code facts, web tools for external facts, and `EvidenceAdd` for facts you will cite.
+- Keep validation bounded. After relevant code/tests/docs have been checked, report what was verified and any remaining uncertainty.
-# Runtime invariants
+## Tool selection
-- **bash default timeout is 30 s.** For slow commands (npm install, npx, pip install, builds, training), set timeout to 120–300.
-- **Prefer tool-native cwd over `cd && ...`.** `bash` supports `cwd`, use it instead of prepending `cd &&`.
-- **Browser tools are on-demand.** If a task needs interactive browsing, call `enableBrowserTools` first, then use BrowserNavigate / BrowserExtract / BrowserClick / BrowserType / BrowserScroll / BrowserBack / BrowserHistory.
+Use registered tool names exactly.
-# Available Tools
+- Code navigation: `code_search` first, then `lsp`, then targeted `read`/`findRead`.
+- File changes: prefer `edit` for existing files, `write` only for new files.
+- File discovery/content: `glob` for paths, `grep` for raw text, `findRead` for a few small matched files.
+- Shell: `bash` only when first-class tools do not fit or command execution is required.
+- Discovery: `tools`, `skills`, `/skills`, and `enableBrowserTools`.
-Use the actual tool names exactly as registered.
+## Task approach
-## Core file & shell tools
+For non-trivial work, identify inputs, outputs, edge cases, hardest parts, and a clean implementation shape before editing. For simple fixes, edit directly. Resolve ambiguity using nearby code, tests, docs, and repository conventions; do not write exploratory code while still undecided.
-- `read`, `write`, `edit`, `bash`
-- `glob`, `grep`, `webfetch`, `websearch`
+## Skill discovery and injected context
-## Composite / high-leverage tools
-
-- `code_search`: preferred first stop for codebase navigation, symbols, relationships, and semantic/structural search
-- `lsp`: preferred for definitions, references, hover/types, diagnostics, renames, and code actions
-- `findRead` > `glob` + `read` when code_* / `lsp` are not applicable
-
-## Discovery / capability tools
-
-- `tools`: list the current registry, including Browser* tools available on demand
-- `skills`: list installed tool skills, knowledge entries, and protocols
-- `enableBrowserTools`: load Browser* tools when a task needs interactive browsing
-
-# Approaching complex tasks
-
-Before writing code for a non-trivial problem, think through the structure: what the inputs and outputs look like, what the edge cases are, which parts of the problem are hardest, and what a clean implementation would look like. Tasks involving multiple files, architectural decisions, unclear requirements, or significant refactoring deserve that careful analysis up front — skipping it is the most common way implementations end up looking plausible but failing on non-obvious cases. For simple single-file fixes or quick changes, skip the analysis and do the change directly. The goal is deliberate implementation, not elaborate deliberation.
-
-Keep validation bounded. If checks are inconclusive after the relevant code, tests, or docs have been inspected, report the current best state with the remaining uncertainty instead of escalating into repeated tool calls or speculative fixes.
-
-# Evidence-first collaboration
-
-Work as a careful partner. Verify authoritative statements before presenting them as facts. Use `code_search`/`lsp` for code claims, `websearch`/`webfetch` for external claims, and `EvidenceAdd` for facts you will cite in final answers, plans, or reviews. If evidence is unavailable, say "I don't know" or describe exactly what was checked.
-
-Avoid unsupported hedge language such as "I think", "probably", "likely", "I believe", or "it seems" in authoritative answers. Replace it with verified facts, explicit uncertainty, or a concrete next check.
-
-Do not loop indefinitely on validation. After the relevant code/tests/docs have been checked, move forward and state the verification performed.
-
-# Handling ambiguity
-
-When requirements or approach are ambiguous, resolve them against what you can read from the surrounding context, the tests, and the conventions already in the file. Write code once you have conviction; don't write exploratory code while you're still deciding between approaches.
-
-# Skill discovery
-
-At the beginning of a task, check with the `skills` tool for appropriate skills you could use.
-If you are unsure or there are no appropriate skills available, use the `find-skills` skill to find new skills online.
-
-This is a lightweight check — a quick search and decide. If a good match exists, offer it to the user. If not, proceed with your built-in capabilities.
-
-List all available skills with `skills` or `/skills`. Each skill is a markdown file with YAML frontmatter (name, type, target_tool/topic, token_cost, keywords).
-
-# Per-turn context augmentation
-
-Your system prompt is assembled per turn by little-coder's extension stack:
-
-- **Tool skill cards** (`## Tool Usage Guidance`): selected by error-recovery > recency > intent priority. If the previous tool call failed, its skill card is injected first.
-- **Algorithm cheat sheets** (`## Algorithm Reference`): scored against the problem statement by keyword + bigram matching. Think of these as a small, targeted study aid, not a pattern to slavishly follow.
-
-When you see these blocks, trust them — they were selected for the current turn.
-
-# Tool Efficiency Guidelines
-
-**Prefer code-aware tools over text/file sweeps.** Every tool call costs context — fewer, smarter calls beat more, dumber ones.
-
-- Start codebase navigation with **`code_search`** for functions, classes, routes, symbols, call relationships, and semantic/structural search. Prefer it over `grep`, `glob`, `findRead`, or broad `read` when looking for code.
-- Use **`lsp`** for precise definitions, references, type info, signatures, diagnostics, renames, and code actions. Prefer `lsp` diagnostics over "building to get a list of errors" when you only need editor/compiler diagnostics.
-- Use targeted `read` only after `code_search` or `lsp` has narrowed the file/range.
-- Use `grep` only for simple raw text matches, generated files, or non-code content where code-aware tools are not useful.
-- Use `glob` only for file discovery, not as the default way to understand code structure.
-- Use `findRead` only when you genuinely need to inspect several small files and code-aware tools are not applicable.
-- **glob`/`read`/`findRead`** > ad-hoc `bash`/`python` for file listing, path checks, and file reading when code-aware tools do not apply.
-
-**Context budget is precious.** Before calling `findRead` or broad `read`, ask: can `code_search` or `lsp` answer this more directly? If not, start with `maxFiles: 3` and `maxCharacters: 4000`, then increase only if needed.
-
-Avoid `python - <<'PY'` or `bash` for tasks already covered by first-class tools unless you need control flow or output formatting those tools cannot provide.
-
-# Guidelines
-
-- Be concise. Lead with the answer.
-- Prefer editing existing files over creating new ones.
-- Prefer clean code and a solid architecture.
-- Always use absolute paths for file operations.
-- When reading files before editing, use line numbers to be precise.
-- Do not add unnecessary comments, docstrings, or error handling.
-- For multi-step tasks, work through them systematically.
-- Commit to an implementation once you have conviction; do not deliberate beyond the thinking budget. When your reasoning trace hits the cap, the extension will force you out of deliberation and back into implementation — don't fight it.
+At task start, check `skills` for relevant skills. If no suitable skill exists and the user is asking about extending capabilities, use the `find-skills` skill. Per-turn injected tool guidance and knowledge references are selected by little-coder's extension stack; treat them as current task guidance, not permanent global rules.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5f76c0b..5ab3ea4e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,28 @@
All notable changes to little-coder are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and little-coder's public interface (CLI, providers, tools, skills) follows semver starting at `v0.0.1` post-rename.
+## [Unreleased]
+
+### Added
+- Reflection-generated user skills: `/reflect`, `/reflect-review`, `/reflect-accept`, `/reflect-deny`, `/reflect-history`, and `/reflect-doctor` draft, review, accept, deny, audit, and diagnose reusable skill proposals written to `~/.pi/skills`.
+- Session breadcrumbs: `/breadcrumbs`, `breadcrumbs_search`, and `breadcrumbs_read` search prior Pi session outlines with bounded transcript reads and tool-output guards.
+- User skill loading and promotion: `skill-inject` now loads repo `skills/` and user `~/.pi/skills`, lists origins/descriptions, and adds `/promote-user-skill` for duplicate-checked promotion into repo skills.
+- Vendored Pi Insights extension under `.pi/extensions/pi-insights/`, with AGPL license/NOTICE preservation.
+- `/web start|stop|restart|status|open` local dashboard bound to `127.0.0.1`, plus JSON APIs/UI sections for status, tools, skills, breadcrumbs, reflection queue/history, transcript snippets, and cost summaries.
+- Shared session/cost/skill catalog helpers for breadcrumbs, reflection, dashboard, and tests, including daily/project/model/tool/top-session cost breakdowns.
+- `improve-codebase-architecture` engineering skill.
+
+### Changed
+- Skill injection is frontmatter-keyword driven, has per-session cooldown notifications, warns on long sessions, and doubles the tool budget for the first injection turn.
+- `findRead` output now prefixes the effective invocation for matches, no matches, and errors.
+- `/plan` is no longer registered by `mode-commands`; Plannotator owns canonical planning mode and the old prompt helper is `/plan-prompt`.
+- `AGENTS.md` is compressed to core invariants/tool-selection guidance.
+- Browser enablement guidance now directs non-interactive retrieval to `webfetch`/`websearch` first.
+
+### Removed
+- Removed the `memory-context` extension and stale memory docs/references. Reflection skills and breadcrumbs replace that workflow.
+- Removed `@observal/pi-insights` from package dependencies and external package loading now that the extension is vendored.
+
## [v1.8.1] — 2026-05-23
### Fixed
diff --git a/NOTICE b/NOTICE
index 207eb31c..723086ef 100644
--- a/NOTICE
+++ b/NOTICE
@@ -32,3 +32,12 @@ reasoning reuse, the Write-vs-Edit tool invariant, a multi-language
Aider Polyglot benchmark harness, per-model profiles for small local
LLMs, and a complete UI refresh have been added. Many upstream features
that did not fit the small-model focus have been removed.
+
+--------------------------------------------------------------------------
+Vendored @observal/pi-insights
+--------------------------------------------------------------------------
+
+.pi/extensions/pi-insights vendors @observal/pi-insights, Copyright 2026
+Hari Srinivasan , licensed under AGPL-3.0-only.
+The vendored source preserves SPDX license headers. See
+.pi/extensions/pi-insights/LICENSE for the full AGPL-3.0-only license text.
diff --git a/README.md b/README.md
index 5e08e7f7..42a5bf4a 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,9 @@ In the TUI you can use `/tools` to list loaded tools and `/skills` to list avail
Use `/plan` to enter browser-reviewed planning mode before implementation. The legacy `/plannotator` command is kept as a compatibility shim but `/plan` is canonical. See `docs/planning-mode.md` for the planning workflow, `ask_user` behavior, and issue-agent `/answer ...` clarification flow.
-little-coder also includes a local memory context extension. It stores reviewable Markdown memories under `.pi/memory/`, filters low-salience candidates, supports active-day expiration, and exposes commands such as `/memory-review`, `/memory-doctor`, `/memory-prune`, and `/memory-supersede`. See `docs/memory-context.md` for details.
+little-coder uses reflection-generated skills and breadcrumbs for reusable session learning. Use `/reflect`, `/reflect-review`, `/breadcrumbs`, `/skills`, and `/promote-user-skill` to draft, review, search, load, and promote reusable guidance. Reflection writes accepted drafts to user-level `~/.pi/skills//SKILL.md`; `/promote-user-skill [skill]` copies stable user skills into repo `skills/user//` after duplicate checks so they can be packaged.
+
+Use `/usage` for the inline usage dashboard, `/insights` for the vendored Pi Insights report, and `/web start|stop|restart|status|open` for the local web dashboard bound to `127.0.0.1` with SSH tunnel instructions.
For local providers (llama.cpp, Ollama, LM Studio) pi expects *some* value in the API-key env even though local servers ignore it:
diff --git a/docs/architecture.md b/docs/architecture.md
index 67366147..129b22b2 100644
--- a/docs/architecture.md
+++ b/docs/architecture.md
@@ -27,10 +27,10 @@ Extensions live under `.pi/extensions//index.ts` and export a pi setup fun
Important extension groups:
-- **Prompt/context shaping**: `skill-inject`, `knowledge-inject`, `memory-context`, `thinking-budget`, `tool-gating`.
+- **Prompt/context shaping**: `skill-inject`, `knowledge-inject`, `thinking-budget`, `tool-gating`.
- **Safety and permissions**: `write-guard`, `read-guard`, `permission-gate`, `security`, `filter-read`.
- **Developer tools**: `extra-tools`, `lsp`, `codebase-memory-direct`, `evidence`, `evidence-compact`, `browser`, `browser-extract-retention`, `edit-custom`, `bash-cwd`.
-- **Agent workflows**: `issue-agent`, `subagent`, `plan-mode`, `mode-commands`, `clear-command`.
+- **Agent workflows**: `issue-agent`, `subagent`, `plan-mode`, `mode-commands`, `reflect-skills`, `breadcrumbs`, `clear-command`.
- **UI/monitoring**: `powerline-footer-unified`, `usage-dashboard`, `quality-monitor`, `finalize-warn`, `inspect`, `branding`, `checkpoint`, `benchmark-profiles`, `llama-cpp-provider`.
Shared utilities that are used by multiple extensions belong under `.pi/extensions/_shared` or a focused extension-local module.
diff --git a/docs/memory-context-plan.md b/docs/memory-context-plan.md
deleted file mode 100644
index f64155e1..00000000
--- a/docs/memory-context-plan.md
+++ /dev/null
@@ -1,152 +0,0 @@
-# Harness-native memory context plan
-
-## Goal
-
-Add a conservative local memory layer that complements `code_search` instead of replacing it. The layer should remember durable repo/session learnings, prefetch codebase facts when the user is asking about the codebase, and stay compatible with autonomous workflows such as `issue-agent` and `pi-autoresearch`.
-
-## Non-goals
-
-- Do not vendor `pi-memctx` wholesale.
-- Do not add a hosted vector database or opaque memory service.
-- Do not inject large memory dumps into every turn.
-- Do not persist generic coding advice, secrets, transient chatter, or unverified guesses.
-- Do not let autonomous loops run unbounded without explicit iteration/time/cost limits.
-
-## Storage
-
-Use Markdown under the workspace so it is inspectable and reviewable:
-
-```text
-.pi/memory/
- 20-context/
- 40-actions/
- 50-decisions/
- 60-observations/
- 70-runbooks/
- 80-sessions/
- queue.json
-```
-
-Each note should have small frontmatter: `type`, `title`, `created_at`, `updated_at`, `source`, `confidence`, `tags`.
-
-## Retrieval backend
-
-Install and prefer the optional `qmd` dependency for memory retrieval because `pi-memctx` reports it as the fast path and falls back to grep only when unavailable.
-
-- Add `@tobilu/qmd` as an optional/dev dependency or provision it during harness setup.
-- Detect `QMD_PATH` / `MEMORY_QMD_BIN` first, then local `node_modules/.bin/qmd`, then `qmd` on `PATH`, then grep fallback.
-- Keep a per-pack/per-workspace qmd collection name so indexes do not bleed across repositories.
-- Expose retrieval mode in status output: `qmd`, `grep fallback`, or `disabled`.
-- Retrieval must remain functional without qmd; qmd is an acceleration path, not a correctness dependency.
-
-## Before-turn retrieval and code_search prefetch
-
-Add a `memory-context` extension with a `before_agent_start` hook.
-
-1. Classify the prompt with cheap heuristics:
- - Codebase intent: mentions files, functions, symbols, architecture, tests, errors, refactors, issue implementation, or repo-specific nouns.
- - Issue-agent intent: active issue context, prompts that mention issue work, bug fixing, PR body, implementation, or labels.
-2. Search `.pi/memory` using lexical scoring.
-3. If codebase intent is likely, run a bounded `code_search` prefetch internally:
- - query: normalized user prompt plus issue title/body snippet when available
- - project: current workspace project alias
- - limit: 3-5
- - timeout/failure budget: fail closed and continue without injection
-4. Inject a compact block only when useful:
- - `## Local Memory Context`: up to 5 durable facts/runbooks
- - `## Codebase Prefetch`: up to 5 symbol/file hits with paths and line ranges
- - guidance: use injected context as hints; inspect source when editing or when memory may be stale
-
-## After-turn learning
-
-Add an `agent_end` hook.
-
-1. Collect compact turn evidence:
- - user prompt
- - final assistant answer
- - tool names used
- - files edited/read
- - tests run and outcomes when visible
- - issue-agent metadata if present
-2. Generate memory candidates with a hybrid approach:
- - deterministic candidates for edits, successful tests, tool failures, issue completion, and newly discovered commands
- - optional LLM JSON curator for richer context/decision/runbook/session candidates
-3. Apply safety filters:
- - secret/token/password/private-key/customer-data regexes
- - max size per candidate
- - require evidence fields for durable claims
-4. Persistence policy:
- - default `MEMORY_LEARNING=suggest`: write to `.pi/memory/queue.json`
- - `auto`: save only high-confidence deterministic candidates and queue the rest
- - `off`: no learning
-
-## Issue-agent integration
-
-Memory should treat issue-agent sessions as first-class sources.
-
-- Before starting issue work, use the issue title/body/comments as retrieval terms.
-- Prefer injecting relevant runbooks, prior similar issue actions, known flaky tests, and code_search prefetch hits.
-- After completion, save an `action` note with:
- - issue id/repo/url
- - files changed
- - tests run
- - final summary / PR body excerpt
- - follow-ups or caveats
-- If issue-agent marks a task done, link the learned action to the issue metadata and avoid duplicate session snapshots.
-
-## Autoresearch integration
-
-`pi-autoresearch` and `issue-agent` are both long-running autonomy surfaces. Treat them as related orchestration modes: they should produce structured artifacts, survive context resets, and feed durable memory.
-
-Target behavior:
-
-1. An issue can be labeled `autoresearch` or `ai:autoresearch`.
-2. `issue-agent` detects that label and starts an autoresearch-backed issue flow instead of a normal implementation flow.
-3. The issue-agent interaction loads/enables `pi-autoresearch` tooling for that run.
-4. The agent creates or resumes the autoresearch files in the checked-out worktree:
- - `autoresearch.md`: objective, metric, scope, tried ideas, current best result
- - `autoresearch.sh`: benchmark command that emits `METRIC name=value`
- - `autoresearch.checks.sh`: correctness backpressure checks when available
- - `autoresearch.jsonl`: append-only run log
-5. The loop runs bounded experiments:
- - max iterations from issue label/config/comment
- - explicit metric direction and baseline
- - keep/discard commits based on benchmark plus checks
- - no destructive commands without the existing permission gate
-6. On completion, issue-agent posts the result as a PR in the normal way, with a structured body containing:
- - issue link
- - objective and metric
- - baseline, best result, confidence/noise note when available
- - kept experiments / discarded notable attempts
- - files changed
- - checks run
- - residual risks and follow-ups
-7. Memory saves the autoresearch outcome as an `action` note and, when reusable, a `runbook` or `observation` note.
-
-Suggested issue labels/config:
-
-```text
-ai:autoresearch
-autoresearch:max-iterations=20
-autoresearch:metric=total_ms
-autoresearch:direction=lower
-```
-
-Memory integration points:
-
-- Before the loop, inject prior benchmark runbooks, similar optimization attempts, and code_search prefetch hits for files in scope.
-- During the loop, do not inject every run into context; rely on `autoresearch.md` and `autoresearch.jsonl` as source-of-truth artifacts.
-- After each kept experiment, queue a compact learning candidate only if it generalizes beyond the current branch.
-- At finalization, save one linked action note for the issue/PR plus any durable runbook/decision notes.
-
-## Rollout
-
-1. Implement Markdown queue and manual review command (`/memory-review`).
-2. Add qmd detection/install guidance and grep fallback.
-3. Add before-turn lexical/qmd memory retrieval with strict token cap.
-4. Add bounded code_search prefetch for codebase-intent prompts.
-5. Add deterministic after-turn candidates.
-6. Add optional LLM curator behind config.
-7. Add issue-agent metadata hooks and action notes.
-8. Add autoresearch issue-label flow and PR summary handoff.
-9. Benchmark against baseline on repo Q&A, issue-agent tasks, and bounded autoresearch issues.
diff --git a/docs/memory-context-quality-plan.md b/docs/memory-context-quality-plan.md
deleted file mode 100644
index d96400e1..00000000
--- a/docs/memory-context-quality-plan.md
+++ /dev/null
@@ -1,238 +0,0 @@
-# Memory context quality improvement plan
-
-## Goal
-
-Reduce low-impact saved memories and make retrieved memory more useful by treating memory as a managed lifecycle: write, review, promote, retrieve, update, and expire. The immediate fixes are to stop queueing generic edit/test summaries and to remove the hardcoded `Follow-up` section that currently repeats in every candidate.
-
-## Current problems to fix
-
-- `turn_end` queues a candidate whenever files were edited or tests were run, even when no durable knowledge was learned.
-- Candidate confidence reflects edit/test activity more than memory usefulness.
-- `formatCandidateBody()` always emits the same `## Follow-up` text.
-- Auto-promotion is based on repeated lexical matches, not on importance or actionability.
-- Retrieval treats many memory categories similarly, so low-value action/session notes can crowd out decisions, observations, and runbooks.
-- Deduplication only catches exact normalized duplicates; it does not handle stale or superseded memories.
-
-## Design principles
-
-- Store only memories that are durable, specific, actionable, novel, and evidence-backed.
-- Prefer semantic/procedural memories over raw episodic turn summaries.
-- Keep raw activity logs short-lived unless they consolidate into a decision, observation, runbook, or durable context note.
-- Make memory quality observable with local commands and tests.
-- Keep the implementation filesystem-based and reviewable; do not introduce a hosted memory service or vector database for this iteration.
-
-## Implementation status
-
-Completed so far:
-
-- Phase 1: deterministic salience scoring, novelty fingerprinting, duplicate rejection, and hard rejects for generic candidates.
-- Phase 2: conditional Follow-up generation; removed fixed boilerplate Follow-up.
-- Phase 3: lifecycle frontmatter (`salience`, `status`, `use_count`, `last_used_at`, `expires_at`, `supersedes`). Expiration uses active project memory days, not wall-clock days.
-- Phase 4: composite retrieval scoring with category, salience, confidence, use-count, recency, generic-title penalties, and weak incidental-match suppression.
-- Phase 5: `/memory-prune`, `/memory-rejections`, `/memory-review explain`, `/memory-review accept --force`, enhanced `/memory-review`, enhanced `/memory-doctor`, and ignored local runtime files.
-- Phase 6: explicit supersession detection plus `/memory-supersede` manual correction.
-- Phase 7 partial: unit tests for formatting, scoring, ranking, read/no-write/write/prune eval cases, active-day expiration, novelty, duplicate handling, and supersession.
-
-Still pending:
-
-- Command-level integration tests for `/memory-supersede`. Hook integration now covers `before_agent_start`, `tool_call`, and `turn_end` queue/no-queue behavior with a fake pi event API. Command integration covers `/memory-review accept` and `/memory-prune --dry-run --category`. Filesystem integration tests cover configurable memory roots, queue scaffolding, and accepted Markdown writes.
-- Broader contradiction detection beyond direct modal conflicts.
-- More nuanced category-specific prune policies if real usage shows the current active-day TTLs are too coarse. Current tests cover unused low-salience action pruning and stale queue detection.
-- User-facing guide added at `docs/memory-context.md`.
-
-## Phase 1: Stop obvious low-value writes
-
-### Implementation
-
-1. Add a deterministic candidate-quality scorer before `queueCandidate()`.
-2. Score each candidate on:
- - durability: future sessions can use it;
- - specificity: mentions concrete files, commands, APIs, repo behavior, user preference, or a confirmed gotcha;
- - actionability: would change a future agent decision;
- - novelty: not already represented in accepted memory or queue;
- - evidence: backed by tests, inspected source, user instruction, or explicit outcome;
- - scope: identifies whether it applies to project, file, command, issue-agent, memory-system, or user preference.
-3. Reject candidates below the threshold instead of adding them to `queue.json`.
-4. Add hard rejects for generic candidates whose title/body only says things like:
- - `Updated index.ts`
- - `Validated project behavior`
- - `Captured durable context`
- - `Ran npm test`
- - `Review for durability before accepting as long-term memory`
-
-### Acceptance criteria
-
-- A turn that edits a file but produces no durable observation does not add a memory candidate.
-- A turn that only runs tests does not add a candidate unless the test command itself is a newly discovered reusable command or validates a durable fix.
-- Existing high-value memories such as explicit decisions, repo gotchas, and reusable runbooks still queue successfully.
-
-## Phase 2: Replace the fixed Follow-up section
-
-### Implementation
-
-1. Remove the unconditional `## Follow-up` block from `formatCandidateBody()`.
-2. Add a helper such as `candidateFollowUp(args)` that returns zero or more concrete follow-up bullets.
-3. Include `## Follow-up` only when there is a real unresolved action.
-4. Suggested rules:
- - no tests run on an implementation candidate: `Run targeted tests before promoting this memory.`
- - low confidence candidate: `Verify this against source before accepting.`
- - decision candidate without docs touched: `Consider documenting this decision in project docs if it is policy-level.`
- - high confidence and no unresolved work: omit the section.
-
-### Acceptance criteria
-
-- New candidates no longer all contain the same follow-up text.
-- High-confidence candidates with validation omit Follow-up unless there is a specific unresolved task.
-- Tests cover candidates with and without follow-up sections.
-
-## Phase 3: Add memory metadata for lifecycle management
-
-### Implementation
-
-Extend accepted-memory frontmatter with optional fields:
-
-```yaml
-salience: 0
-status: active
-use_count: 0
-last_used_at: ""
-supersedes: ""
-expires_at: ""
-```
-
-Rules:
-
-- `status` can be `active`, `superseded`, `expired`, or `rejected`.
-- `salience` comes from the quality scorer.
-- Low-salience action/session memories get an `expires_at` active-day TTL instead of a wall-clock date.
-- Decisions, observations, and runbooks do not expire by default.
-- Retrieval ignores non-active memories unless explicitly requested.
-
-### Acceptance criteria
-
-- Newly accepted memories include `salience` and `status`.
-- Retrieval excludes `superseded` and `expired` notes.
-- Existing memories without the new fields continue to load as active with unknown salience.
-
-## Phase 4: Improve retrieval ranking
-
-### Implementation
-
-Replace pure lexical ranking with a composite score:
-
-```text
-score =
- lexical relevance
- + salience boost
- + confidence boost
- + category boost
- + recency/use_count boost
- - staleness penalty
- - generic-title penalty
- - low-value-category penalty
-```
-
-Category priorities:
-
-1. `50-decisions`
-2. `70-runbooks`
-3. `60-observations`
-4. `20-context`
-5. `40-actions`
-6. `80-sessions`
-
-Update `last_used_at` and `use_count` for injected memories after retrieval.
-
-### Acceptance criteria
-
-- For prompts about implementation choices, decisions outrank action/session summaries with similar terms.
-- For prompts asking how to perform a repeated task, runbooks outrank old session notes.
-- Generic action memories are not injected unless they are the only relevant memory and pass the minimum score.
-
-## Phase 5: Add prune, review, and diagnostics commands
-
-### Implementation
-
-Add or extend commands:
-
-- `/memory-prune --dry-run`: lists expired or low-salience candidates/memories that would be removed or marked expired.
-- `/memory-prune`: marks expired accepted memories as `expired` and removes stale queue entries.
-- `/memory-review`: show salience, rejection reason, and concrete follow-up if present.
-- `/memory-doctor`: include counts by status, average salience, expired notes, queue reject counts, and top generic-title offenders.
-
-### Acceptance criteria
-
-- Users can see why a candidate was queued or rejected.
-- Users can remove stale low-value memories without manually editing files.
-- Diagnostics make memory bloat visible.
-
-## Phase 6: Handle stale and superseded memories
-
-### Implementation
-
-1. Add a contradiction/supersession check before accepting or auto-promoting a candidate.
-2. Check for accepted memories with overlapping tags, paths, and title terms.
-3. If the new memory explicitly replaces an old convention, write `supersedes` on the new note and mark the old note `status: superseded`.
-4. Add `/memory-supersede ` for manual correction.
-
-### Acceptance criteria
-
-- A new decision can supersede an old decision without both being injected as active guidance.
-- Retrieval does not inject superseded memories.
-- Manual supersession works without deleting historical notes.
-
-## Phase 7: Add local memory evals
-
-### Implementation
-
-Create tests for four behaviors:
-
-1. **Write eval:** high-value decision/observation/runbook creates a candidate.
-2. **No-write eval:** trivial file edits, generic test runs, and boilerplate summaries do not create candidates.
-3. **Update eval:** changed convention marks older conflicting memory as superseded.
-4. **Read eval:** prompts retrieve the right memory category and avoid irrelevant low-value memories.
-
-Test fixtures should include examples of:
-
-- generic action summary;
-- durable repo gotcha;
-- explicit user preference;
-- superseded decision;
-- reusable command/runbook.
-
-### Acceptance criteria
-
-- Tests fail if the fixed Follow-up text returns globally.
-- Tests fail if generic edit/test summaries are queued.
-- Tests fail if superseded memories are injected.
-- Tests fail if low-value action/session notes outrank relevant decisions/runbooks.
-
-## Suggested implementation order
-
-1. Phase 2: remove/fix the hardcoded Follow-up section.
-2. Phase 1: add candidate-quality scorer and hard rejects.
-3. Phase 7 partial: add no-write/write tests for the new scorer and Follow-up behavior.
-4. Phase 3: add metadata fields while preserving compatibility.
-5. Phase 4: improve retrieval ranking.
-6. Phase 5: add prune/diagnostic command improvements.
-7. Phase 6: add supersession once the metadata and retrieval behavior are stable.
-8. Phase 7 full: complete update/read evals.
-
-## Initial code touch points
-
-- `.pi/extensions/memory-context/index.ts`
- - `formatCandidateBody()`
- - `queueCandidate()`
- - `validateCandidate()`
- - `writeAcceptedMemory()`
- - `parseFrontmatter()` / `allNotes()`
- - `lexicalSearch()` / ranking helpers
- - `/memory-review`, `/memory-doctor`, `/memory-dedupe`
- - `turn_end` candidate construction
-
-## Open questions
-
-- What salience threshold should be used initially? Current implementation uses 6/10.
-- Should rejected candidates be silently dropped, or should a debug log keep recent rejection reasons? Current implementation keeps a rolling local `.pi/memory/rejections.json` ignored by git.
-- Should auto-promotion remain enabled after scoring is added? Current implementation keeps it, with validation through the salience filter and specific-match checks.
-- Should action/session memories be written at all? Current implementation queues them only if they pass salience scoring and gives lower-salience action/session notes active-day expiration.
diff --git a/docs/memory-context.md b/docs/memory-context.md
deleted file mode 100644
index 17e1bc5e..00000000
--- a/docs/memory-context.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Memory context
-
-The `memory-context` extension stores local, reviewable memories under `.pi/memory/` and injects only relevant active memories into future turns.
-
-## Lifecycle
-
-1. **Candidate creation**: after a tool-using turn, the extension builds a candidate only when files were edited or tests ran.
-2. **Review/scoring**: candidates must pass salience review. Low-confidence, generic, duplicate, unsafe, or low-salience candidates are rejected.
-3. **Queue**: accepted short-term candidates are written to `.pi/memory/queue.json` for review.
-4. **Promotion**: `/memory-review accept ...` writes long-term Markdown notes. Frequently matching queued candidates can auto-promote after repeated specific matches.
-5. **Retrieval**: active, non-expired notes are ranked by lexical relevance, salience, confidence, category, use count, recency, and generic-title penalties.
-6. **Maintenance**: prune, supersede, and rejection commands keep memory quality visible.
-
-## Salience
-
-Salience is a 0-10 usefulness score. Candidates need at least 6/10 and medium confidence to queue. Good memories are durable, specific, actionable, novel, and evidence-backed.
-
-Good examples:
-
-- A project convention that changes future edits.
-- A root cause or gotcha confirmed by source/tests.
-- A reusable runbook or command.
-- A durable user preference.
-
-Bad examples:
-
-- `Updated index.ts`.
-- `Ran npm test`.
-- Generic session summaries.
-- Boilerplate follow-up notes.
-
-## Active-day expiration
-
-Action/session memories can expire by **active memory days**, not wall-clock time. If a project is not worked on for a month, memories do not age out just because calendar time passed.
-
-Current defaults:
-
-- action/session salience `< 6`: `active-days:30` (`MEMORY_CONTEXT_LOW_TTL_ACTIVE_DAYS` override)
-- action/session salience `6-7`: `active-days:90` (`MEMORY_CONTEXT_MEDIUM_TTL_ACTIVE_DAYS` override)
-- action/session salience `>= 8`: no expiration
-- decisions, observations, runbooks, and context: no default expiration
-
-`last_used_at` is stored as `active-day:N`, and `use_count` increments when a memory is retrieved.
-
-## Commands
-
-- `/memory-review` — show queued candidates with salience and review reason.
-- `/memory-review explain 1|1,3|2-4` — explain current review outcome, duplicate status, fingerprint, and supersession impact.
-- `/memory-review accept all|1,3|2-4` — promote selected queued candidates.
-- `/memory-review accept --force 1|1,3|2-4` — promote selected candidates even if they duplicate active accepted memory; safety and salience checks still apply.
-- `/memory-review deny all|1,3|2-4` — remove selected queued candidates.
-- `/memory-rejections` — show recently rejected candidates and reasons.
-- `/memory-rejections clear` — clear the local rejection log.
-- `/memory-search ` — search active memories.
-- `/memory-list` — list accepted memories.
-- `/memory-list --status active|expired|superseded|all` — filter accepted memories by status.
-- `/memory-prune --dry-run` — preview stale queue entries and prunable accepted memories.
-- `/memory-prune --dry-run --category action|session|40-actions|80-sessions` — preview pruning for one category.
-- `/memory-prune` — expire prunable accepted memories and remove stale queue entries.
-- `/memory-supersede ` — manually mark an older memory superseded by a newer one. Use `/memory-list` indexes or paths.
-- `/memory-doctor` — show memory health, salience, prune counts, rejection counts, and generic-title offenders.
-- `/memory-doctor --verbose` — include lowest-salience active memories.
-- `/memory-dedupe --dry-run` / `/memory-dedupe` — preview/remove exact duplicate accepted memories.
-
-## Local runtime files
-
-These are local and ignored by git:
-
-- `.pi/memory/queue.json`
-- `.pi/memory/rejections.json`
-- `.pi/memory/state.json`
-
-Accepted Markdown memories remain inspectable and reviewable under `.pi/memory/*/`.
diff --git a/package-lock.json b/package-lock.json
index 9456e039..844a6e35 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,7 +12,6 @@
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-coding-agent": "^0.74.0",
"@earendil-works/pi-tui": "^0.74.1",
- "@observal/pi-insights": "^1.2.2",
"@plannotator/pi-extension": "^0.19.20",
"@sinclair/typebox": "^0.34.49",
"chokidar": "^5.0.0",
@@ -2455,15 +2454,6 @@
"node": ">= 8"
}
},
- "node_modules/@observal/pi-insights": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@observal/pi-insights/-/pi-insights-1.2.2.tgz",
- "integrity": "sha512-YRaJH2/fJwoLZscjEuRkR66hJrfNgZ8NTSjaO1rm4fvaqW6JkGIAZhQhhJtA+UzUQBUSlvzkVVCrarZumq2Hqw==",
- "license": "AGPL-3.0-only",
- "peerDependencies": {
- "@earendil-works/pi-coding-agent": ">=0.74.0"
- }
- },
"node_modules/@pierre/diffs": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@pierre/diffs/-/diffs-1.2.3.tgz",
diff --git a/package.json b/package.json
index a658b68c..4f81129f 100644
--- a/package.json
+++ b/package.json
@@ -16,7 +16,6 @@
"littleCoder": {
"packages": [
"@plannotator/pi-extension",
- "@observal/pi-insights",
"pi-better-openai",
"pi-ask-user"
]
@@ -52,7 +51,6 @@
"@earendil-works/pi-ai": "^0.74.1",
"@earendil-works/pi-coding-agent": "^0.74.0",
"@earendil-works/pi-tui": "^0.74.1",
- "@observal/pi-insights": "^1.2.2",
"@plannotator/pi-extension": "^0.19.20",
"@sinclair/typebox": "^0.34.49",
"chokidar": "^5.0.0",
diff --git a/plans/enhancements-roadmap.md b/plans/enhancements-roadmap.md
new file mode 100644
index 00000000..99fcf6cf
--- /dev/null
+++ b/plans/enhancements-roadmap.md
@@ -0,0 +1,200 @@
+# Enhancements Roadmap Plan
+
+## Context
+
+The requested work spans little-coder's extension stack, bundled skills, prompt text, telemetry/dashboard UX, session search, reflection-driven skill creation, planning-command cleanup, browser/web UI tooling, and Python sandboxing.
+
+Verified repository facts so far:
+- `package.json` already depends on `@observal/pi-insights`, `@plannotator/pi-extension`, `pi-ask-user`, and optional `@tobilu/qmd`.
+- Existing first-party extensions include `skill-inject`, `memory-context`, `mode-commands`, `plan-mode`, `extra-tools`, `browser`, `permission-gate`, `usage-dashboard`, `inspect`, and `branding`.
+- `AGENTS.md` contains the long global agent prompt that should be compressed.
+- `skill-inject` currently parses `keywords` frontmatter but still uses a hard-coded `INTENT_MAP` for tool prediction. Tool/protocol skills mostly lack `keywords`; knowledge skills already have them.
+- The `/skills` command/tool currently lists names, token costs, and keywords, but not descriptions.
+- Two `/plan` providers exist: `.pi/extensions/mode-commands/index.ts` registers a prompt-only `/plan`, while `scripts/patch-extension-notifications.mjs` patches `@plannotator/pi-extension` to register the real planning-mode `/plan`.
+- `memory-context` injects memory automatically, exposes `/memory-*` commands, writes `.pi/memory`, and is referenced by `branding` startup text.
+- `usage-dashboard` already parses Pi session JSONL cost/tokens/tool data for an inline `/usage` TUI.
+- `inspect` already implements a local web server command pattern, snapshot capture, static dashboard launch, port probing, and browser/PWA opening.
+- `permission-gate` currently whitelists `python ` and `python3 ` by prefix, so arbitrary Python can bypass command-level permission checks.
+
+User decisions captured:
+- Vendor `@observal/pi-insights` directly despite AGPL-3.0-only licensing; preserve license/NOTICE details.
+- Sandbox **all** Python execution without asking for approval.
+- Reflection-generated skills should default to user-level `~/.pi/skills`; `skill-inject` should load user-level and repo skills. Add `/promote-user-skill [skill]` to copy user skills into repo `skills/` with duplicate checks.
+
+## Approach
+
+Implement this as a set of small, testable extension changes rather than one monolithic rewrite:
+
+1. **Stabilize existing UX and prompt behavior first**: fix duplicate `/plan`, compress prompts, improve tool descriptions/output, and update `/skills` display.
+2. **Rework skill injection around skill metadata and roots**: add missing `keywords`/`description` frontmatter, load both repo `skills/` and user `~/.pi/skills`, score tool/reference skills from frontmatter, and add per-session cooldown state so automatic injection does not repeat recent skills.
+3. **Add session intelligence as reusable infrastructure**: create a session-transcript parser/index shared by breadcrumbs, reflection, cost dashboards, and the web UI.
+4. **Replace memory with reflection-generated skills**: remove automatic memory injection and `/memory-*`, then add `/reflect` commands that review bounded session history, propose user-level skill files, and require user yes/no/edit approval before writing to `~/.pi/skills`.
+5. **Vendor and unify dashboards**: vendor `pi-insights`, port useful cost-dashboard concepts from `agent-cost-dashboard`, and expose a richer `/web` UI that links or embeds cost, inspect, breadcrumbs, skills, reflection, commands, tools, and chat.
+6. **Sandbox Python execution**: stop treating arbitrary Python as safe; route all Python execution through a sandbox path without prompting for approval, with tests that prove Python cannot trivially bypass `permission-gate`.
+
+## Files to modify
+
+Critical paths expected to change:
+- `AGENTS.md`
+- `package.json`
+- `package-lock.json`
+- `scripts/patch-extension-notifications.mjs`
+- `.pi/extensions/skill-inject/index.ts`
+- `.pi/extensions/skill-inject/frontmatter.ts`
+- `.pi/extensions/skill-inject/*.test.ts`
+- `.pi/extensions/mode-commands/index.ts`
+- `.pi/extensions/mode-commands/mode-prompts.ts`
+- `.pi/extensions/plan-mode/*.ts`
+- `.pi/extensions/extra-tools/index.ts`
+- `.pi/extensions/browser/index.ts`
+- `.pi/extensions/permission-gate/index.ts`
+- `.pi/extensions/permission-gate/*.test.ts`
+- `.pi/extensions/usage-dashboard/index.ts`
+- `.pi/extensions/branding/index.ts`
+- `.pi/extensions/memory-context/**` (remove or replace with migration stub)
+- New shared session parser/index module, likely `.pi/extensions/_shared/session-history.ts`
+- New breadcrumbs extension, likely `.pi/extensions/breadcrumbs/`
+- New reflection extension, likely `.pi/extensions/reflect-skills/`
+- New vendored insights/cost extension, likely `.pi/extensions/pi-insights/`
+- New web UI extension, likely `.pi/extensions/web/`
+- `skills/**/*.md` frontmatter updates
+- New skill files from `mattpocock/skills`, likely `skills/engineering/improve-codebase-architecture/`
+- `NOTICE` / license docs if vendored code is included
+
+## Reuse
+
+Existing code and external references to reuse:
+- `.pi/extensions/skill-inject/frontmatter.ts` and `loadSkills()` already parse skill markdown/frontmatter; extend them rather than replacing the loader.
+- `.pi/extensions/skill-inject/index.ts` already has budgets, `/skills`, `/skill`, explicit `/skill:`, recency, last-failed-tool recovery, and UI notifications; extend it to load user and repo skill roots with deterministic precedence.
+- `.pi/extensions/usage-dashboard/index.ts` already parses `~/.pi/agent/sessions/**/*.jsonl` for provider/model/cost/token/tool stats.
+- `.pi/extensions/powerline-footer-unified/index.ts` already derives the project session directory and extracts recent user prompts from JSONL.
+- `.pi/extensions/inspect/index.ts` already has reusable local-dashboard patterns: port probing, subprocess/server lifecycle, snapshots, browser/PWA opening, and request watching.
+- `.pi/extensions/browser/index.ts` already registers `enableBrowserTools`; only the description/prompt snippet needs tuning.
+- `.pi/extensions/permission-gate/index.ts` already centralizes bash allowlisting and external file access policy.
+- `@tobilu/qmd` is installed as an optional dependency; its README documents BM25, semantic search, hybrid query, JSON output, and SDK usage.
+- External `mrexodia/agent-cost-dashboard` is MIT-licensed and provides cost-dashboard ideas: global stats, daily spend charts, model/tool/project/session views, Pi/OMP/Claude/Codex parsing, subagent grouping, and transcript export.
+- External `jo-inc/pi-reflect` is MIT-licensed and provides transcript collection, reflection history/config commands, and safe/surgical edit concepts.
+- External `briggsd/pi-reflect-ext` provides a skill-management-oriented reflection design with safe skill path confinement and background review prompts.
+- External `mattpocock/skills` is MIT-licensed and contains `skills/engineering/improve-codebase-architecture/SKILL.md` plus support files (`LANGUAGE.md`, `DEEPENING.md`, etc.).
+
+## Steps
+
+### Phase 1 — Prompt, command, and small tool fixes
+
+- [ ] Remove the prompt-only `/plan` registration from `.pi/extensions/mode-commands/index.ts`; keep real planning mode owned by Plannotator's patched `/plan` and optionally add a non-conflicting `/plan-prompt` only if still useful.
+- [ ] Update tests around `scripts/patch-extension-notifications.mjs` and add a command-registration test so only the real `/plan` is exposed.
+- [ ] Compress `AGENTS.md` by removing repeated tool-efficiency/evidence wording, keeping only invariants, autonomy, tool-selection order, ambiguity handling, and skill discovery.
+- [ ] Compress `.pi/extensions/mode-commands/mode-prompts.ts` to short mode prompts with clear constraints and outputs.
+- [ ] Update `.pi/extensions/browser/index.ts` so `enableBrowserTools` says to prefer `webfetch`/`websearch` for non-interactive web retrieval and only enable Browser* tools for interactive navigation/click/type/extract workflows.
+- [ ] Update `.pi/extensions/extra-tools/index.ts` `findRead` output to prefix the effective invocation: `pattern`, `path`, `maxFiles`, `maxCharacters`, and `ignoreDefaultExcludes`, including no-match/error paths.
+- [ ] Update `skills/tools/find_read.md` and `skills/tools/skills.md` to describe the new output and skill descriptions.
+
+### Phase 2 — Skill metadata and injection cooldown
+
+- [ ] Add `keywords` and concise `description` frontmatter to every bundled tool/protocol skill and to `skills/hatch-pet/SKILL.md`; add descriptions to knowledge skills where missing.
+- [ ] Import `mattpocock/skills/skills/engineering/improve-codebase-architecture/` into `skills/engineering/improve-codebase-architecture/`, preserving support files and adding little-coder frontmatter fields (`type`, `token_cost`, `keywords`, and any needed `requires_tools`).
+- [ ] Extend skill discovery to load both repo `skills/` and user `~/.pi/skills`. Repo skills should remain packaged/canonical; user skills should be mutable and higher priority for explicit `/skill` by exact name. If both roots contain the same skill name, list both origins in `/skills` and make automatic injection choose the higher-priority origin deterministically.
+- [ ] Add `/promote-user-skill [skill]`:
+ - without an argument, list user skills that are not already present in repo `skills/` by same name/content;
+ - with an argument, copy the selected user skill directory into repo `skills/user//` by default, unless a known repo category mapping is explicitly supported for that skill type;
+ - detect duplicate names, identical content, and near-duplicate descriptions/keywords before writing;
+ - skip identical duplicates, warn on conflicting same-name skills, and require an explicit conflict resolution path such as `--force`/rename guidance rather than overwriting silently.
+- [ ] Replace hard-coded tool intent prediction with frontmatter-driven scoring for tool skills. Keep non-keyword priority sources only where they are behavioral rather than semantic: explicit `/skill`, required tools from selected references, last failed tool, and recent tool-call recovery.
+- [ ] Export/test pure selection helpers instead of duplicating `INTENT_MAP` logic in tests.
+- [ ] Add automatic-injection cooldown state per session:
+ - explicit `/skill` always bypasses cooldown;
+ - last-failed-tool recovery may bypass once after a failure;
+ - other automatic tool/reference skills are suppressed if injected in the previous turn and by default become eligible again after 3 completed user turns;
+ - skipped skills are listed in the `skill-inject` notification as `suppressed recent [...]`.
+- [ ] Add long-conversation warning throttled by session: notify once when either context usage is above ~75% or the session has at least ~16 user turns, then at most every 6 turns. Wording should suggest `/compact` or starting a fresh session, not alarm the user.
+- [ ] Update `/skills`, `/skill` completions, and the `skills` tool output to include each skill description (frontmatter description or a short first-line fallback), not just name/token/keywords.
+
+### Phase 3 — Shared session history and breadcrumbs tools
+
+- [ ] Create `.pi/extensions/_shared/session-history.ts` to discover Pi session JSONL files using `PI_CODING_AGENT_DIR || ~/.pi/agent`, parse session headers/messages/tool events safely, normalize project/cwd/session id/date, and produce bounded outlines.
+- [ ] Add lexical search over session outlines/messages using BM25-ish scoring that boosts user prompts, file paths, tool names, and current project matches.
+- [ ] Add optional semantic search adapter using `@tobilu/qmd` when available; fall back to lexical with a clear mode note when QMD cannot initialize.
+- [ ] Add `breadcrumbs_search` tool: returns only outlines/snippets, not full transcripts. Defaults: current project first, limit 5, snippets <= 300 chars, no tool-output bodies.
+- [ ] Add `breadcrumbs_read` tool: requires a session id/path from search, returns bounded chunks with `cursor`, `maxTurns` default 8/max 20, `maxCharacters` default 8000/hard cap 16000, and `includeToolOutput` default false.
+- [ ] Add tests for parser robustness, lexical ranking, QMD fallback, outline-only search, and read guards.
+
+### Phase 4 — Reflection replaces memory
+
+- [ ] Remove `memory-context` from active extension loading and delete its tests/source once replacement commands exist; do not leave automatic memory injection in place.
+- [ ] Update `branding` startup text to remove memory counts and `/memory-*` hints; replace with `/reflect`, `/reflect-review`, `/breadcrumbs`, and `/skills` hints.
+- [ ] Add `.pi/extensions/reflect-skills/` with commands patterned after the current `/memory-*` ergonomics but skill-oriented:
+ - `/reflect` — review recent session history and propose one or more skill changes;
+ - `/reflect-review` — show queued proposals;
+ - `/reflect-accept`, `/reflect-deny`, or `/reflect-review accept|deny` — apply/discard proposals;
+ - `/reflect-history` and `/reflect-doctor` — audit runs and dependencies.
+- [ ] Reflection should use bounded session history from the shared parser/breadcrumbs index, not raw unbounded transcripts.
+- [ ] Reflection prompt should propose user-level skill files with required frontmatter: `name`, `description`, `type`, `token_cost`, `keywords`, and optional `requires_tools`.
+- [ ] Reflection approval loop must be user-mediated: for each proposal ask yes/no/edit; an edit response is treated as guidance, regenerates/adapts the skill, and presents it again.
+- [ ] Write accepted skills to `~/.pi/skills//SKILL.md` by default so `skill-inject` loads them on the next reload; use path confinement and slug validation from the external reflection designs.
+- [ ] Add a one-time migration/notice for existing `.pi/memory` users explaining that memory was superseded and is no longer injected. Do not auto-convert old memories into skills without approval.
+- [ ] Document the promotion flow: user-level skills are experimental/local; `/promote-user-skill` copies stable skills into repo `skills/` after duplicate checks so they can be packaged with little-coder.
+
+### Phase 5 — Vendor insights/cost dashboard and unified web UI
+
+- [ ] Vendor `@observal/pi-insights` into `.pi/extensions/pi-insights/`, preserving its AGPL license headers and adding license/NOTICE entries as an explicit user-approved vendoring decision.
+- [ ] Remove the `@observal/pi-insights` package entry from `littleCoder.packages` and dependencies only after the vendored extension is active; remove obsolete postinstall patches against `node_modules/@observal/pi-insights`.
+- [ ] Port selected `agent-cost-dashboard` concepts into the vendored TypeScript extension rather than shelling out to Python: daily spending chart, model breakdown, tool usage, project/session browser, top costly sessions, subagent grouping, and transcript export links.
+- [ ] Reuse `usage-dashboard` parsing logic where possible; move shared cost/session aggregation to a helper so `/usage`, `/insights`, `/web`, and breadcrumbs do not each parse sessions differently.
+- [ ] Add `.pi/extensions/web/` with `/web` command, binding to `127.0.0.1` by default and printing SSH tunnel instructions for remote use.
+- [ ] Implement `/web start|stop|restart|status|open` using the safer server lifecycle pattern from `inspect`.
+- [ ] Web UI feature set should include: shared agent chat, streaming transcript, expandable tool/thinking blocks, abort/new session, command palette with command descriptions, tools registry, skills list/load with descriptions, breadcrumbs search/read, reflection review/approval, cost dashboard, inspect snapshot links, and permission prompts.
+- [ ] Prefer a no-build static frontend served from the extension if feasible; add a small dependency such as `ws` only if bidirectional streaming cannot be cleanly handled with built-in HTTP + SSE/POST.
+
+### Phase 6 — Python sandbox first draft
+
+- [ ] Remove broad `python ` and `python3 ` from `BUILTIN_SAFE_PREFIXES` in `permission-gate`; no Python execution should be auto-approved by prefix.
+- [ ] Add Python-command detection for `python`, `python3`, venv Python paths, `uv run python`, `python -m ...`, `python -c`, stdin/heredoc scripts, and direct `.py` execution when invoked through bash.
+- [ ] Route every detected Python execution through a sandbox path without asking the user for approval. Prefer mutating the `bash` tool input in `tool_call` to invoke a generated sandbox wrapper; if a command cannot be rewritten safely, block with a clear sandbox-unavailable reason rather than asking or running unsandboxed.
+- [ ] First-draft sandbox design:
+ - On Linux, prefer an OS sandbox if available (`bubblewrap`/similar): read-only bind the workspace unless write access to a controlled temp/work output dir is explicitly needed, tmpfs `/tmp`, no network where supported, minimal env, timeout, output cap.
+ - If no OS sandbox is available, run only in the most restrictive fallback available and block with a clear message if containment cannot be provided; do not ask for approval and do not silently run unsandboxed.
+ - Use TypeBox/Zod-style validation in TypeScript for command specs; do not rely on Pydantic as the security boundary. Pydantic can validate a helper manifest if a Python helper is later introduced, but validation is not containment.
+ - Optionally add a restricted AST helper only for tiny data-transformation snippets, clearly documented as convenience rather than a security sandbox.
+- [ ] Include test-running commands such as `python -m pytest` in the sandbox route. They should not require approval, but they also should not run outside the sandbox.
+- [ ] Add tests proving `python -c 'import os; os.system(...)'`, heredoc Python, arbitrary Python scripts, `python -m pytest`, and venv Python paths are sandboxed or blocked when sandboxing is unavailable, never silently allowed unsandboxed.
+
+### Phase 7 — Cleanup and docs
+
+- [ ] Update README/CHANGELOG if these commands/features are documented there.
+- [ ] Remove stale memory docs/references and update startup hints.
+- [ ] Update package metadata and lockfile for any new vendored extensions or dependencies.
+
+## Verification
+
+Automated checks:
+- `npm test`
+- `npm run typecheck`
+- Focused Vitest suites:
+ - `skill-inject` frontmatter/scoring/cooldown/listing/user-root/promotion tests
+ - `mode-commands` command-registration tests
+ - `extra-tools` `findRead` output tests
+ - `browser` description snapshot/registration tests if existing patterns allow
+ - `permission-gate` Python allow/block tests
+ - new `breadcrumbs` parser/search/read-guard tests
+ - new `reflect-skills` proposal/path/frontmatter/approval tests
+ - cost aggregation tests shared by `/usage`, `/insights`, and `/web`
+
+Manual checks:
+- Start a local session and confirm `/plan` enters Plannotator planning mode, with no prompt-only `/plan:1` duplicate.
+- Run `/skills` and the `skills` tool; descriptions and origins should appear for repo and user-level skills.
+- Trigger `findRead` and verify the returned text includes effective `pattern`, `maxFiles`, and `maxCharacters`.
+- Run a multi-turn sequence where the same skill would match repeatedly; confirm immediate reinjection is suppressed, explicit `/skill` still works, and long-session warning is throttled.
+- Run `breadcrumbs_search` and `breadcrumbs_read`; search should return outlines only, read should enforce chunk guards.
+- Run `/reflect`; verify proposals require yes/no/edit approval and accepted skills land under `~/.pi/skills` with keywords.
+- Run `/promote-user-skill` with no args and with a selected skill; verify promotable listing, duplicate checks, and repo `skills/` output.
+- Confirm old `/memory-*` commands are gone or replaced by clear reflection equivalents and that `.pi/memory` is not injected.
+- Run `/usage`, `/insights`, and `/web`; compare aggregate costs/session counts against a small fixture or known session set.
+- Confirm `/web` binds to `127.0.0.1` and prints tunnel/open instructions.
+- Try Python bypass examples and verify they are sandboxed, or blocked if sandboxing is unavailable, without asking for approval.
+
+## Resolved decisions
+
+- Directly vendor AGPL `@observal/pi-insights` with license/NOTICE preservation.
+- Sandbox all Python execution; do not use approval as the escape hatch.
+- Reflection writes to user-level `~/.pi/skills` by default; repo `skills/` receives skills only via `/promote-user-skill` after duplicate checks.
+
diff --git a/scripts/patch-extension-notifications.mjs b/scripts/patch-extension-notifications.mjs
index 4660da79..59fd5a45 100644
--- a/scripts/patch-extension-notifications.mjs
+++ b/scripts/patch-extension-notifications.mjs
@@ -33,41 +33,6 @@ export const PATCHES = [
oldText: `function openBrowserForServer(serverUrl: string, ctx: ExtensionContext): void {\n\tconst browserResult = openBrowser(serverUrl);\n\tif (isRemoteSession()) {\n\t\tctx.ui.notify(\`[Plannotator] \${serverUrl}\`, "info");\n\t} else if (!browserResult.opened) {\n\t\tctx.ui.notify(\`Open this URL to review: \${serverUrl}\`, "info");\n\t}\n}`,
newText: `function openBrowserForServer(serverUrl: string, ctx: ExtensionContext): void {\n\tctx.ui.notify(\`Plannotator listening at: \${serverUrl}\`, "info");\n\tconst browserResult = openBrowser(serverUrl);\n\tif (!browserResult.opened) {\n\t\tctx.ui.notify(\`Open this URL to review: \${serverUrl}\`, "info");\n\t}\n}`,
},
- {
- name: "pi-insights http server imports",
- path: ["node_modules", "@observal", "pi-insights", "index.ts"],
- oldText: `import { execFile as execFileCb } from "node:child_process";\nimport { mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";`,
- newText: `import { execFile as execFileCb } from "node:child_process";\nimport { createServer, type Server } from "node:http";\nimport { mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";`,
- },
- {
- name: "pi-insights http server constants",
- path: ["node_modules", "@observal", "pi-insights", "index.ts"],
- oldText: `const REPORT_PATH = join(DATA_DIR, "report.html");\nconst REPORT_MD_PATH = join(DATA_DIR, "report.md");`,
- newText: `const REPORT_PATH = join(DATA_DIR, "report.html");\nconst REPORT_MD_PATH = join(DATA_DIR, "report.md");\nconst REPORT_PORT = 5463;\nconst REPORT_URL = \`http://localhost:\${REPORT_PORT}\`;\n\nlet reportServer: Server | null = null;`,
- },
- {
- name: "pi-insights http server helper",
- path: ["node_modules", "@observal", "pi-insights", "index.ts"],
- oldText: `function displayLabel(key: string): string {\n\treturn (\n\t\tLABEL_MAP[key] ??\n\t\tkey.replace(/_/g, " ").replace(/\\b\\w/g, (c) => c.toUpperCase())\n\t);\n}`,
- newText: `function displayLabel(key: string): string {\n\treturn (\n\t\tLABEL_MAP[key] ??\n\t\tkey.replace(/_/g, " ").replace(/\\b\\w/g, (c) => c.toUpperCase())\n\t);\n}\n\nasync function startReportServer(): Promise {\n\tif (reportServer?.listening) return REPORT_URL;\n\n\treportServer = createServer(async (req, res) => {\n\t\tconst path = new URL(req.url ?? "/", REPORT_URL).pathname;\n\t\tif (path !== "/" && path !== "/report.html") {\n\t\t\tres.writeHead(404, { "content-type": "text/plain; charset=utf-8" });\n\t\t\tres.end("Not found");\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst html = await readFile(REPORT_PATH, "utf8");\n\t\t\tres.writeHead(200, {\n\t\t\t\t"content-type": "text/html; charset=utf-8",\n\t\t\t\t"cache-control": "no-store",\n\t\t\t});\n\t\t\tres.end(html);\n\t\t} catch {\n\t\t\tres.writeHead(404, { "content-type": "text/plain; charset=utf-8" });\n\t\t\tres.end("Pi Insights report has not been generated yet. Run /insights first.");\n\t\t}\n\t});\n\n\tawait new Promise((resolve, reject) => {\n\t\tconst onError = (err: NodeJS.ErrnoException) => {\n\t\t\tif (err.code === "EADDRINUSE") resolve();\n\t\t\telse reject(err);\n\t\t};\n\t\treportServer!.once("error", onError);\n\t\treportServer!.listen(REPORT_PORT, "127.0.0.1", () => {\n\t\t\treportServer!.off("error", onError);\n\t\t\tresolve();\n\t\t});\n\t});\n\n\treturn REPORT_URL;\n}`,
- },
- {
- name: "pi-insights browser URL notification",
- path: ["node_modules", "@observal", "pi-insights", "index.ts"],
- oldText: `\tctx.ui.notify(\`✅ Report saved: \${REPORT_PATH}\`, "success");\n\n\tif (!noOpen) {\n\t\tconst opener = platform() === "darwin" ? "open" : "xdg-open";\n\t\texecFile(opener, [REPORT_PATH]).catch(() => {\n\t\t\tctx.ui.notify(\`Open manually: \${REPORT_PATH}\`, "info");\n\t\t});\n\t}\n}`,
- newText: `\tconst reportUrl = await startReportServer();\n\tctx.ui.notify(\`✅ Report saved: \${REPORT_PATH}\`, "success");\n\tctx.ui.notify(\`Pi Insights report URL: \${reportUrl}\`, "info");\n\n\tif (!noOpen) {\n\t\tconst opener = platform() === "darwin" ? "open" : "xdg-open";\n\t\texecFile(opener, [reportUrl]).catch(() => {\n\t\t\tctx.ui.notify(\`Open manually: \${reportUrl}\`, "info");\n\t\t});\n\t}\n}`,
- alreadyAppliedText: [
- "const reportUrl = await startReportServer();",
- "Pi Insights report URL: ${reportUrl}",
- "execFile(opener, [reportUrl])",
- ],
- },
- {
- name: "pi-insights canonical command",
- path: ["node_modules", "@observal", "pi-insights", "index.ts"],
- oldText: `pi.registerCommand("pi-insights", {`,
- newText: `pi.registerCommand("insights", {`,
- },
{
name: "pi-inspect clearer group labels",
path: ["node_modules", "pi-inspect", "public", "app.js"],
diff --git a/scripts/patch-extension-notifications.test.mjs b/scripts/patch-extension-notifications.test.mjs
index 94af0aa1..93557cf3 100644
--- a/scripts/patch-extension-notifications.test.mjs
+++ b/scripts/patch-extension-notifications.test.mjs
@@ -6,6 +6,10 @@ import { PATCHES, applyTextPatch, isPatchApplied } from "./patch-extension-notif
const root = process.cwd();
describe("postinstall node_modules patches", () => {
+ it("does not patch vendored pi-insights through node_modules", () => {
+ expect(PATCHES.some((patch) => patch.name.includes("pi-insights") || patch.path.includes("@observal"))).toBe(false);
+ });
+
it("all patch targets either match upstream text or are already applied", () => {
for (const patch of PATCHES) {
const file = join(root, ...patch.path);
diff --git a/skills/engineering/improve-codebase-architecture/HTML-REPORT.md b/skills/engineering/improve-codebase-architecture/HTML-REPORT.md
new file mode 100644
index 00000000..e7cc702c
--- /dev/null
+++ b/skills/engineering/improve-codebase-architecture/HTML-REPORT.md
@@ -0,0 +1,3 @@
+# HTML Report Guidance
+
+When a visual report is requested, write a self-contained HTML file in the OS temp directory. Include cards for each candidate with files, problem, solution, benefits, before/after diagrams, recommendation strength, and a top recommendation.
diff --git a/skills/engineering/improve-codebase-architecture/LANGUAGE.md b/skills/engineering/improve-codebase-architecture/LANGUAGE.md
new file mode 100644
index 00000000..4e1599e8
--- /dev/null
+++ b/skills/engineering/improve-codebase-architecture/LANGUAGE.md
@@ -0,0 +1,3 @@
+# Architecture Language
+
+Use module, interface, implementation, depth, seam, adapter, leverage, and locality consistently. Prefer "seam" over "boundary" and "adapter" over generic integration names.
diff --git a/skills/engineering/improve-codebase-architecture/SKILL.md b/skills/engineering/improve-codebase-architecture/SKILL.md
new file mode 100644
index 00000000..37801229
--- /dev/null
+++ b/skills/engineering/improve-codebase-architecture/SKILL.md
@@ -0,0 +1,43 @@
+---
+name: improve-codebase-architecture
+description: Find deepening opportunities in a codebase and propose refactors that improve architecture, testability, and AI-navigability.
+type: workflow
+token_cost: 150
+keywords: [architecture, codebase architecture, refactor, refactoring, testability, module, interface, deep module, shallow module, seam, adapter, locality, leverage]
+requires_tools: [code_search, lsp, read, write]
+---
+# Improve Codebase Architecture
+
+Surface architectural friction and propose **deepening opportunities** — refactors that turn shallow modules into deep ones. The aim is testability and AI-navigability.
+
+## Glossary
+
+Use these terms exactly in every suggestion:
+
+- **Module** — anything with an interface and an implementation (function, class, package, slice).
+- **Interface** — everything a caller must know to use the module: types, invariants, error modes, ordering, config.
+- **Implementation** — the code inside.
+- **Depth** — leverage at the interface: a lot of behaviour behind a small interface. Deep = high leverage. Shallow = interface nearly as complex as the implementation.
+- **Seam** — where an interface lives; a place behaviour can be altered without editing in place.
+- **Adapter** — a concrete thing satisfying an interface at a seam.
+- **Leverage** — what callers get from depth.
+- **Locality** — what maintainers get from depth: change, bugs, knowledge concentrated in one place.
+
+Key principles:
+
+- **Deletion test**: imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
+- **The interface is the test surface.**
+- **One adapter = hypothetical seam. Two adapters = real seam.**
+
+## Process
+
+1. Explore domain glossary/docs and ADRs first.
+2. Use code_search/lsp/read to identify friction:
+ - understanding one concept requires bouncing through many small modules;
+ - modules are shallow;
+ - pure functions were extracted for testability but bugs hide in orchestration;
+ - tightly-coupled modules leak across seams;
+ - tests are missing or hard to write through the current interface.
+3. Present candidates with: files, problem, solution, benefits in terms of locality/leverage, before/after structure, and recommendation strength.
+4. End with a top recommendation and ask which candidate to explore.
+5. Do not implement refactors until the user chooses one.
diff --git a/skills/knowledge/bfs_state_space.md b/skills/knowledge/bfs_state_space.md
index 2c8a0761..7f21715b 100644
--- a/skills/knowledge/bfs_state_space.md
+++ b/skills/knowledge/bfs_state_space.md
@@ -5,5 +5,6 @@ topic: State-Space Search
token_cost: 120
keywords: [bucket, pouring, state space, minimum moves, shortest sequence, reach goal, transitions, visited states, water, pour, fill, empty]
user-invocable: false
+description: Concise guidance for State-Space Search.
---
When a problem asks for the MINIMUM number of moves/steps to reach a goal state (bucket pouring, puzzle solving, sliding tiles), model it as BFS over a state space. State = a tuple of all values that fully describe the situation (e.g. (bucket_a, bucket_b)). From each state, enumerate every legal transition (fill A, fill B, empty A, empty B, pour A→B, pour B→A) and produce the next state. Use a visited set keyed on the state tuple to avoid cycles. BFS from the start state; the first time you pop a state matching the goal, its distance is the minimum move count. Track which bucket holds the goal and the other bucket's value at that point. Edge case: if start_bucket is forbidden as an immediate "fill the wrong one first" move, encode that as a filter on the initial transitions.
diff --git a/skills/knowledge/binary_search.md b/skills/knowledge/binary_search.md
index ad260c6f..0383626c 100644
--- a/skills/knowledge/binary_search.md
+++ b/skills/knowledge/binary_search.md
@@ -5,5 +5,6 @@ topic: Binary Search
token_cost: 90
keywords: [binary, search, sorted, monotonic, bisect, minimum, maximum, feasible, predicate, lower, upper, bound, log, efficient, mid, pivot, rotated]
user-invocable: false
+description: Concise guidance for Binary Search.
---
Binary search works on any monotonic predicate, not just sorted arrays. Pattern: "find minimum X such that condition(X) is true" — binary search on the answer space. Use bisect.bisect_left/bisect_right for sorted-array insertion points. For "minimize the maximum" or "maximize the minimum" problems, binary search on the answer and check feasibility. Always use lo + (hi - lo) // 2 to avoid overflow. When searching rotated arrays, check which half is sorted first. Time: O(log n) — whenever you see "sorted" or "monotonic" in a problem, consider binary search.
diff --git a/skills/knowledge/code_review.md b/skills/knowledge/code_review.md
index c0ab1589..20bd0cd6 100644
--- a/skills/knowledge/code_review.md
+++ b/skills/knowledge/code_review.md
@@ -6,6 +6,7 @@ token_cost: 150
keywords: [code review, review, reviews, reviewing, pr review, pull request, pull request review, merge request, diff, reviewer, feedback, request changes, approve, approval, blocker, nit, testability, maintainability]
requires_tools: [read, code_search, lsp]
user-invocable: false
+description: Concise guidance for Code Review.
---
Use this when reviewing code changes, pull requests, merge requests, diffs, or when establishing review practices.
diff --git a/skills/knowledge/dfs_vs_bfs.md b/skills/knowledge/dfs_vs_bfs.md
index 32f373d0..ca4d9a9c 100644
--- a/skills/knowledge/dfs_vs_bfs.md
+++ b/skills/knowledge/dfs_vs_bfs.md
@@ -5,5 +5,6 @@ topic: Graph Traversal
token_cost: 100
keywords: [dfs, bfs, depth, breadth, graph, traverse, path, maze, shortest, connected, reachable, visited, queue, stack, neighbor, walk, flood, fill, island]
user-invocable: false
+description: Concise guidance for Graph Traversal.
---
DFS (stack/recursion) explores one branch fully before backtracking — use for: cycle detection, topological sort, path existence, connected components, backtracking puzzles, flood fill. BFS (queue) explores level-by-level — use for: shortest unweighted path, level-order traversal, nearest neighbor, minimum steps. If the problem asks "shortest" or "minimum steps" on an unweighted graph, always choose BFS. If it asks "all paths," "can we reach," or "count islands," DFS is simpler. Both visit each node once: O(V+E) time.
diff --git a/skills/knowledge/dynamic_programming.md b/skills/knowledge/dynamic_programming.md
index 4bdd23e2..27eb9029 100644
--- a/skills/knowledge/dynamic_programming.md
+++ b/skills/knowledge/dynamic_programming.md
@@ -5,5 +5,6 @@ topic: Dynamic Programming
token_cost: 110
keywords: [dynamic programming, dp, memoize, memoization, tabulation, subproblem, overlapping, optimal substructure, fibonacci, knapsack, longest, subsequence, minimum cost, maximum profit, number of ways, climb, stairs, coins, edit distance]
user-invocable: false
+description: Concise guidance for Dynamic Programming.
---
Use dynamic programming when a problem has overlapping subproblems (same computation repeated) and optimal substructure (optimal solution built from optimal sub-solutions). Signs: "find minimum cost," "count the number of ways," "longest/shortest subsequence," "can you reach." Define state (what changes between subproblems) and recurrence (how states relate). Top-down with @cache is easiest to write; bottom-up tabulation avoids recursion limits and is often faster. Always check if you can reduce space by keeping only the previous row/state instead of the full table.
diff --git a/skills/knowledge/frontend_design.md b/skills/knowledge/frontend_design.md
index 0055749f..7f4c8bac 100644
--- a/skills/knowledge/frontend_design.md
+++ b/skills/knowledge/frontend_design.md
@@ -5,6 +5,7 @@ topic: Frontend Design
token_cost: 150
keywords: [frontend, design, ui, ux, css, html, react, vue, component, layout, typography, color, animation, aesthetic, styling, interface, web, landing, page, dashboard, responsive, theme, font, spacing, visual, creative, distinctive, production]
user-invocable: false
+description: Concise guidance for Frontend Design.
---
Create distinctive, production-grade frontend interfaces that avoid generic "AI slop" aesthetics. Implement real working code with exceptional attention to aesthetic details and creative choices.
diff --git a/skills/knowledge/hash_vs_tree.md b/skills/knowledge/hash_vs_tree.md
index c01a8a2e..c91087be 100644
--- a/skills/knowledge/hash_vs_tree.md
+++ b/skills/knowledge/hash_vs_tree.md
@@ -5,5 +5,6 @@ topic: Data Structure Choice
token_cost: 90
keywords: [lookup, dictionary, dict, set, hash, hashtable, map, frequency, count, unique, duplicate, ordered, sorted, tree, counter, defaultdict, collections]
user-invocable: false
+description: Concise guidance for Data Structure Choice.
---
Use dict/set (hash table, O(1) avg lookup) for: membership testing, frequency counting, deduplication, grouping by key. Use collections.Counter for frequency counts, defaultdict(list) for grouping. When you need ordered keys or range queries, use sorted containers or bisect on a sorted list. For "find if X exists" or "count occurrences," always reach for a set or dict first — never scan a list repeatedly. If the problem involves pairs summing to a target, use a set to check complements in O(n) instead of O(n^2) nested loops.
diff --git a/skills/knowledge/io_wrapper.md b/skills/knowledge/io_wrapper.md
index 370e856c..85008592 100644
--- a/skills/knowledge/io_wrapper.md
+++ b/skills/knowledge/io_wrapper.md
@@ -5,5 +5,6 @@ topic: File-Like Wrapper + Counters
token_cost: 120
keywords: [io wrapper, wrap file, read counter, write counter, nreads, nwrites, context manager, __enter__, __exit__, passthrough, delegate, paasio, MetaRead, MetaWrite]
user-invocable: false
+description: Concise guidance for File-Like Wrapper + Counters.
---
To wrap a file-like and count reads/writes: store the wrapped object as self._wrapped. Implement read(size=-1) (or readable/readinto as needed) by delegating to self._wrapped.read(size) and incrementing counters by the length of the RETURNED bytes (not the requested size — a short read counts for what it returned). Same for write: call self._wrapped.write(data) and increment nwrites by the RETURN VALUE (number of bytes actually written), or by len(data) if the wrapped write returns None. Expose read_bytes/nreads and write_bytes/nwrites as properties or attributes. Context-manager support: __enter__ returns self; __exit__ calls self._wrapped.__exit__ (or close()) and forwards the exception info. Don't forget close() as a plain method for non-context-manager use. Edge case: thread safety — if the test uses threads, wrap counter updates in a threading.Lock.
diff --git a/skills/knowledge/recursion_backtracking.md b/skills/knowledge/recursion_backtracking.md
index 9e5f09e5..707cee7f 100644
--- a/skills/knowledge/recursion_backtracking.md
+++ b/skills/knowledge/recursion_backtracking.md
@@ -5,5 +5,6 @@ topic: Backtracking
token_cost: 100
keywords: [permutation, combination, subset, backtrack, constraint, generate, valid, recursive, pruning, n-queens, sudoku, exhaustive, all, solutions, choose, pick, arrangement, password, sequence]
user-invocable: false
+description: Concise guidance for Backtracking.
---
Use backtracking for constraint satisfaction and combinatorial generation: permutations, combinations, subsets, N-queens, sudoku, valid arrangements. Pattern: make a choice, recurse, undo the choice (backtrack). Prune early — skip branches that already violate constraints to avoid exploring dead ends. For subsets: at each element, choose to include or exclude it (2^n total). For permutations: choose each unused element at each position (n! total). Always pass state by reference and undo mutations rather than copying. If the problem says "generate all" or "find all valid," backtracking is usually the right approach.
diff --git a/skills/knowledge/rule_string_transform.md b/skills/knowledge/rule_string_transform.md
index d77a8298..7045925e 100644
--- a/skills/knowledge/rule_string_transform.md
+++ b/skills/knowledge/rule_string_transform.md
@@ -5,5 +5,6 @@ topic: Ordered-Rule String Transformation
token_cost: 120
keywords: [pig latin, string rule, transform word, vowel, consonant, cluster, qu, ordered rules, first match, prefix, suffix, translate word]
user-invocable: false
+description: Concise guidance for Ordered-Rule String Transformation.
---
For rule-based string transforms (pig latin, atbash, rot, etc.): encode the rules as an ordered list of (predicate, transform) pairs. For each word, walk the list; apply the FIRST matching rule and stop. Order matters — specific rules must come before general ones. Pig latin gotchas: (1) a "qu" or consonant-cluster-ending-in-qu counts as a unit — "quick" → "ickquay", "square" → "aresquay"; (2) "y" acts as a consonant at the start but a vowel in the middle — "yellow" → "ellowyay", "rhythm" → "ythmrhay"; (3) the rule order that works is: starts-with-vowel-or-xr-or-yt → append "ay"; starts-with-consonant(s)-then-"qu" → move cluster+qu, append "ay"; starts-with-consonants-up-to-first-"y"-or-vowel → move the consonants, append "ay"; fallback → append "ay". Always test each rule in isolation before combining.
diff --git a/skills/knowledge/sorting_choice.md b/skills/knowledge/sorting_choice.md
index ff6f46e1..9a156398 100644
--- a/skills/knowledge/sorting_choice.md
+++ b/skills/knowledge/sorting_choice.md
@@ -5,5 +5,6 @@ topic: Sorting
token_cost: 90
keywords: [sort, order, rank, largest, smallest, kth, median, arrange, compare, stable, priority, heap, nlargest, nsmallest, key, reverse, sorted]
user-invocable: false
+description: Concise guidance for Sorting.
---
Python's built-in sorted()/list.sort() is Timsort — O(n log n), stable, and almost always the right choice. Use key= for custom ordering. For top-k elements, use heapq.nlargest/nsmallest (O(n log k)) instead of full sort. For finding just the kth element, consider quickselect or statistics.median. Counting sort / radix sort help only when values are bounded integers. When the problem says "sort by X then by Y," use a tuple key: key=lambda x: (x.a, x.b). For reverse on one field only, negate it or use functools.cmp_to_key.
diff --git a/skills/knowledge/tree_rerooting.md b/skills/knowledge/tree_rerooting.md
index d1dc1b3b..73107ace 100644
--- a/skills/knowledge/tree_rerooting.md
+++ b/skills/knowledge/tree_rerooting.md
@@ -5,5 +5,6 @@ topic: Tree Re-Rooting (POV)
token_cost: 120
keywords: [re-root, reroot, pov, point of view, tree rotation, change root, from_pov, reparent, path between nodes, undirected tree]
user-invocable: false
+description: Concise guidance for Tree Re-Rooting (POV).
---
Re-rooting an undirected tree from a new node: build an undirected adjacency map (parent↔children become symmetric neighbor sets), then do DFS/BFS from the target node. Every node you visit gets its parent set to the node you came from, and its children become all neighbors minus that parent. The result is a new rooted tree with the target as root. Path-between(a, b): re-root at a, then walk from b up parent pointers until you hit a — that gives the reversed path; reverse it for a→b order. If the target node is not in the tree, return None (not an error — many test suites treat "node absent" as None). Cost: O(N) per re-root. Do NOT mutate the original tree when re-rooting — build a fresh node structure, so repeated from_pov calls on the original work correctly.
diff --git a/skills/knowledge/tree_zipper.md b/skills/knowledge/tree_zipper.md
index 43f044b3..7d0761ca 100644
--- a/skills/knowledge/tree_zipper.md
+++ b/skills/knowledge/tree_zipper.md
@@ -5,5 +5,6 @@ topic: Functional Tree Navigation
token_cost: 130
keywords: [zipper, tree navigation, breadcrumb, focus, up, down, left, right, functional tree, immutable tree, cursor]
user-invocable: false
+description: Concise guidance for Functional Tree Navigation.
---
A tree zipper is a cursor for immutable trees. State = (focus, trail). focus is the current subtree. trail is a list of "breadcrumbs" describing the path from root to focus — each crumb remembers the parent's value plus the siblings NOT taken. Operations: down_left/down_right push a crumb (remembering current node + the other child) and make the chosen child the new focus. up pops the top crumb, rebuilds the parent by combining it with the current focus, and makes that parent the new focus. set_value replaces the focused subtree's value. to_tree walks all the way up (repeated up) to rebuild the whole tree. Key invariant: you can always reconstruct the full original tree from (focus, trail) — no information is lost. Equality of two zippers = equality of the fully-reconstructed trees, NOT of the raw (focus, trail) pairs, because different trails can represent the same tree position.
diff --git a/skills/knowledge/two_pointers.md b/skills/knowledge/two_pointers.md
index a08b0641..c1f1329b 100644
--- a/skills/knowledge/two_pointers.md
+++ b/skills/knowledge/two_pointers.md
@@ -5,5 +5,6 @@ topic: Two Pointers and Sliding Window
token_cost: 100
keywords: [pointer, two, sliding, window, substring, subarray, pair, sum, target, sorted, left, right, fast, slow, cycle, linked, list, contiguous, consecutive, squeeze]
user-invocable: false
+description: Concise guidance for Two Pointers and Sliding Window.
---
Two pointers on a sorted array: start left=0, right=n-1, move inward based on comparison — solves pair-sum, three-sum, container problems in O(n). Sliding window for contiguous subarrays/substrings: expand right boundary, shrink left when constraint violated — solves "longest/shortest substring with property" in O(n). Fast/slow pointers: detect cycles in linked lists (Floyd's), find middle element. Key insight: if brute force is O(n^2) nested loops over a sorted or sequential structure, two pointers likely reduces it to O(n).
diff --git a/skills/knowledge/workspace_docs.md b/skills/knowledge/workspace_docs.md
index d84c3ed3..91d68c5b 100644
--- a/skills/knowledge/workspace_docs.md
+++ b/skills/knowledge/workspace_docs.md
@@ -6,5 +6,6 @@ token_cost: 140
keywords: [implement, build, create, fix, task, exercise, feature, todo, spec, specification, requirements, instructions, bug, test, failing, review, refactor]
requires_tools: [Read, Glob]
user-invocable: false
+description: Concise guidance for Workspace Documentation.
---
Before writing code for a non-trivial task, check if the workspace has a problem specification or convention document. These are cheap to read and often contain the exact format rules, edge cases, or constraints the tests assert — which the model would otherwise have to reverse-engineer from tests alone. Look for (in priority order): `.docs/instructions.md` and `.docs/instructions.append.md` (exercism-style problem specs), `AGENTS.md` / `CLAUDE.md` (agent-specific instructions at repo root), `README.md` in the current directory, `SPEC.md` / `SPECIFICATION.md`, and `docs/*.md`. Use Glob to discover them (`*.md`, `.docs/*.md`, `AGENTS.md`) and Read the relevant one. Do this ONCE at the start of a task, not every turn. If the spec disambiguates a failing test (e.g. "the first and last elements must match" or "spaces and punctuation are excluded"), that single read saves many debug iterations. Skip for pure read-only questions — only invest the Read call when you are about to change code.
diff --git a/skills/protocols/cite_before_answer.md b/skills/protocols/cite_before_answer.md
index e2f910b5..fb7c6bfc 100644
--- a/skills/protocols/cite_before_answer.md
+++ b/skills/protocols/cite_before_answer.md
@@ -6,6 +6,8 @@ when_to_use: always, before producing a final answer on a research task
context: inline
token_cost: 120
user_invocable: false
+description: Checklist for citing saved evidence before final answers on research tasks.
+keywords: [cite, citation, evidence, final answer, research, source]
---
## Cite-before-answer checklist
diff --git a/skills/protocols/research_protocol.md b/skills/protocols/research_protocol.md
index e2f09b5c..e3b2aa5c 100644
--- a/skills/protocols/research_protocol.md
+++ b/skills/protocols/research_protocol.md
@@ -6,6 +6,8 @@ when_to_use: when the task requires gathering facts from the web and citing them
context: inline
token_cost: 180
user_invocable: false
+description: Workflow for evidence-first web research with citations.
+keywords: [research, web, browser, evidence, citation, fact, source]
---
## Research Protocol (evidence-first)
diff --git a/skills/protocols/task_decomposition.md b/skills/protocols/task_decomposition.md
index f93f7169..0cf979bf 100644
--- a/skills/protocols/task_decomposition.md
+++ b/skills/protocols/task_decomposition.md
@@ -6,6 +6,8 @@ when_to_use: when the task has multiple unknowns or clearly requires multi-step
context: inline
token_cost: 140
user_invocable: false
+description: Workflow for decomposing multi-step tasks into knowns, unknowns, and tool steps.
+keywords: [decompose, plan, steps, unknown, task, multi-step, workflow]
---
## Task Decomposition
diff --git a/skills/tools/bash.md b/skills/tools/bash.md
index 44e9e07d..16021063 100644
--- a/skills/tools/bash.md
+++ b/skills/tools/bash.md
@@ -5,6 +5,8 @@ target_tool: bash
priority: 10
token_cost: 120
user-invocable: false
+description: Guidance for running shell commands safely with bounded timeouts and cwd handling.
+keywords: [shell, command, bash, run, execute, test, build, install, cwd, timeout]
---
## Bash Tool
Execute a shell command and return stdout+stderr.
diff --git a/skills/tools/browser_click.md b/skills/tools/browser_click.md
index f9ea0533..0ee110c3 100644
--- a/skills/tools/browser_click.md
+++ b/skills/tools/browser_click.md
@@ -5,6 +5,8 @@ target_tool: BrowserClick
priority: 7
token_cost: 90
user-invocable: false
+description: Guidance for clicking elements in the interactive browser by role or selector.
+keywords: [browser, click, button, link, selector, aria, interactive, navigate]
---
## BrowserClick Tool
Click an element by CSS selector OR by ARIA role+name.
diff --git a/skills/tools/browser_extract.md b/skills/tools/browser_extract.md
index 0db50b95..8eb2eb98 100644
--- a/skills/tools/browser_extract.md
+++ b/skills/tools/browser_extract.md
@@ -5,6 +5,8 @@ target_tool: BrowserExtract
priority: 9
token_cost: 110
user-invocable: false
+description: Guidance for extracting readable text from the current interactive browser page.
+keywords: [browser, extract, page, read, markdown, cursor, citation, interactive]
---
## BrowserExtract Tool
Return readable markdown of the current page, chunked at ~2KB.
diff --git a/skills/tools/browser_navigate.md b/skills/tools/browser_navigate.md
index 7b63c0ce..db1bc39c 100644
--- a/skills/tools/browser_navigate.md
+++ b/skills/tools/browser_navigate.md
@@ -5,6 +5,8 @@ target_tool: BrowserNavigate
priority: 8
token_cost: 80
user-invocable: false
+description: Guidance for navigating the interactive browser to complete HTTP or HTTPS URLs.
+keywords: [browser, navigate, url, website, interactive, page, http, https]
---
## BrowserNavigate Tool
Load a URL in the shared browser page.
diff --git a/skills/tools/browser_type.md b/skills/tools/browser_type.md
index 43ba26bd..a1c5b3aa 100644
--- a/skills/tools/browser_type.md
+++ b/skills/tools/browser_type.md
@@ -5,6 +5,8 @@ target_tool: BrowserType
priority: 6
token_cost: 80
user-invocable: false
+description: Guidance for typing text into interactive browser form inputs.
+keywords: [browser, type, form, input, search, submit, selector, interactive]
---
## BrowserType Tool
Fill text into an input element.
diff --git a/skills/tools/codegraph_memory_search_graph.md b/skills/tools/codegraph_memory_search_graph.md
index 949d8e7f..694cb18c 100644
--- a/skills/tools/codegraph_memory_search_graph.md
+++ b/skills/tools/codegraph_memory_search_graph.md
@@ -5,6 +5,8 @@ target_tool: code_search
priority: 10
token_cost: 150
user-invocable: false
+description: Guidance for structural codebase search over symbols, relationships, and routes.
+keywords: [code, search, codebase, symbol, definition, references, function, class, route, semantic, graph]
---
## code_search Tool
Search the code knowledge graph for functions, classes, routes, and variables. This is a **structural code search** — it understands code relationships, not just text.
diff --git a/skills/tools/edit.md b/skills/tools/edit.md
index 22f93f3f..38c37937 100644
--- a/skills/tools/edit.md
+++ b/skills/tools/edit.md
@@ -5,6 +5,8 @@ target_tool: edit
priority: 10
token_cost: 150
user-invocable: false
+description: Guidance for exact in-place file edits using targeted replacements.
+keywords: [edit, change, modify, replace, patch, fix, refactor, update, file]
---
## Edit Tool
Replace exact text in a file. This is the **default tool for changing any existing file** — prefer it over Write for anything except creating a new file from scratch.
diff --git a/skills/tools/evidence_add.md b/skills/tools/evidence_add.md
index b71bc569..451f6eeb 100644
--- a/skills/tools/evidence_add.md
+++ b/skills/tools/evidence_add.md
@@ -5,6 +5,8 @@ target_tool: EvidenceAdd
priority: 10
token_cost: 100
user-invocable: false
+description: Guidance for saving citable evidence snippets before making factual claims.
+keywords: [evidence, cite, citation, source, fact, research, claim, snippet]
---
## EvidenceAdd Tool
Save a short citable snippet. Every fact you will put in your final answer must come from an evidence entry.
diff --git a/skills/tools/find_read.md b/skills/tools/find_read.md
index 30e4b1c3..1f973e69 100644
--- a/skills/tools/find_read.md
+++ b/skills/tools/find_read.md
@@ -5,6 +5,8 @@ target_tool: findRead
priority: 10
token_cost: 120
user-invocable: false
+description: Guidance for finding files by glob and reading matched contents in one bounded call.
+keywords: [findread, find, read, glob, files, contents, pattern, search]
---
## findRead Tool
Find files matching a glob pattern and read their contents in one call. Combines Glob + Read so you don't need two separate tool calls.
@@ -14,7 +16,9 @@ OPTIONAL: path (base directory, defaults to cwd), maxFiles (default 5, max 50),
RULES:
- Use ** for recursive matching across directories
+- Output starts with the effective invocation: `pattern`, `path`, `maxFiles`, `maxCharacters`, and `ignoreDefaultExcludes`
- Returns each file's absolute path followed by its content, separated by headers
+- No-match and error responses still include the effective invocation prefix
- **Always use conservative limits** — this tool can easily overload the context window
- Default maxFiles is 5 and default maxCharacters is 4000; increase only when needed
- Never use maxFiles > 10 or maxCharacters > 10000 without a specific reason
diff --git a/skills/tools/glob.md b/skills/tools/glob.md
index ce68bc9a..1f2db25a 100644
--- a/skills/tools/glob.md
+++ b/skills/tools/glob.md
@@ -5,6 +5,8 @@ target_tool: glob
priority: 8
token_cost: 80
user-invocable: false
+description: Guidance for finding file paths with glob patterns.
+keywords: [glob, find, files, path, pattern, recursive, list]
---
## Glob Tool
Find files matching a glob pattern.
diff --git a/skills/tools/grep.md b/skills/tools/grep.md
index 4dbba8fd..0575202d 100644
--- a/skills/tools/grep.md
+++ b/skills/tools/grep.md
@@ -5,6 +5,8 @@ target_tool: grep
priority: 8
token_cost: 100
user-invocable: false
+description: Guidance for searching file contents with ripgrep-compatible patterns.
+keywords: [grep, search, regex, pattern, contents, matches, files]
---
## Grep Tool
Search file contents with regex. Uses ripgrep.
diff --git a/skills/tools/read.md b/skills/tools/read.md
index 8a9204be..732ca3f8 100644
--- a/skills/tools/read.md
+++ b/skills/tools/read.md
@@ -5,6 +5,8 @@ target_tool: read
priority: 10
token_cost: 100
user-invocable: false
+description: Guidance for reading files by absolute path with optional line ranges.
+keywords: [read, file, view, show, lines, absolute, path]
---
## Read Tool
Read a file's contents with line numbers.
diff --git a/skills/tools/skills.md b/skills/tools/skills.md
index cabbc0f3..e0620eeb 100644
--- a/skills/tools/skills.md
+++ b/skills/tools/skills.md
@@ -5,9 +5,11 @@ target_tool: skills
priority: 5
token_cost: 80
user-invocable: true
+description: Guidance for listing and loading installed skills by name, type, origin, and description.
+keywords: [skills, list, load, description, keywords, skill, guidance]
---
## skills Tool / Command
-List all available skills (tool skills, knowledge entries, protocols).
+List all available skills (tool skills, knowledge entries, protocols, repo skills, and user-level skills).
Usage: `skills` or `/skills`
@@ -16,9 +18,12 @@ Shows three categories:
- **Knowledge** — algorithm cheat sheets scored against the user's prompt and injected when keywords match (threshold 2.0).
- **Protocols** — research/cite/decomposition workflows injected for research-heavy tasks.
-Skills live under the `skills/` directory at the repo root:
-- `skills/tools/*.md` — tool skill cards (14 files)
-- `skills/knowledge/*.md` — algorithm cheat sheets (13 files)
-- `skills/protocols/*.md` — research workflows (3 files)
+The listing includes each skill's token cost, origin (`repo` or `user`), keywords, and frontmatter description/fallback first line.
+
+Skills load from:
+- repo `skills/` — packaged canonical skills
+- user `~/.pi/skills/` — local reflection-generated or installed skills; exact explicit loads prefer user skills when names collide
+
+Use `/skill ` or `/skill:` to load one explicitly. Use `/promote-user-skill [skill]` to copy stable user-level skills into repo `skills/user//` after duplicate checks.
To find and install new skills from the open agent skills ecosystem, use `npx skills find `.
diff --git a/skills/tools/webfetch.md b/skills/tools/webfetch.md
index d10ef6ef..cea9a527 100644
--- a/skills/tools/webfetch.md
+++ b/skills/tools/webfetch.md
@@ -5,6 +5,8 @@ target_tool: webfetch
priority: 6
token_cost: 80
user-invocable: false
+description: Guidance for fetching non-interactive web pages by URL.
+keywords: [webfetch, fetch, url, web, http, documentation, page, non-interactive]
---
## WebFetch Tool
Fetch and extract content from a URL.
diff --git a/skills/tools/write.md b/skills/tools/write.md
index 0de3b757..348cdb7d 100644
--- a/skills/tools/write.md
+++ b/skills/tools/write.md
@@ -5,6 +5,8 @@ target_tool: write
priority: 10
token_cost: 110
user-invocable: false
+description: Guidance for creating new files only, not modifying existing files.
+keywords: [write, create, new, file, content]
---
## Write Tool
Create a **new** file with the given content. Creates parent directories automatically.