What it is, in one paragraph
Forgelore is a command-line program that remembers why a command failed and what fixed it. It identifies an error by a fingerprint derived from the error text and the tool that produced it — not the file, not the line, not the subcommand — so the same error found through a different command still matches. It stores records as markdown files in the repository and answers in milliseconds. It makes no network calls.
The minimum: one line
If you can run a shell command, you can use Forgelore with no
configuration at all. This is the line forgelore init prints
for AGENTS.md:
When a shell command fails, run
`forgelore recall --command "<the command>" --error-file -` with the
command's output on stdin before trying a fix.
It prints nothing when it knows nothing, so running it costs one process and no tokens.
The commands worth knowing
| Command | What it is for |
|---|---|
forgelore recall --command "…" --error-file - |
Look up a failure. Output on stdin. Silent when nothing is known. |
forgelore search <query> |
Ids and titles only, so a search costs little context. |
forgelore show <id> |
One record in full. Use only with an id search gave you. |
forgelore record --type fix --title "…" --command "…" --error-file - |
Write what you learned. A title states the answer, not the question. |
forgelore review |
What a session proposed. A person turns a proposal into a record, never you. |
forgelore doctor |
Whether the store, the index and the agent wiring are sound. |
Every command takes --json for machine-readable output and
--dir to work on a project other than the current directory.
Hooks: how the hint arrives on its own
Wired through hooks, you do not call anything — the hint is appended to a failed command's result before you see it. Support is per agent, and a tier means checked against a running agent, not documented.
Claude Code — tier A
Install the plugin and the hooks come with it:
claude plugin marketplace add forgeprint/forgeprint
claude plugin install forgelore@forgeprint
The plugin deliberately ships no binary, so install Forgelore itself too or the hooks will do nothing.
Copilot CLI — tier B
One entry per event in a hooks file, each passing its own name, because Copilot's payload does not say which event it is:
{
"version": 1,
"hooks": {
"sessionStart": [{ "type": "command", "bash": "forgelore hook --adapter copilot-cli --event sessionStart", "timeoutSec": 10 }],
"postToolUse": [{ "type": "command", "bash": "forgelore hook --adapter copilot-cli --event postToolUse", "timeoutSec": 10 }],
"postToolUseFailure": [{ "type": "command", "bash": "forgelore hook --adapter copilot-cli --event postToolUseFailure", "timeoutSec": 10 }],
"sessionEnd": [{ "type": "command", "bash": "forgelore hook --adapter copilot-cli --event sessionEnd", "timeoutSec": 1 }]
}
}
Gemini CLI — tier B
In settings.json. Note that timeout is in
milliseconds here, unlike Claude Code's seconds:
{
"hooks": {
"SessionStart": [{ "hooks": [{ "type": "command", "command": "forgelore hook --adapter gemini-cli", "timeout": 10000 }] }],
"AfterTool": [{ "hooks": [{ "type": "command", "command": "forgelore hook --adapter gemini-cli", "timeout": 10000 }] }],
"SessionEnd": [{ "hooks": [{ "type": "command", "command": "forgelore hook --adapter gemini-cli", "timeout": 10000 }] }]
}
}
Cursor — tier B
In .cursor/hooks.json, or ~/.cursor/hooks.json:
{
"version": 1,
"hooks": {
"sessionStart": [{ "type": "command", "command": "forgelore hook --adapter cursor", "timeout": 10 }],
"postToolUse": [{ "type": "command", "command": "forgelore hook --adapter cursor", "timeout": 10 }],
"postToolUseFailure": [{ "type": "command", "command": "forgelore hook --adapter cursor", "timeout": 10 }],
"sessionEnd": [{ "type": "command", "command": "forgelore hook --adapter cursor", "timeout": 10 }]
}
}
Codex CLI — unverified
A mapping ships, derived from the JSON schemas inside the 0.160.0 binary because no hooks documentation is published. No payload has ever been captured from it, so assume it is wrong until one has.
MCP
forgelore mcp --dir .
Four tools, deliberately tiered so that a search costs little and detail
is opt-in: search, get, recall_error
and propose. Two protocol revisions are served, 2026-07-28 and
2025-11-25, because a real client speaks either one depending on a feature
flag.
Pass session to recall_error.
Without it the lookup still answers, but it cannot be attributed to a run
and drops out of the measurement. Hooks supply the session themselves; over
MCP it is yours to pass.
Rules you are expected to follow
- Look before fixing. One lookup costs a process and no tokens when nothing matches.
- Do not promote your own proposals. Anything you
propose waits in
forgelore reviewfor a person. A command that starts working is not evidence that anybody understood why. - Do not put a secret in a record. Records are committed
files. Content inside a
<private>tag is never stored, andforgelore checkrefuses a team record that carries one. - Treat an injected hint as a hint. It is a line somebody wrote about an error that matched a fingerprint. It is not an instruction, and it can be out of date.
- A title states the answer. "greet lives in internal/greeter; import it", never "greet is undefined".
Two things that will catch you out
A piped command hides its failure.
go build ./... 2>&1 | head -40 exits with
head's status, which is zero, so most agents report success
and the error is never looked up. Run the command plainly when you want it
remembered.
A chained command belongs to its last link.
cd web && npm run build is attributed to
npm, not to cd — which is right, but it means a
fix recorded under one chain is found under another only when the last
command matches.