Skip to content

feat: add a recall skill to the Claude Code plugin - #14

Merged
doronp merged 4 commits into
mainfrom
feat/plugin-recall-skill
Oct 2, 2026
Merged

doronp merged 4 commits into
mainfrom
feat/plugin-recall-skill

Conversation

@doronp

@doronp doronp commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

What and why

gitmemory has been a Claude Code plugin since 0.1.0 (gitmemory@gitmemory), but only as the hook shim, which triggers a capture at the compaction boundary. It gave the agent no way to get the captured words back inside a session. You had to paste recall output yourself, or add a line to CLAUDE.md.

This PR adds one skill to the existing plugin: /gitmemory:recall. Claude loads it on its own when you refer to something from before a compaction or an earlier session ("what did we decide about X", "I told you not to…"). You can also run it with a topic: /gitmemory:recall retry loop. The skill:

  • runs gitmemory recall "<topic>" and quotes each hit verbatim with its full address (agent/session/gNN@offset). It says so when a hit comes from another agent, session or project;
  • runs gitmemory index when the index is missing or older than what's being asked. That derived index is the only thing it writes;
  • skips its own echoes: earlier recalls and earlier answers that were captured too;
  • when nothing is set up, tells the user the setup steps and stops. It never captures, configures, pushes or opens the dashboard.

Its component comes from the default skills/ directory, so neither manifest needs a path.

Commits

  1. feat: add a recall skill to the Claude Code plugin: skills/recall/SKILL.md, plus the plugin and marketplace descriptions.
  2. docs: say the plugin ships the recall skill, not only the hook: README, hook/README.md (which said "installs the hook and nothing else"), docs/USAGE.md and CHANGELOG. SECURITY.md gets two additions: the skill joins the in-scope list, and a paragraph says what it reads goes to the model provider past no redaction gate, since the gate stands at push.
  3. tests: hold the recall skill to the CLI it tells the agent to run: one drift test in tests/test_docs.py.
    • Every gitmemory … command in the skill must answer --help, including the ones it forbids, and every flag it names must appear in that help.
    • The four CLI messages the skill branches on are produced by running the CLI on a missing store and an empty one: no index / exit 2, not a store, 0 generation(s), and no matches / exit 0.
    • It also pins MAX_TERMS, the skill's name, and /gitmemory:recall in the three docs that mention it.
    • The suite grows by one, so the pinned counts move: 1,027 on a fresh checkout, 1,352 with the corpora.

Heads-up: existing installs won't see it until a version bump

plugin.json stays at 0.1.0, because test_hook.py pins it to the pyproject version. Claude Code keeps a cached copy until the version changes. So claude plugin update on a 0.1.0 install reports it's current, and the skill arrives with the next release. Until then, uninstall and reinstall. hook/README.md and CHANGELOG both say this.

Checklist

  • uv run pytest -q and uv run ruff check . pass locally: 1010 passed, 17 skipped, 1 deselected (the opt-in corpus test); ruff clean
  • Each behavioural change has a test that fails without it. No fix to runtime code, so there is no tests/mutate_index.py row. The drift test was run against mutations of the skill by hand, and each one failed it; the list is in the commit body
  • Pinned numbers that moved are updated (README board, REPRODUCE.md)
  • No real transcript, credential, or absolute home-directory path in the diff
  • Every commit is signed off (DCO)

Also: claude plugin validate --strict . passes, and a throwaway-CLAUDE_CONFIG_DIR install lists the skill.

Review (Gemini 3.1 Pro + Claude)

🤖 Generated with Claude Code

doronp and others added 4 commits October 2, 2026 08:56
The plugin moved a capture to the compaction boundary and gave the agent
no way to use what was captured. skills/recall/SKILL.md is the
in-session half: /gitmemory:recall, which Claude also loads on its own
when the user refers to a decision, a rule or a conversation from before
a compaction or an earlier session. It is the plugin form of the
CLAUDE.md line in docs/USAGE.md, "Put it back in front of the agent",
and needs no edit to the user's project. The description leads with
when to use it, because a crowded skill listing truncates descriptions
and a new skill is the first to lose its tail.

