Skip to content

Claude Code: the hook and the plugin

Claude Code can use passageway in two ways, and the plugin sets up both:

  • The recall tool

    Over MCP. The model calls it when it decides to search; the server sends instructions on connect that say when.

  • A prompt hook

    UserPromptSubmit sends every prompt to the server and adds up to three short passages when the sources have something, and nothing otherwise. A model only calls a tool when it thinks it needs one; the hook does not ask.

Install the plugin

/plugin marketplace add getpassageway/passageway
/plugin install passageway@passageway

This gives you the hook, /passageway-install that installs the server on this machine and runs it as a service (and, run again, upgrades it to the latest release), the /passageway-connect skill that connects it, /passageway-add-source that writes a source into passageway.toml, /passageway-evaluate that measures retrieval quality on your own questions, /passageway-status that checks the whole chain when something is off, the /passageway guide and /create-passageway-connector. Run /passageway-install for a local server, or /passageway-connect for one that already runs, and give it the server's URL; it checks /health, writes the hook's config and registers the MCP server. A fresh passageway.toml has no source yet: /passageway-add-source writes the [[connector]] for a folder of markdown, Trilium, Confluence or Wikipedia, with secrets as env: references, and tells you how to restart. Never paste the password into the chat: the skill reads it from ~/.config/passageway/password for a local server, or you pass it through a variable.

How the hook behaves

  • It reads passageway.json ({"url", "token"}), and one passageway-<name>.json per further instance, from the plugin's data folder or from ${CLAUDE_CONFIG_DIR:-~/.claude}/plugin-data/passageway/, where the connect skill writes them, readable only by you. With several, it asks them all at once and joins their passages. A recall.json left by trilium-recall is used until it is replaced.
  • It posts the prompt (the first 20,000 characters), the session id and the working directory to POST /recall. The password and the prompt go through files only you can read, never on a command line.
  • It waits at most 1.5 s. A slow or broken server, no config, a bad answer: no output, exit 0. It never blocks a prompt.
  • What comes back is the rendered passages (context), which it hands to Claude as additional context. The server remembers per session what it already showed, so a passage is not repeated.
  • bash "$CLAUDE_PLUGIN_ROOT/scripts/test-recall-hook.sh" checks the hook against a stub server: a hit, no hit, errors, a slow server, a huge prompt, both config folders, several instances, and that neither the password nor the prompt shows up in the process table; scripts/test-recall-hook.sh in the repository is the same file.

Without the plugin

The hook is one shell script, scripts/recall-hook.sh; any hook runner can call it with the Claude Code hook input on stdin. The MCP registration is one command:

claude mcp add --transport http passageway "http://127.0.0.1:8082/mcp" -H "Authorization: Bearer $(cat ~/.config/passageway/password)" -s user

On claude.ai, the desktop app or Cowork there is no hook: add the server's public HTTPS URL ending in /mcp as a custom connector and log in with the password (the server needs PASSAGEWAY_BASE_URL for that login page, see Install).