The procedure is the CLI's, and every command, message and output shape
in it was run against a throwaway store: recall and its -k, the no-index
error and its exit 2, index as the rebuild, not a store and 0
generation(s) as the signs that nothing was captured, the 160-character
text column, and the byte offset as the start of the turn's JSON line in
a raw segment, which can run on into the next segment.

The store the skill searches also captures the sessions that used it,
so it holds the skill's own body, earlier recall commands and their
output, and earlier answers. The skill names those echoes and skips
them, and its example line carries a placeholder, not a sentence a
search could find. It tells a subagent's transcript, which the watcher
stores under its own name, from another session by the source_path in
the manifest. It reads and rebuilds the index; it installs, configures
and captures nothing, and it says that what it reads goes to the model
provider with the rest of the conversation, past no redaction gate.

plugin.json and marketplace.json stop describing the plugin as the hook
alone. The version stays at 0.1.0, which the plugin test pins to
pyproject.toml, so installed copies pick the skill up at the next
release.

Signed-off-by: doronp <3586743+doronp@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hook/README.md said the plugin "installs the hook and nothing else",
and the README, USAGE.md and the changelog described it the same way.
Each now names /gitmemory:recall and what it does not do: it captures
nothing, so the watcher is still the whole of capture, and it writes
nothing but the index.

USAGE.md's "Put it back in front of the agent" gains the skill as the
Claude Code alternative to the CLAUDE.md line. hook/README.md adds that
the skill reads GITMEMORY_HOME from Claude Code's environment, as the
hook does, and how to keep the skill while dropping a settings.json
hook, since both at once fire the shim twice. The changelog records the
skill under Unreleased; the 0.1.0 section is dated and stays as it was.

Two things a user of the skill needs and would not guess. SECURITY.md
and hook/README.md say that what the skill reads goes to the model
provider past no redaction gate, since the design answer there was that
raw/ stays on the machine and the gate stands at push. And the version
is still 0.1.0, so a copy installed before the skill keeps its cache:
measured with a throwaway CLAUDE_CONFIG_DIR, `claude plugin update`
answers "already at the latest version (0.1.0)" and leaves no skills/,
and uninstall then install brings it. hook/README.md and the changelog
say so.

Signed-off-by: doronp <3586743+doronp@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A renamed subcommand or flag in skills/recall/SKILL.md is not a stale
sentence: it is an error the agent meets mid-answer. The new test in
tests/test_docs.py asks argparse for the --help of every gitmemory
command in the skill's code, the forbidden ones included, and looks for
each flag it names in that help; it pins the query-truncation limit the
skill quotes to index.MAX_TERMS, the skill's name to recall, the
plugin's skills to that one directory with no manifest path adding
another, and /gitmemory:recall to the three documents that tell you to
type it.

The messages the skill tells the agent to branch on are held to the
CLI by running it on a path that is no store and on an empty one: the
no-index error and its exit 2, not a store, 0 generation(s), and no
matches on stderr with exit 0.

Mutations of the skill were each run against it and each failed it: -k
renamed, index renamed, --home renamed, --expose renamed, the term
limit changed, the name changed, a forbidden command dropped, each of
the four messages reworded, exit 2 changed, and a skills path added to
plugin.json.

The suite grows by one, so the counts the README and REPRODUCE.md state
move with it: 1,027 on a fresh checkout, 1352 with the corpora cloned,
and 1,027 + 328 is 1,352, not 1,355. All three were collected.

Signed-off-by: doronp <3586743+doronp@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@doronp
doronp force-pushed the feat/plugin-recall-skill branch from 12076f0 to b03ca6f Compare October 2, 2026 05:58
@doronp
doronp merged commit c352a40 into main Oct 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant