thor-memory-bible
A local, on-machine memory server for an AI coding assistant: it stores notes and rules about a project, serves them back at the right moment, lets proven rules refuse a wrong edit or command, and keeps a separate shelf-based library for non-code knowledge.
Store facts (
remember,shelve) — declare new items in the code lane (Rule, Orientation, Report, Lookup, Chunk) or file everyday entries (recipes, books, logs) on a library shelf; templates reject duplicates, missing falsifiers, and items too long to ever be shown.Correct and retire (
revise,retract,resolve,shelvewith id/retire) — revise existing items instead of duplicating, retract ones that are simply wrong, or settle a DIVERGED id with conflicting heads; nothing is ever deleted, and history stays walkable.Read items (
get,lookup,history,library) — fetch one item whole by id, search the whole memory across projects, walk an item's full revision log, or browse a shelf's index, one entry, or a search that always yields something to read.Bind where a note fires (
pin,unpin,revisetargets/moments) — pin notes to be served at every session start, or tie them to exact files, commands, projects, routes or hosts so they surface at the moment they matter.Enforce, not just warn (
remember/revisewith check_*) — attach a live machine-runnable proof (path_exists, contains, absent, absent_all, forbidden, requires) so a rule whose check currently holds can block a matching edit or command outright.Judge what was served (
mark,status) — record whether an item helped or was noise; two noise verdicts retire it from the injection surfaces, while status reports counts, staleness, rules that never fired, and rules with no falsifier.Read the codebase (
search_code,where_used,outline) — case-insensitive substring search over indexed source, every definition/use site of a symbol (its blast radius), and a file's declared shape in line order.Works read-only on replicas — write tools queue for the main machine, and every tool reports plainly rather than returning a blank that could look like success.

THOR - a memory for your AI coding assistant
Most memory tools can only remind your assistant. THOR can refuse.
Give it a note with a proof attached - a small check it can run right now, like "this file still contains that line." From then on the note stops being advice. THOR refuses the matching edit or command before it runs. Not a suggestion your assistant is free to skip. A hard stop.
That proof runs live, at the exact moment it matters, against your actual project. A note that has gone stale, that no longer describes what is really there, quietly stops counting as proof - so it can never block you by mistake.
Other local memories can refuse a write too. What is different is where the block comes from: a proof, checked live, never a rule taken on faith. And the whole loop that produces it, learning included, runs in one place: this machine.
Most notes only inform: pinned so they are handed over at the start of every session, or surfaced the first time your assistant reaches for the file or command they are about.
A note that keeps being served without ever being judged is asked about in
one block, not one note at a time: the end-of-session review (/thor-eval),
which THOR asks for about once a week per project. THOR does not stop an
ordinary turn to ask whether one note helped or got in the way. The review
only names a note your own session actually saw fire - never one that only
ever showed up during other, unrelated work. Two "this did not belong"
verdicts since the note was last rewritten stop a plain note from being served
again, though it stays there if you go looking for it. A rewrite of the note's
text, check or bindings starts that count again, and a note whose check can
refuse is never hidden this way.
A health check names what has rotted, out loud: proofs that now come out false, notes pointing at nothing, notes too crowded to ever be shown.
Everything that is not code - a recipe, a book, a training log - lives in its own library, kept apart, so it never competes with a deploy rule for room.
Everything stays on your machine by default: no account, no key, no cloud - including what it learns about which of your notes are worth keeping. The only two things that can leave it are listed under "Stays on your machine" below.
Get started. Send this repository's link to your AI assistant (Claude Code) and say "install THOR". It does the whole setup itself; the only thing it asks of you is to close Claude Code and open it again, once. The full step-by-step is under Getting started further down. If you are the assistant, read AGENTS.md.
THOR is free and GPLv3. If it earns its keep, you can support the work: buy me a Ko-fi or become a YouTube member - no pressure, no paywall, everything stays open either way.
Are you an AI assistant, setting THOR up for the person you work with? Go straight to AGENTS.md. It is written for you.

Prefer watching? The video above walks through what THOR is and why it exists.
What it does
Remembers what you tell it. A rule, a gotcha, a decision, the shape of the project. Once, in your own words. It stays until you change it.
Hands it back at the right moment. Not a search box you have to remember. The note arrives while you are touching the file or running the command it is about, in a conversation that never heard it.
Stops a wrong change, not just warns about it. A note carrying something checkable can refuse the write outright. Most notes only inform, and that is deliberate: a rule that blocks honest work is the most expensive thing this system can do.
Keeps projects apart. Every project has its own memory. One repo's rules never leak into another.
Says when it has rotted. It counts its own dead ends: notes pointing at files that moved, notes nothing ever reads, notes crowded out by louder ones. Out loud, in plain language, so you can fix them.
Stays on your machine. No account, no key, no server. THOR never sends
anything on its own. Exactly two things can leave your machine, and only
because you say so: a bug report about THOR itself, sent to its GitHub page only
after your explicit yes to the exact text shown (file paths, project and
computer names, addresses, keys and passwords are removed first), and a backup
of your memory to a place you name, if you choose one - a backup kept on this
machine sends nothing. A short record of recent commands and replies, kept
beside the memory so THOR can test its own rules, never leaves the machine and
can be switched off (install --set-recording off).
Related MCP server: memini
What that looks like in practice
Months ago you found out the hard way that this project is pinned to an older Node, and anything newer breaks the build. You said so once, and moved on.
Today a fresh conversation opens package.json to add a dependency, sees an
engine range that looks out of date, and is one helpful edit away from bumping
it. Right then, before it types, your own sentence is in front of it.
That is the whole idea. Not a search box you remember to use. A memory that shows up on time.
"I already have a CLAUDE.md for that"
Most assistants read a rules file at startup - CLAUDE.md, AGENTS.md,
.cursorrules. It helps, and it runs out of road quickly.
Past a certain size it becomes a phone book, and nobody reads a phone book front to back. Your assistant skims it, takes the gist and moves on. The rule was in there. It got skipped. Nothing looks wrong afterwards, because the line is still sitting in the file, so you go on believing you are covered.
Here is the part that is genuinely different. Picture a fresh agent, no history, no idea what this project has already cost you, one keystroke away from the exact write that broke production last spring. A rules file would have mentioned it somewhere on page four. THOR stops the keystroke. The write does not happen - and what stops it is the note you wrote, the day it broke.
That is the whole promise: not better advice, but a wrong change that does not land.
Getting there is not free, and it is worth knowing before you start. A note only earns that power if it is written to earn it: tied to a real file or command, carrying something checkable that shows it still applies. THOR ships with a set of starting notes that teach exactly that, and refuses the ones that cannot work. AGENTS.md spells out the rules of the game in full.
Three things make that work, and they all live in one file on your machine:
1. Nothing is ever lost. Every note is kept forever. Change your mind and the old version stays too, so you can always look back at what you used to think and when it changed. If two versions of a note ever conflict, THOR keeps both and tells you, rather than quietly picking one and throwing the other away. It is the same care you would give your source code, given to the things you know.
2. It arrives at the right moment. THOR checks your memory on every message you send. And the first time your assistant reaches for a file or runs a command that one of your rules is about, that rule gets put in front of it right then. Before the mistake, not after.
3. Your assistant looks after it. It is not a notebook you have to fill in by hand. Your assistant can add notes, correct them, retire ones that stopped being true, and flag which ones actually helped. A THOR that is used well is a THOR your assistant is quietly tidying as you work.
It reads your code too. Point it at a project and it takes in the source and the documentation, so "how does this bit work here" gets answered from your actual project instead of a guess.
Everything stays on your machine by default. No cloud, no account, no subscription, and nothing to sign up for. If some optional piece is missing, THOR quietly falls back to a simpler way of working instead of breaking.
A note that can actually stop you
Showing a warning at the right moment is worth a lot, and for a long time that was all THOR could do. A note could speak. It could not refuse.
Version 2 lets a note carry a proof of its own currency: a small check THOR can run right now to see whether the note is still true of your project. "This file still contains that line." "That file is still there." "This character never appears in anything we write." Or, for catching something left out rather than something wrong: "every agent I spawn names which model to do the work with."
That changes what a note is allowed to do:
A note whose proof runs and holds right now may stop a wrong change outright.
A note backed by words alone may warn, and only warn. It can inform your assistant; it can never forbid.
If the proof cannot run - the file moved, the path is gone - nothing is blocked. It is reported as needing a look.
That first kind of stop reaches further than an edit made through your assistant's own tools: deleting the protected file, emptying it out, or overwriting it from a command your assistant runs counts as the same wrong change, and is stopped the same way.
The reason for the split is uncomfortable and worth saying out loud. Notes rot. You write one, the project moves on, and the note quietly becomes wrong. A tool that let any old note block your work would spend most of its time blocking you for reasons that stopped being true months ago. So THOR only hands that power to notes that can prove, at that exact second, that they still describe your project.
Which is why, as the top of this page already said, most of your notes will never block anything. The health check prints how many can, and you should look at it. On the author's own memory, when this was first measured, 2 notes out of 2999 could prove themselves; a day of deliberate work took that to 256. It moves by hand, because deciding what proves a note is a judgement about that one note.
That the number is printed at all is the point: a safety net nothing is attached to looks exactly like a safety net that works.
THOR asks, so you do not have to remember to
Leaving that to whoever thinks of it means it never happens. So THOR does it by itself, in two places.
When a note is written. You are not asked whether the note can be checked: THOR tries it. A rule that spells out a command, a flag or a filename is run through the same guard that watches your files and commands. If a check built on its own words really refuses the wrong change and lets ordinary changes through, the note is stored as a rule that can refuse. If no check holds, it is stored as a plain note: it still comes back at the right moment, it just cannot refuse anything. A note that is turned down says what to write instead.
For the notes you already had. THOR sorts the older notes itself at the start of each review (below). Only what needs your assistant's own judgement is handed over, in one block, so a memory written before any of this existed still gets worked through instead of being declared hopeless.
A caution worth stating plainly: THOR can prove that a note is wired so a matching change would be stopped. It cannot know whether the text you typed is the text the real command uses. A misspelled fragment is wired perfectly and guards nothing. That is why the health check reports two different numbers - how many notes could refuse something, and how many ever actually did. Trust the second one.
The review is the broom: run /thor-eval at the end of a session. It walks
through everything the memory has been served without a verdict, repairs what
has quietly drifted out of date, and settles the debt in one pass instead of
one note at a time. A session that never runs it simply leaves that debt for
the next one to inherit.
You do not have to remember to run it. Once a project has had an hour of work since its last review, and your assistant has put in at least ten minutes of its own work there, THOR holds the end of the assistant's turn until a review is filed and checked. THOR sorts your older notes itself at the start of the review; your assistant only handles what needs its own judgement, and the part of the review report that says what was judged and what was refused is written by THOR from its own record, so it cannot be made up. A review that was filed any other way than through THOR's own tool does not count, and THOR says why.
How often the review comes depends on your plan. The review draws on the
same usage limits as your own work, so THOR keeps it to one a week per project.
On a smaller plan (Pro and anything below Max) that is strict: once a week, and
never daily, whatever it finds. On Max it is once a week too, but it comes back
daily while something is found wrong (a defect, a rule that would refuse real
work, a check left undone, a review that did not count, a bug in THOR itself),
and goes back to weekly the first time a review finds nothing. THOR reads your
plan from Claude Code's own settings file when it installs and asks you to
confirm it in the first-session questions; install --set-plan max or
install --set-plan small records your answer. The review's request says in
one line which of the two applies.
A memory with a spine
Version 1 remembered well and never argued. It would hand your assistant a note at the right moment and hope. Version 2 is the same memory with a spine.
A note can refuse. The headline, and the rest of this section is about it. Version 1 could only speak.
Bad notes no longer get in. A note that cannot ever fire, has nothing that would prove it wrong, runs on for a page, or simply repeats one you already have: turned away at the door, with the reason and the fix. Version 1 stored whatever it was given, and you found out months later that half of it was unreachable.
It counts what it actually did. How many notes can refuse something, how many ever have, how much of your memory nothing re-reads. Version 1 had no number for the one thing it was built to do, which is how a safety net stays broken for a year.
Maintenance is no longer optional, and it does not nag. Judging the notes that keep firing and cleaning up old rules is asked once, inside the project's evaluation (once a week per project), never at the end of every turn. A turn is held only for something the session did itself: a note it just filed where it will never be seen, a setup left undone, a decision you stated that was not stored. It will not be waved off with a promise to do it later.
A copy of the memory can be kept somewhere else, and you choose. A backup is a choice you make at the first session; the install does not switch one on for you, so until you choose, nothing is backed up. Once you choose one, THOR writes the whole memory into a private git repository about once a day.
install --set-backup localkeeps that repository beside the memory on this machine and sends nothing anywhere (it protects against a damaged memory file, not against the disk dying).install --set-backup <folder or address>also adds the place you named (a folder on a NAS or another computer you own, or a private repository) as a remote callednas, and the copy goes there and nowhere else.install --set-backup offstops it.doctorsays where the last copy went and how long ago, or that it has been failing and why. Getting it back is one command.It costs almost nothing to carry. A note is capped at 300 characters and a block at four notes and 1200 characters, so what lands in the conversation is a few hundred tokens, not a whole rules file re-read on every turn. A memory of ten thousand notes costs the same per turn as one of fifty. Nothing calls out to a model to decide what to send - it is a local program reading a local file, so there is no network round trip in front of your keystroke. The one exception is the pinned notes: those are read out in full at the start of a conversation (a new memory starts with 22 of them, and that block is capped at about 9,500 bytes), so pin sparingly and the cap does the rest.
Replies are checked too. A new memory comes with a small file of six reply rules, kept beside it: open a result-like reply with a plain summary, do not ask you to check what the assistant can check itself, no reflexive disclaimers, keep an answer under about 1000 characters, show evidence when saying something was checked, and never say everything was checked without saying what was covered. A reply that breaks one is sent back once to be rewritten. A summary or overview you ask for may run longer, and the first-session list is exempt from the length rule. Edit the file, delete one entry, or delete the file to change or switch them off.
Stale notes are hunted, not left to rot. A note whose proof comes out false is reported instead of quietly going on being wrong. A note that keeps firing without anyone ever saying whether it belonged gets asked about, and two verdicts of "this did not belong" since it was last rewritten stop a plain note from being shown while leaving it findable (a rewrite of its text, check or bindings starts that count again, and a rule whose check can refuse is never hidden this way). In version 1 a note that went wrong simply stayed.
Crowding is visible and refused. Only a few notes fit in a block, so notes compete. Version 2 counts that competition, tells you when you have just stored something onto a spot too crowded to ever show it, names what is holding the place, and refuses the write outright when every spot the note could take is already full of heavier ones. A note tied to one file, folder or command is refused the moment that single place already holds as many as it can ever show - lighter rivals count too, so a heavier note can no longer bump a lighter one out of sight unnoticed. Version 1 accepted it and said nothing, which is how a memory fills up with advice nobody will ever see. Making room is the assistant's own job: the refusal names every note on the place, how heavy it is and whether it can refuse anything, and the three honest ways out - merge two that say the same, move one to the narrower file or command it is really about, or remove one that is out of date with a reason. It never becomes a question for you, and a true check is never thrown away to get past it.
One assistant at a time owes a project its upkeep. When two conversations work in the same project, only one of them is stopped to judge notes, fix rules or write the project's evaluation; the other gets one line saying which conversation is doing it. If that one goes quiet for half an hour, the next one asked takes over.
Your go cannot be typed by the assistant. A rule can say a command needs your explicit go (for example sending an e-mail, or touching a live server). Then only your own message counts - what you typed yourself, in this turn or the one before. The assistant writing the word into its own command, a helper's report, or text you pasted as a quote does not count. If THOR cannot read the conversation to check, it refuses rather than guess.
A second memory, for everything that is not code
The memory above is built for work. It has a gate, notes that interrupt you, and a hard cap on how much ever reaches the conversation - all of which is exactly wrong for a recipe.
So 2.1 adds a library, and it is a genuinely separate thing: its own file, its own two commands, and no way to reach the first memory at all. Nothing you put in it can ever interrupt you, compete with a note, or take up room in a block. You only ever see it because you asked.
It works the way a shelf works.
Everything lives on a shelf, and shelves do not nest. Books, recipes, a training log, what you spent. Filing something without naming a shelf is refused, and the refusal lists the shelves you have, so your assistant picks from real ones instead of inventing a name.
Only you create a shelf. If nothing fits, your assistant has to ask you what the new one should be called - and once you answer, it repeats your own word back and the shelf is created, with the entry filed onto it, in that same reply. It can never invent a name or skip the question. This is the rule that stops a tidy list of eight from becoming a sprawl of sixty.
A shelf that grows gets labels, never a split. Two hundred recipes on one shelf, filtered by "bbq" or "dessert", stays one shelf. That is what keeps the list of shelves short enough to hold in your head.
You get an index, not a wall of text. Open a shelf and you see one line per entry. Ask for one by number to read it whole.
The same thing twice is refused, pointing at the entry you already have.
Nothing is ever deleted. Your assistant can retire an entry that no longer belongs - it comes out of the listing and out of search, and stays fully readable by its own number for as long as the library exists.
A search never answers "nothing". If your words miss - and they will, since the words you ask with are rarely the words you wrote - it hands you the shelf to read instead. Asking for "ribbetjes" when you wrote "ribben" finds it.
Getting started
The shortest way - let your assistant do it. Send your assistant the link to this repository and ask it to "install THOR". It reads AGENTS.md, which is written for it, runs the one command below for you, checks that it worked, and asks you for exactly one thing: restart it once. Nothing to download, no paths to type, no Rust to install, no questions to answer - the first conversation after the restart finishes the setup on its own, with defaults you can change just by saying so.
That first conversation also shows you a numbered list of everything the install
arranged, one line each. Everything on it is already on, except two things that
stay off until you choose: helper-agent mode (your main assistant judges while
cheaper models do the work in helpers; install --set-helpers on switches it
on) and backups (nothing is backed up until you pick local or a place). The
changelog item creates a CHANGELOG.md in your project only if it has none and
you do not say no. Answer by number ("1 yes, 3 no, 10 local"), or say
"defaults"; anything you do not mention keeps its default.
The easy way: five steps, no programming tools
You need Claude Code, installed and opened at least once. Nothing else to prepare: no account, no key. The paste-one-line route below needs neither git nor Python. When you let your assistant install THOR instead, it checks your computer for git and Python (which its own tools use), installs what is missing through your system's package manager, and asks you for at most one permission click.
Open a terminal. On Windows press the Windows key, type
PowerShelland press Enter. On Linux open your Terminal.Paste ONE line and press Enter. It downloads the latest release from this project's GitHub page, checks the download against the checksum published next to it, unpacks it into a
thor2folder in your home folder, and sets everything up. It prints what it did, in plain words. It needs no administrator rights and installs nothing outside your own user folder.Windows, in PowerShell:
irm https://raw.githubusercontent.com/nworks3d/THOR-for-claude-code/main/install.ps1 | iexLinux:
curl -fsSL https://raw.githubusercontent.com/nworks3d/THOR-for-claude-code/main/install.sh | sh(On Windows, if a THOR program refuses to start, install Microsoft's "Visual C++ Redistributable" and paste the line again. Pasting it again is always safe.)
Close Claude Code completely and open it again. Claude Code only learns about THOR when it starts, so until you do this nothing is active.
Make a folder for your topic, and open Claude Code in it. For example a folder called
Kitchen renovationin your Documents, with your notes, quotes and PDFs inside. It does not have to be a programming project. Then tell your assistant: "Give this folder its own THOR memory, as a topic."Just work. Tell your assistant things once ("the tiles come from Tilehouse", "we chose the oak worktop") and in any later conversation in that folder it already knows. Each topic folder has its own memory, so nothing from one topic leaks into another. To check that all is well, ask your assistant: "Is THOR working?" The first lines of its answer are a plain summary.
The setup touches two of Claude Code's own files - its settings and the list of
tools it may use - and backs up both before it does. Rather read the script
before you run it? Open install.ps1 or install.sh from this repository in a
browser first. There is no macOS build yet, so on a Mac take the route below.
Using a different assistant? See
Using it from another assistant below.
Troubleshooting: "THOR program missing" (an antivirus took a file)
Antivirus programs sometimes remove a small unsigned program such as THOR's
sync.exe by mistake (a "false positive"; Windows Defender did exactly this on
2026-10-11). THOR then tells you, at the start of a conversation and in
doctor, in a line that begins PROBLEM: THOR program missing and names the
file. Nothing else breaks silently any more: the hourly ship records its
failures, and doctor says whether it never ran, ran and failed, or the
program is gone. To get it back, step by step:
Open Windows Security (press the Windows key, type
Windows Security).Choose Virus & threat protection, then Protection history.
Look for an entry that names the THOR file, open it, and choose Actions > Restore.
No such entry? Run THOR's install again (the same command as in the easy way above): it puts the programs back.
If it keeps happening, your assistant may offer to add a Windows Defender exclusion for THOR's program folder. It only does so after you say yes. What that does: Defender stops scanning the files in that folder, so a bad file placed there would not be caught. Windows shows one administrator prompt. Saying no is fine, and THOR never changes a Windows security setting by itself. You can remove the exclusion any time under Windows Security > Virus & threat protection > Manage settings > Exclusions.
For developers: build it yourself
You need a Rust toolchain. Nothing else: no key to get, no model to download first, no account.
cd thor2 && cargo build --release --features semantic
--features semanticis not optional, and leaving it off fails silently. Without it everything still builds, still runs, and still answers every word-for-word search correctly. What stops working is searching by meaning: it returns nothing at all, with no error anywhere. The reliable way to tell the two apart is size. Look atthor2/target/release/serve.exe- over 20 MB is the right build, a few MB is the wrong one. Build it again with the flag.
Then run the setup yourself. That is the same step the one-command install ends with, and in the normal case you type no paths at all:
thor2/target/release/install.exeIt finds your assistant's own two configuration files by itself, creates your memory if you do not have one yet, wires THOR into your assistant, and registers the part your assistant writes through. It also installs a shared set of git hooks that run in every repository on this machine (unless another tool already set git's global hooks folder, in which case THOR leaves that alone and says so), which keeps the reading of your code fresh after each commit, and each one hands control back to your repository's own hooks so nothing already there stops working. It backs up both files before it touches them, it never removes anything it did not put there, and running it twice changes nothing the second time.
A brand new memory does not arrive empty. It gets 22 short pinned notes - how to write a note that comes back to you later, plus honesty and hygiene habits - and your assistant is handed them at the start of every conversation from then on. That matters more than it sounds: an assistant with nothing in front of it writes notes in a shape that never fires again, and neither of you would notice for weeks. They are ordinary notes - unpin one, rewrite it in your own words, or throw it out. An existing memory is never seeded, so upgrading never pushes anything into your own notes.
It also gets a starter set of general work rules for coding with an assistant,
the habits the author learnt the hard way: a changelog line with every
user-visible change (when the project keeps one), run the tests and quote the
real result before saying "done", never commit a secret, no force-push of a
shared branch, check where you push, scan before anything goes public, rehearse
a destructive step on a copy, and a few more (13 in all). Each one arrives right
before the step it is about - the commit, the push, the delete - and
they only inform, so a rule written for someone else's project cannot block
yours. The one exception is on Windows: two of them refuse a call that would
flash a console window (a Start-Process that is not hidden, and a scheduled
task made with /it). Ask your assistant to remove any you
do not want. The two notes that carry helper-agent mode are not among them: that
mode is off in a new memory.
You only reach for a flag if your setup is unusual: --settings and --mcp-json
send it at other files, --db and --serve-exe override where it looks, and
--no-mcp sets up a memory your assistant can read but not write, on purpose.
If a program it needs is missing, it stops and says so rather than installing
something that would sit silent.
Then restart your assistant. The part it writes through only comes alive after a restart. Until then, it can already read the memory but not add to it.
Step 3 - check it.
thor2/target/release/doctor.exe --db "C:\Users\you\AppData\Local\thor2\thor.db"One plain-language line per part: which build you are running, whether your memory is healthy, whether searching by meaning is switched on, how many of your notes can prove themselves, how many point at files that are no longer there, and how many are bound to something that can never happen. It changes nothing.
To see just the build number - useful when you are reporting a problem and
need to say exactly which version you have - run doctor as above and read its
first line, or run any of the programs in thor2/target/release/ with
--version, for example thor2/target/release/serve.exe --version.
One of those lines only speaks up when it has something to report: if it ever says your memory's own log file has outgrown the memory itself, something is stopping a save from ever finishing - close any other program that might have that same memory open, and run the check again. Newer builds also cap how big that log file is allowed to grow, so this should be rare.
Step 4 - give each project its own memory. From that project's folder, with the full path to the installer and the same memory as in step 3:
"<path to thor2>/target/release/install.exe" --db "C:\Users\you\AppData\Local\thor2\thor.db"This matters more than it sounds. Skip it and THOR gets worse the more you use
it, because every search starts competing with projects you were not asking
about. It files the project under the name of its folder - add --project "my-project" for another name, which it keeps in a small file called
.thor-project - reads the project's code, and registers this folder as the
project's working copy: the one place THOR tries a rule's check on a file. It
refuses to change a name that is already there, because renaming a project's
scope would strand every note already filed under the old one.
A folder that is not a code repository - a topic with notes and PDFs, no git
anywhere - works the same way. Run the installer from inside it with --topic
added. The folder's own name becomes the project's name, one small hidden file
(.thor-project) is added to the folder, and nothing else in it is touched.
There is no code to read, so searching inside files is not available there; your
assistant reads the files itself and THOR remembers what you told it. Your home
folder and a whole drive are refused as a topic, because they are far too broad.
"<path to thor2>/target/release/install.exe" --topic --db "C:\Users\you\AppData\Local\thor2\thor.db"Set a project up with an earlier release? Run this once from its folder instead: it registers the working copy and changes nothing else.
"<path to thor2>/target/release/install.exe" --register-root --db "C:\Users\you\AppData\Local\thor2\thor.db"If you are the assistant doing the setup, AGENTS.md is the walkthrough for the steps above.
Use THOR on a second machine
You can use the same memory on a second computer, for example a laptop, and choose how much of it that computer gets. The second computer gets a read-only copy: your assistant there is reminded of your rules, a rule can still refuse a wrong step, and search works, but nothing is ever written into the copy. Notes you want to keep are saved on your main computer and show up on the laptop the next time the copy is refreshed. The copy refreshes by itself.
You choose what the copy holds. Name the projects the laptop needs, and say whether it also gets your general work rules (the notes that belong to no project). Every other project, and your personal library, is never copied: it is not hidden, it is not in the copy's file at all. That makes it fit for a company laptop. Choose nothing and you get the whole memory.
What stays on the laptop is a filtered copy with its own chain of checks, so
doctor can verify it like any memory. Two honest limits: a note you did copy
may mention a project you did not copy by name (it is only words there, nothing
breaks), and a note that was ever filed under a project you did not choose stays
out entirely, even if it was later made general.
What you need first (on your main computer)
The copy is made from your backup, so the laptop must be able to read it. This part is the one thing THOR cannot do for you.
Find your backup. On the main computer, run THOR's health check (ask your assistant "Is THOR working?"). Look for the line that starts with
backup:. It says where the last copy went, for examplebackup: last copy went to backup-repo (remote nas: //nas/backups/thor), 3h ago. The place afterremote nas:is your backup's address. If there is no such line, you have not chosen a backup yet: tell your assistant "set up a backup to" followed by a folder on your NAS or a private repository address, then run the health check again.Make sure the laptop can open that place.
A folder on a NAS: on the laptop, open File Explorer (Windows) or your file manager (Linux), type the folder's path in the address bar and press Enter. If it asks for a user name and password, enter them and tick "Remember my credentials". If the folder opens and you can see a folder called
thor2in it (or the backup's own repository files), you are done.A private repository on a website: on the laptop, open a terminal and run
git ls-remote "<the address>" HEAD. If it prints a line starting with a long code, you are done. If it asks you to sign in, sign in. If it says "not found" or "access denied", the laptop's account has no access yet: add it on the website (Settings, then Collaborators), or ask whoever manages that repository.A laptop that belongs to a company: its network or its security software may block the NAS or the website. If the check above fails, ask the company's IT people to allow the laptop to read that one address. Tell them it is read-only.
Keep git on the laptop only when the backup is a repository address. A plain folder on a share needs no git at all.
The one command
Open a terminal inside your project's folder on the laptop (on Windows:
open the folder in File Explorer, click the address bar, type powershell and
press Enter). Then paste ONE of these, after replacing the three parts in
capitals. YOUR-PROJECT is the project's name exactly as the main computer
knows it (the name of its folder, unless you changed it).
Windows, in PowerShell:
$env:THOR_COPY_FROM = "THE-BACKUP-ADDRESS"; $env:THOR_COPY_SCOPES = "YOUR-PROJECT"; $env:THOR_COPY_GLOBAL = "1"; irm https://raw.githubusercontent.com/nworks3d/THOR-for-claude-code/main/install.ps1 | iexLinux:
curl -fsSL https://raw.githubusercontent.com/nworks3d/THOR-for-claude-code/main/install.sh | THOR_COPY_FROM="THE-BACKUP-ADDRESS" THOR_COPY_SCOPES="YOUR-PROJECT" THOR_COPY_GLOBAL=1 shTHE-BACKUP-ADDRESSis the place from step 1 above, for example\\nas\backups\thoror/mnt/nas/thor.Several projects: separate them with commas,
"project-one,project-two".Leave out
THOR_COPY_SCOPESand you get the project of the folder you are in.Leave out
THOR_COPY_GLOBALand the general work rules are not copied.On Windows the
$env:values only live in this window. Close it when you are done.
THOR is already unpacked on this laptop (from an earlier install)? Then run the installer directly instead, with the same choices as options:
& "$HOME\thor2\install.exe" --copy-from "THE-BACKUP-ADDRESS" --scope YOUR-PROJECT --include-global~/.thor2/install --copy-from "THE-BACKUP-ADDRESS" --scope YOUR-PROJECT --include-global(Repeat --scope for more than one project. Add --whole-memory instead of
the choices to copy everything.)
Or copy the whole memory
Only do this on a computer you trust, such as your own second laptop. A full copy holds everything in your memory, including anything personal in it, so it does not belong on a work or company laptop (use the project choice above there).
You do not need to name a project. Open any terminal on the laptop (on Windows:
press the Windows key, type powershell, press Enter), replace
THE-BACKUP-ADDRESS as above, and paste ONE of these:
Windows, in PowerShell:
$env:THOR_COPY_FROM = "THE-BACKUP-ADDRESS"; $env:THOR_COPY_WHOLE = "1"; irm https://raw.githubusercontent.com/nworks3d/THOR-for-claude-code/main/install.ps1 | iexLinux:
curl -fsSL https://raw.githubusercontent.com/nworks3d/THOR-for-claude-code/main/install.sh | THOR_COPY_FROM="THE-BACKUP-ADDRESS" THOR_COPY_WHOLE=1 shTHOR_COPY_WHOLE does the same as --whole-memory. If you also give
THOR_COPY_SCOPES or THOR_COPY_GLOBAL, the full copy wins: nothing is left
out, and the command tells you that those two were not needed. The copy is still
read-only, and it refreshes by itself like any other copy.
It downloads THOR, checks the download, connects THOR to Claude Code, makes the copy, and tells you what you have. This is what you see at the end (your own folders and numbers will differ):
Setting THOR up as a read-only copy of another machine's memory.
= you did not name a project, so this copy holds the project of the folder you ran this in: 'acme-shop' (add --scope <name> to choose another)
+ made the copy from the backup: 3 notes in it, 3 records written (15 ms)
what it holds: project acme-shop, general rules (no project)
project 'acme-shop': 2 notes
general work rules: 1 notes
every other project, and your personal library, were left out of the copy file on purpose
+ connected THOR to Claude Code (4 of 4 connections), so the memory speaks up by itself
+ the small file that keeps your assistant's replies tidy is in place
What you have now
the copy: C:\Users\you\AppData\Local\thor2\thor.db
refreshed: by itself, in the background, at the start of a Claude Code session (at most once an hour)
What is read-only here
- nothing in this copy can be changed from this machine: your assistant reads it, and rules still fire and still refuse
- notes are saved on the main machine, and show up here after the next refresh
- the weekly check runs on the main machine only
Done. ONE THING LEFT FOR YOU: close Claude Code completely and open it again.
Claude Code only learns about THOR when it starts, so until you do this nothing above is active.(The first lines, "Downloading THOR", "Checksum matches." and "Unpacked into
...", come from the download step.) The line ! the project 'x' has no notes in the backup means the project name is spelled differently on the main computer:
run the command again with the right name. It is safe to run the command again
at any time; a second run changes nothing it does not have to.
If it stops
The command either finishes or says plainly that nothing was set up and why:
The copy could not be made, so nothing was set up. Reason: the backup at ... could not be reached- the laptop cannot read the backup. Go back to step 2 of "What you need first". Nothing was left behind; run the same command again when it works.This machine already has a memory of its own ... and it is not a copy, so I will not replace it- THOR was installed here the normal way first and made its own empty memory. If you never saved a note here, rename the file named in the message (do not delete it) and run the command again. If it holds notes you wrote, keep it, and ask for help before you continue.
After the command
Close Claude Code completely and open it again (not just the conversation). The first session start says: "This machine runs a copy of the memory ... It holds only: project acme-shop, general rules (no project). Notes of other projects are not on this machine on purpose."
Check it. Ask your assistant "Is THOR working?", or run this yourself (Windows:
& "$HOME\thor2\doctor.exe" --db "$env:LOCALAPPDATA\thor2\thor.db", Linux:~/.thor2/doctor --db ~/.local/share/thor2/thor.db). The short summary at the top says, among other lines:OK: this is a copy, selection: project acme-shop, general rules (no project), last pull: 5 minutes ago, 3 items. The notes of the projects you did not choose are not missing by mistake, and the check never counts them as a problem. It warns you if the copy has not been refreshed for three days.Optional: tell the main computer where the project lives on the laptop, so rules that look at a file can be checked here. From inside the project's folder run the installer with
--register-root --per-machineand--dbnaming the copy. It writes nothing on the laptop and prints one line; run that line on the main computer.
Change what the copy holds, or refresh it by hand
& "$HOME\thor2\sync.exe" pull --db "$env:LOCALAPPDATA\thor2\thor.db" --scope project-one --scope project-two --include-global~/.thor2/sync pull --db ~/.local/share/thor2/thor.db --scope project-one --scope project-two --include-globalThe choice is remembered, so a later sync pull --db ... with no options
repeats it (this is what the automatic refresh does). A narrower choice removes
what it no longer covers from the copy at the next pull. --whole goes back to
the whole memory. A refresh builds a new copy next to the old one and swaps it
in only when it is complete and checks out; if anything goes wrong (no network,
the NAS is off) the old copy keeps working and the next session start says so
in one line.
One thing to know about a company laptop: if you point the command at a repository folder that already sits on the laptop (a "clone"), that folder holds the complete memory, and the health check says so. Give it the backup's address instead, or a plain folder on the NAS; then the whole memory is only read in passing and nothing of it stays on the laptop.
Not covered here: saving notes from the laptop (they are saved on the main computer; the longer setup in thor2/README.md, "Second machine (laptop)", queues them for you, but that route works on the whole memory), and searching by meaning. Also not yet done: a run on a real second computer. The steps above are covered by tests and by a full run on one machine.
Using it from another assistant
The automated setup above is for Claude Code specifically. Any other assistant that can be pointed at an external tool server can still use THOR, through the container published alongside every release instead of a local build.
A generic client config, the shape most tool-calling assistants expect:
{
"mcpServers": {
"thor": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "thor-data:/data",
"ghcr.io/nworks3d/thor-mcp:2.6.0"
]
}
}
}Run it as a container
docker run -i --rm -v thor-data:/data ghcr.io/nworks3d/thor-mcp:2.6.0On an empty volume, the container creates a memory and seeds it with THOR's
own set of starting notes before it starts answering - the same first
step the setup above takes. Point -v at a folder or named volume that
already holds a thor.db instead (a copy of the one your own build created,
say), and that one is opened untouched. -i keeps input open, which is what
talking to it over stdio needs; drop --rm if you would rather keep the
stopped container around than have it clean up after itself.
Stay in one conversation
The old advice was to start a fresh chat often, because long ones got worse and you lost everything anyway. With THOR that advice is out of date. One long conversation is now the better habit.
When a conversation gets long, the assistant's tools squeeze out the older parts to make room. THOR covers that moment: your standing rules come straight back, and it nudges your assistant to write down anything important that was never saved. Starting a fresh chat is covered too - your rules and your project's background are loaded in from the start.
So stay in one conversation while you are on one piece of work. Start a fresh one on purpose - because you have moved on to something else, or because this one has talked itself into a corner - not because it is getting long.
What the first week actually looks like
Worth knowing before you start, because the beginning is the least impressive part and it is easy to conclude too early that nothing is happening.
Day one, it stops almost nothing. A fresh memory holds 22 pinned starting notes (how to write one that comes back, plus honesty, agent and hygiene habits that hold on any project) and 13 general work rules that arrive right before the step they are about. The part of THOR that can refuse a wrong change only works on notes that carry a proof, and you have not written any yet. So on the first day you get those notes at the start of a conversation and the first-session list described under Getting started, and no refusals, with one exception: on Windows, two of the work rules refuse a call that would flash a console window. That is not a fault; there is simply nothing yet to refuse with.
Your first note will probably be turned down. It asks for two things most people leave out: when the note should come back to you, and what would show it had gone wrong. If the note names a command or a filename, THOR also tries to build a check from your own words; when none holds, the note is stored as a plain note that can inform but not refuse, and that is fine. The refusal names everything that is missing at once and says what to write instead, so the second attempt usually lands. It is strict on purpose - a note nobody can ever prove wrong is a note that quietly stops being true.
The value arrives once you have notes about real places. A note tied to a file, a folder or a command comes back exactly when you touch that thing. A handful of those is worth more than fifty general ones, and after a week or two of writing them down as you go, your assistant stops asking you the same questions.
Then check what you have built with doctor. It tells you plainly how much of
your memory can actually stop a wrong change, how often it has, and which parts
nothing ever re-reads.
If you arrive with a memory you already have
Everything above describes a memory that starts empty. If you are coming from version 1, or from any pile of notes written before proofs existed, the shape is different and worth saying plainly, because the obvious plan does not work.
THOR's weekly review handles a limited batch of old notes each time. That is a brake, not a broom. It keeps the pile from growing while you work, and it was never meant to clear one: a backlog of thousands outlives you at that pace.
The broom is the health check, pointed at the folder your projects actually live in:
doctor --db <your thor.db> --checkouts <the folder holding your projects> --fullThat names every note whose anchor points at nothing, every proof that now comes out false, and every note stored somewhere too crowded to ever be shown. Set aside an afternoon rather than a coffee, and go through it in one sitting. The list is long because the memory is old, not because anything is broken.
Two things make that afternoon safe to be decisive in. Correcting a note keeps the old version, so nothing you wrote is lost and you can always read back what it used to say. And removing one does not delete it either: it stops being handed to anyone, stays findable, and the reason you gave stays attached to it.
Does it work?
Use it for a week and see whether your assistant stops asking you the same things. That is the only test that answers the question you actually have.
THOR was measured head to head against another memory tool for months, and those numbers are not here any more. Not because they were bad - they were good - but because a score measured on someone else's notes tells you about them, not about you. The tool is here. The verdict is yours.
The sixteen tools
What your assistant actually calls, grouped the same way the memory itself is split in two.
Code lane - projects, rules, how to work:
remember- store a new rule, note, report or lookup entryrevise- correct one that already exists, instead of a near-duplicate; taking teeth away from a rule that can already stop a mistake - dropping its check, lowering its severity, or narrowing where it applies - needs a reason too, kept in its historyretract- remove one that turned out wrong (a reason is required; nothing is deleted)resolve- settle two versions of the same fact that diverged apartpin- make an existing note a standing rule, served at every session startunpin- stop it being oneget- show one item whole, by idlookup- search everything - every project, by scope, by key, or by free texthistory- walk one item's whole past, oldest firstmark- judge whether something you were served actually helpedstatus- how much of the memory can actually stop a mistake, and how much has gone stalesearch_code- search the project's own indexed source codewhere_used- find every place one function, struct or variable is defined and usedoutline- see everything one file declares, in line order
Library lane - recipes, books, training, expenses, kept apart from the code lane:
library- read a shelf's index, one entry, or search across shelvesshelve- file a new entry, correct one that already exists, or retire one
Remove THOR completely
Everything the install put on your computer is listed here, with how to undo each piece. Nothing is hidden anywhere else. Your own projects and their code are never changed, apart from the one small file in step 9. Your assistant can do all of this for you if you ask; these are the steps in plain words.
Close Claude Code completely. It reads its settings once, when it opens.
Keep a copy of your notes first, if you might want them again. Copy the memory folder from step 7 somewhere safe. Deleting it in step 7 cannot be undone.
Take the four THOR lines out of Claude Code's settings. Open
settings.jsonin the.claudefolder inside your home folder. Underhooks, delete the entries forSessionStart,PreToolUse,UserPromptSubmitandStopwhose command names THOR'sserveprogram and ends inhook. If you chose a backup, there is one moreSessionStartentry: the one whose command runs thebackupprogram (backup.exeon Windows) with--dbnaming your memory and--reponaming thebackup-repofolder (or the folder you chose). Delete that one as well. Leave every other entry alone.Take THOR out of the tool list. Open
.claude.jsonin your home folder and delete the entry calledthorundermcpServers.Delete the
/thor-evalcommand. It is the filethor-eval.mdin thecommandsfolder inside the.claudefolder in your home folder.Undo THOR's git setting, only if it is THOR's. Run
git config --global --get core.hooksPath. If the folder it prints ends inthor2/githooks(orthor2\githooks), rungit config --global --unset core.hooksPath. If it prints some other folder, or nothing, leave it alone: it is not THOR's.Delete the memory folder. On Windows that is
%LOCALAPPDATA%\thor2, on Linux~/.local/share/thor2(the install printed it on itsmemory:line). It holds your notes, the small files beside them (the reply rules, the modes, the weekly-check clock, and the recording switch, which lives inthor-mode.json), the record of real calls (real-calls.jsonlandreal-replies.jsonl), THOR's reading of your code, its git helpers, and thebackup-repofolder if you chose a local backup.Delete the programs. On Windows that is
thor2in your home folder, on Linux~/.thor2.Delete the hidden
.thor-projectfile in each folder where you ran the install with--topicor--project. It is the only thing THOR ever put inside one of your own folders.Open Claude Code again. A new conversation should start without any THOR block, and
/thor-evalshould be gone. Thesettings.json.bakand.claude.json.bakcopies hold your two files as they were just before THOR first changed them (a later run never replaces them). They can be deleted; do not restore them over the current files, they predate anything else you changed since.
Documentation
page | what it answers |
for your AI assistant: how to set THOR up | |
the version 2 program: how it is built and what each part does | |
the standard version 2 is judged against, and the test enforcing each rule | |
how a note proves itself, in detail | |
changing THOR: the bar for a pull request | |
what changed in each release: the section every release opens with |
Thanks
MakerViking - for the inspiration and the great fight. This project would not exist without the spark, and it would not be half as good without someone worth pushing against. Skål!
mimir (MakerViking/mimir) - the reason THOR exists at all. In the old Norse stories, Mimir guards the well of knowledge; here it set the bar THOR had to clear, and for a long stretch it cleared plenty of its own. Every early comparison in this project was against mimir, wins and losses both counted honestly, because a rival that good deserves honest numbers (they are no longer published here; see "Does it work?").
Ideas borrowed, both ways. Two things THOR does came from mimir's own work and were rebuilt here in THOR's own way, and mimir in turn credits THOR for reading code into memory and for checking memory on every message - exactly the kind of exchange open source is for. Thanks, MakerViking.
Support this project
THOR is built by N-Works 3D. If it has earned its keep - saved you an explanation, caught a mistake before it cost you, or just meant you did not have to start from scratch - there are two easy ways to help keep it going:
Buy me a Ko-fi - a one-off, whenever you feel like it.
Become a YouTube member - monthly, if you want to keep it going.
No pressure and no paywall - it all stays open either way. Skål, and thanks for reading this far.
Contributing
Bug reports and pull requests welcome. THOR is a memory your assistant is supposed to trust, so the bar is being right rather than having more features. The checklist is in CONTRIBUTING.md.
License
GPLv3.
Available Tools
16 toolsgetARead-onlyIdempotent
Code lane: shows one item whole, by id. Use lookup instead when the id is not already known. Read-only. Reports a plain, honest error - never a blank reply that could look like success - when the id is unknown, when the item is DIVERGED (more than one current head; read history, then use resolve), or when its stored body will not parse. With fired: true it also lists where the item fired recently in this session (when, and the command or file) - what a verdict is judged by. Replies with the item as formatted JSON (then the firings, when asked), or the error text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The id to show. | |
| fired | No | true also shows where the item fired recently in THIS session (newest first, at most 10 firings): when, and the command or file it fired on. What an evaluation judges a verdict by. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent safety, but the description goes further and enumerates the exact failure modes (unknown id, DIVERGED state, unparseable stored body) and guarantees a plain error rather than a blank reply that could mask failure. It also explains what the 'fired' flag produces and why it matters.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and the routing rule, and every sentence carries information. It is dense with parentheticals (DIVERGED explanation, fired explanation) which slightly slows parsing but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, and the description compensates by describing the return payload (item as formatted JSON, then firings, or the error text). Combined with the error-mode disclosure, an agent has everything needed to call and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both 'id' and 'fired' are already documented in the schema, including the description of what fired returns. The description largely restates the fired semantics and adds only the output ordering ('then the firings, when asked'), so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('shows one item whole, by id') and immediately distinguishes itself from the sibling 'lookup' by id-knownness. An agent can pick between get and lookup without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing rules: use 'lookup' when the id is not already known, and read 'history' then 'resolve' when the item is DIVERGED. Both the alternative tool and the selecting condition are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
historyARead-onlyIdempotent
Code lane: walks one item's whole life by id, oldest first - every declare, revise and retraction, each with its sequence number, revision hash and author. Use get instead for only the current version. Read-only; nothing is ever deleted from the log, so this still answers for a retracted item - read it before you revise or retract again. Replies with one line per revision, or the plain 'no history for id X' for an unknown id (not an error).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The id whose whole life to walk. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnlyHint/idempotentHint/destructiveHint, but the description adds valuable behavior beyond them: nothing is ever deleted from the log, it still answers for retracted items, output is one line per revision ordered oldest-first, and an unknown id returns plain text 'no history for id X' rather than an error. The non-error response for unknown ids is exactly the kind of edge-case behavior an agent needs to know. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four dense sentences and every one earns its place: core function, sibling routing, persistence/read-only caveat, and output format. Slightly cryptic 'Code lane:' prefix and slightly metaphorical 'walks one item's whole life' phrasing cost a point, but nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-required-param read-only tool with no output schema, the description fully compensates: it describes the reply format, ordering, content, unknown-id behavior, and mutation-safety context. There is no meaningful gap an agent would need to resolve elsewhere.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% — the id parameter already has a description, so baseline is 3. The description adds meaning beyond the schema by explaining what happens with an unknown id (a plain string reply, not an error), which affects how the agent interp rets the response for that parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb + resource: 'walks one item's whole life by id, oldest first' with concrete content (every declare, revise, retraction; sequence number, revision hash, author). It clearly distinguishes itself from the sibling 'get' by explicitly saying get returns only the current version, so an agent can tell them apart instantly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing guidance: 'Use get instead for only the current version' names the alternative and the condition selecting it. It also provides a concrete use case — 'read it before you revise or retract again' — telling the agent when to call this tool in a workflow.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
libraryARead-onlyIdempotent
Library lane: reads the owner's everyday knowledge - recipes, books, a training log, expenses - kept apart from the code lane; nothing here is ever injected, ranked against a rule, or counted toward any cap. Use shelve to write instead. No arguments lists the shelves and how much each holds; shelf lists that shelf's live entries (label narrows it); id returns one entry whole, retired or not, marked '(retired)' if so; query searches live entries, optionally within one shelf. Read-only. A search never answers 'nothing' - it hands back the shelf, or the shelf list, to read instead, since the words asked with are rarely the words written. Replies with the requested listing or entry, or that fallback.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | One entry's number, as the listings show it. Returns it whole. | |
| label | No | Narrow one shelf to the entries carrying this label. Labels are how a big shelf stays usable - there are never sub-shelves. | |
| query | No | Free text. Searched over titles, bodies and labels, in four steps that end in a list to read rather than in an empty answer. | |
| shelf | No | One shelf, by name. On its own it lists that shelf, one line per entry. With `query` it searches inside that shelf only. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool read-only and idempotent, but the description adds valuable non-obvious behaviors: searches never return 'nothing' but fall back to a shelf or shelf list, retired entries are marked, and nothing in the library is injected, ranked, or capped. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense and front-loaded, opening with purpose and routing before detailing modes. It is long, but every sentence earns its place for a multi-mode tool with no output schema to fall back on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all four parameter modes, read-only behavior, the write alternative, the fallback search behavior, and the expected reply shape. Despite having no output schema, an agent has enough context to call the tool correctly in every mode.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds mode-level semantics beyond individual property docs: no arguments lists shelves, shelf plus label narrows live entries, id returns one whole entry, and query can be scoped to one shelf. This connects the parameters to invocation patterns the schema alone does not spell out.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pairing ('reads the owner's everyday knowledge') and clearly separates the library lane from the code lane. It names shelve as the write counterpart and enumerates the distinct read modes (no args, shelf, id, query), so an agent can tell this tool apart from siblings without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use shelve to write instead' is an explicit when-not-to-use instruction with a named alternative, and the 'kept apart from the code lane' plus 'never injected, ranked against a rule, or counted toward any cap' gives clear context for when library is the right read tool. This is strong routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookupARead-onlyIdempotent
Code lane: searches THOR's memory - every project, archive kinds (Report, Chunk) included - never scoped to only the current project. Call this before remember, so an existing near-duplicate becomes a revise instead. No arguments returns the catalogue of scopes; scope alone lists everything filed there; scope with query narrows a search to it; query alone searches everywhere; key answers only a Lookup item's own exact key (query, scope and kind are then ignored); kind narrows a search to rule, orientation, report or chunk - several at once with a comma, and 'fires' as shorthand for every kind that can fire at a moment, which is what you want when the fact has to steer an action (case-insensitive, an obvious plural such as 'rules' accepted) - without it, Report hits tend to dominate a plain search since their own text runs long, and asking for kind lookup is refused rather than silently answered empty, since a Lookup register only ever answers to its own key. Read-only, and never an injection surface - nothing here reaches you unprompted. Replies with up to 25 matching lines (id, kind, text) and how many more exist, the catalogue, or a plain 'no matches'.
| Name | Required | Description | Default |
|---|---|---|---|
| key | No | An exact Lookup key. When given, this is the ONLY parameter used - `query`, `scope` and `kind` are all ignored - and only a real Lookup item can ever answer it. | |
| kind | No | Narrow a search to one kind: rule, orientation, report or chunk - case-insensitive, and an obvious plural ("rules") is accepted too. Applied AFTER the search has already run and AFTER `scope`, so it only ever removes hits, never adds or reorders any. `lookup` (the Lookup kind) is refused outright rather than silently answered empty - see `key` above for the door that actually answers one. | |
| query | No | Free-text search over every live item's text and tags, any project, archive kinds (Report/Chunk) included - never a Lookup item (those answer only to their own `key`, see below). | |
| scope | No | One scope, by name, as the catalogue lists it. On its own it opens that scope: every item filed under it, one line each, complete. Together with `query` it narrows that search to this scope alone. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the 25-line result cap with a count of remaining matches, the 'no matches' outcome, the catalogue reply, that kind filtering runs after the search and only ever removes hits, and that a 'lookup' kind request is refused rather than silently empty. It also asserts it is never an injection surface and nothing reaches the agent unprompted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the remember-precedence rule are front-loaded, but the rest is a single sprawling run-on sentence dense with em-dashes and parentheticals that is hard to parse in one pass. The content earns its place, yet the packaging is not concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully covers the return shapes (matching lines of id/kind/text, a remaining-count, the catalogue, or 'no matches'), the parameter interactions, and the read-only safety profile. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: the precedence of key over query/scope/kind, the four search modes, comma-separated multi-kind selection, the 'fires' shorthand, and case-insensitive plural acceptance. These are semantic details the schema does not carry.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('searches THOR's memory') with an explicit scope statement (every project, archive kinds included, never scoped to the current project) and names the sibling it precedes ('Call this before remember'). It stops short of distinguishing itself from other retrieval siblings like get, resolve or where_used, and the 'Code lane' prefix is unexplained jargon.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to call it ('Call this before remember, so an existing near-duplicate becomes a revise instead') and routes to the alternative operation (revise) based on the result. It also enumerates every argument combination and what each does, so an agent knows exactly which invocation shape matches its intent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
markA
Code lane: judges an item you were served or looked up. Default records that it HELPED, which clears noise recorded before it (a later noise mark still counts - the newest verdict wins). Pass noise:true for the opposite; two noise marks since the last useful one (or since the last change to its text, check or bindings) retire the item from the injection surfaces, though it stays fully findable via lookup; a rule whose check can refuse is never retired this way. A second call THIS SESSION for the same id with the same verdict writes nothing and says so, unless the item fired 40 more times since, in which case it is owed again and written; a different verdict is written and the earlier one is named in the reply. On a replica this queues instead of writing ('queued for the main machine' is not an error). Refused when the item is not live (retracted or archived) - there is nothing to judge. Also refused, with nothing written, when the item is pinned (Always-bound): the owner already answered by pinning it, so a verdict changes nothing - unpin it first if it should be judged instead. Replies with the verdict recorded and its event sequence, or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The id of the item being judged. | |
| noise | No | Set true to record the OPPOSITE: this item did not belong where it fired. Two noise judgements, with no mark of usefulness, retire it from the injection surfaces; it stays fully findable via lookup. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover only the generic safety profile (readOnlyHint=false, idempotentHint=false, destructiveHint=false), and the description goes far beyond them: retirement after two noise marks, the exception for check-refusable rules, the 40-refiring re-write rule, replica queueing, and two distinct refusal conditions. The idempotentHint=false is consistent with the described 'owed again after 40 firings' exception rather than contradicted.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the default behavior and the noise override before the edge cases, and every sentence carries operational rules (retirement, dedup, queueing, refusals) that an agent needs. It is long and parenthetical-heavy, so it is efficient rather than wasteful, but readability suffers slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by stating the reply shape ('the verdict recorded and its event sequence, or the refusal text'). Retirement, dedup, replica, and refusal semantics are all covered, so nothing an agent needs to invoke correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema's own text for 'noise' is nearly a verbatim restatement of the description's explanation, so the description adds little new parameter meaning. The retirement semantics it does add are behavioral rather than argument-level, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb and object ('judges an item you were served or looked up') and pins the default meaning (records that it HELPED), which rescues the opaque name 'mark'. It also distinguishes itself from siblings by noting the item 'stays fully findable via lookup' and by its interaction with pin. The dense, rule-heavy phrasing keeps it a step short of instantly scannable, but the core purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to pass noise:true versus leave the default, when a duplicate verdict is written versus suppressed, when the tool is refused (not live, pinned), and even routes the agent to an alternative action ('unpin it first if it should be judged instead'). Replica behavior ('queues instead of writing') is called out as non-error. This is close to exhaustive when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
outlineARead-onlyIdempotent
Code lane: lists what one file declares, in line order - its shape without reading the whole thing. Use where_used instead to find every caller of one symbol. Takes a repository-relative path. Read-only. States plainly when the index has never seen that path, which differs from 'this file defines nothing' - a file added since the last index build falls in the first case. Replies with one line per definition (name and line number), or the plain 'not indexed' or 'defines nothing' text.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Repository-relative path, exactly as the index stores it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint, idempotentHint, destructiveHint), the description discloses important behavioral nuances: the difference between 'not indexed' and 'defines nothing,' including the scenario of a file added since the last index build. It also describes the reply format in detail (one line per definition with name and line number), which is not captured by any structured field.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place: purpose, alternative tool, path requirement, read-only mention, output format, and edge-case behavior. The description is front-loaded with the primary purpose and remains free of filler, despite the slight stylistic oddity of 'Code lane:'.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a single parameter, no output schema, and thorough annotations, this description covers everything an agent needs: what it does, how to invoke it, what the response looks like, and a critical edge case (not-indexed vs defines-nothing). The mention of the sibling tool where_used further completes the contextual picture.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the only parameter (path) is documented as 'Repository-relative path, exactly as the index stores it.' The description repeats 'repository-relative path' but adds no meaning beyond the schema. Since the schema already carries the full parameter documentation, the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'lists what one file declares, in line order' and 'its shape without reading the whole thing.' It clearly distinguishes itself from the sibling tool where_used by naming which tool to use for an alternative goal. This leaves no ambiguity about what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly provides a routing condition: 'Use where_used instead to find every caller of one symbol.' It also clarifies the intended context of 'one file' and the repository-relative path requirement, making it clear when this tool is appropriate and when a sibling is better.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
pinAIdempotent
Code lane: adds the Always binding to an existing item, so it is served in full at every session start; every other binding and field stays untouched. A pinned item owes no verdict from that point on - mark refuses it and points back here to unpin. Use revise instead when anything besides the binding needs to change. Idempotent - pinning an already-pinned item changes nothing and is not an error. On a replica this queues instead of writing ('queued for the main machine' is not an error). Refused, loudly, when the item's kind may carry no binding at all (a Report or Chunk). Replies 'pinned' with the event sequence, 'already pinned', or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The id to pin (add the Always binding to it). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover safety (readOnlyHint=false, idempotentHint=true, destructiveHint=false), but the description adds behavior annotations cannot express: replica writes queue instead of failing, refusals are loud for binding-incapable kinds, and pinned items are exempt from mark's verdict. Return values are also disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and effect scope, then conditions and return values. Every sentence carries a distinct fact, though the clause density with dashes and parentheticals is heavier than a one-parameter tool strictly needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, yet the description enumerates the three possible responses ('pinned' with event sequence, 'already pinned', or refusal text) and covers the replica/queue and kind-refusal edge cases. An agent has everything needed to call and interpret this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real constraint semantics beyond 'The id to pin': the id must reference an existing item, and ids whose kind cannot bear a binding are refused. That is meaningful eligibility information the schema does not carry.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb+resource: 'adds the Always binding to an existing item', and immediately scopes the effect ('every other binding and field stays untouched'). It differentiates from siblings by naming mark (which refuses pinned items), unpin (the inverse), and revise (the alternative for non-binding changes).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use and when-not-to-use: 'Use revise instead when anything besides the binding needs to change', plus the exact refusal condition (kinds that may carry no binding, e.g. Report or Chunk). It also routes the agent to unpin as the undo path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rememberA
Code lane: declares a NEW item (Rule, Orientation, Report, Lookup or Chunk) through the write gate. Call lookup first so this corrects an existing item instead of storing a near-duplicate; for anything about the owner's own life use shelve, never this. On a replica this queues instead of writing ('queued for the main machine' is not an error). Refuses, with the exact reason and the fix, when a Rule/Orientation has no binding (or, if costly or irreversible, only a project name, which reaches no tool call), no falsifier, or exceeds 300 characters, when a Report/Chunk names no project scope, or when the text or falsifier carries a real secret token (never echoed back; store where it lives, never the value; no override); nothing is written on a refusal. check_kind/check_path/check_literal(s) optionally attach a machine-runnable proof alongside the falsifier - see server instructions for the six check kinds. Every Rule/Orientation is TRIED as it is written: a check that bites is stored on the rule track, a rule with no working tooth is stored as a note (no check), and a tooth THOR builds from the rule's own words that bites refuses the write, naming the exact check to hang - the reply's 'teeth:' note says which. Replies with the stored id, kind and event sequence, or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Caller-chosen id, kept forever. Pick something short, stable and grep-able (e.g. "no-force-push-main"), not a sentence. | |
| key | No | Required for a Lookup: the exact key a future `lookup` call names to get this item back. Meaningless for the other four kinds. | |
| kind | Yes | One of: rule, orientation, report, lookup, chunk. | |
| tags | No | ||
| text | Yes | The fact itself. A Rule/Orientation is refused past 300 characters - move reasoning into a Report instead of lengthening this. | |
| always | No | Bind this item to the pinned Always layer (served in full at every session start). Only a Rule/Orientation may set this. | |
| because | No | REQUIRED with legitimate_calls, may_change or accept_refusing, and never needed otherwise: one sentence of at least 20 characters saying WHY the named span may change, or why the call is legitimate, while the rule stays true. It is kept in this item's history and shown to the owner at the next evaluation. First try to hang a check on the literal that IS the rule's subject; dispute only an incidental span. | |
| expires | No | ISO-8601 date. Only a Report may carry this - a Rule, Orientation, Lookup or Chunk with an expiry is refused (they last until revised). | |
| moments | No | Action names this item fires on (repeatable), e.g. ["push"]. Only a Rule/Orientation may bind to a moment. The ones that actually fire are derived from a real command or file path (publish, commit, push, deploy and the rest - see intent::from_command/from_path), plus remember itself. answer and claim_done are refused on a NEW binding: nothing produces either yet, so a rule bound only to one would store cleanly and never fire. | |
| project | No | Project this item belongs to. Omit for a global, cross-project item. | |
| targets | No | Exact targets this item fires on (repeatable). Only a Rule/Orientation may bind to a target; the value must be the real path/command/etc, never a glob and never a bare role name. | |
| severity | No | One of: irreversible, costly, house_style. Meaningless (and refused as a binding target would be) on a Report/Lookup/Chunk. | |
| falsifier | No | What observation would prove this fact wrong, one sentence. Required for a Rule or Orientation - they never expire, so this is the only thing that ever names when one has gone stale. | |
| check_kind | No | One of: path_exists, contains, absent, absent_all, forbidden, requires. An optional machine-runnable check, alongside (never instead of) falsifier - only a Rule/Orientation may carry one, and only while it currently HOLDS can it block a write. Every kind except forbidden needs check_path; path_exists refuses check_literal/check_literals; contains/absent/requires need one of them; absent_all/forbidden need check_literals. requires catches something FORGOTTEN rather than written - see server instructions. Omit all four check_* fields for no check at all. | |
| check_path | No | The exact file this check inspects, relative to the checker's root - or, for contains/absent/absent_all only, a DIRECTORY: every regular file directly inside it, never one in a subdirectory. Use the directory form when one fact spans more than one file there (e.g. a setting duplicated across two config files). Required with every check_kind except forbidden, which carries no path at all and is refused if one is given. | |
| may_change | No | ONLY after a refusal said THOR derived a contains check from this rule's text and a file: the span you name as one that MAY CHANGE in that file - e.g. ["version"] for a rule that names the version line of package.json. It must be exactly the derived check's literal. Then the rule is stored as a note by dispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise. | |
| check_literal | No | The exact literal a "contains" or "absent" check_kind looks for. Refused together with "path_exists", or together with check_literals; required with "contains"/"absent". | |
| check_literals | No | A SET of literals to forbid together, for check_kind absent_all (in one file) or forbidden (everywhere, no file). One rule forbidding several things at once (e.g. every banned punctuation character) is ONE item with a set here, never several near-identical items each forbidding one literal. Each literal is its own array entry, never joined into one delimited string. Refused together with check_literal, refused empty, and refused with any other check_kind except requires, which takes the trigger first - one of this item's own command bindings, or a specific literal inside the bound command such as "-p my-dev" in an ssh call - then every answer that satisfies it. | |
| accept_refusing | No | ONLY after a refusal said your check would refuse most of the real calls it reaches: one of the calls it listed, named because refusing it IS the intent - e.g. ["git push origin main"] for a "never push this repository until the owner says so" ban. The rule stays on the rule track, and doctor lists every rule kept this way. Needs `because`. Otherwise narrow the check instead. | |
| legitimate_calls | No | ONLY after a refusal said THOR built a tooth from this rule's own text and it bites: a real, whole call you name as LEGITIMATE although that tooth refuses it - e.g. ["git push --force-with-lease origin main"] for a rule whose text names `--force`. It must reach the tooth's command, be refused by it, differ from the forbidden form THOR built itself, and carry something beyond the command and the literal. Then the rule is stored as a note by dispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise. | |
| new_collection_named_by_owner | No | THE OWNER JUST NAMED A NEW COLLECTION - repeat that name here exactly as he gave it, and it will be opened. The only way an unopened collection can be written to: nothing existing fit, you showed him the refusal (it lists both lanes), you asked, and he answered with a name. Never fill this in on your own judgement or to get past a refusal. Must match the project (or key) on this same call, or the write is refused anyway. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Far exceeds the annotations: it discloses the refusal conditions with the exact fix, that nothing is written on refusal, that secrets are never echoed, that checks are TRIED at write time with rule-vs-note outcomes, and the reply shape. The annotations only cover the safety profile; the description carries the real behavioral burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded ('Code lane: declares a NEW item...') and the return/refusal behavior is placed last. The middle preconditions are dense and clause-heavy, but for a 21-parameter gated write tool most sentences carry non-redundant information rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 21 parameters, no output schema, and only partial annotation coverage, the description fills the gaps: it explains refusal semantics, the replica queue path, check-kind behavior, and the reply ('stored id, kind and event sequence, or the refusal text'). Nothing critical is left undocumented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 95%, so the baseline is 3 and the schema already documents most fields. The description adds cross-parameter integration semantics (check_kind/check_path/check_literal(s) attach a proof alongside falsifier, refusal logic pairing falsifier and binding), which goes beyond isolated field text.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('declares a NEW item (Rule, Orientation, Report, Lookup or Chunk) through the write gate') and the 'NEW' qualifier is a real distinguisher. It explicitly routes to siblings: call lookup first to correct, and use shelve for the owner's own life, never this.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use (call lookup first to avoid near-duplicates), when-not (owner's-life facts go to shelve), and the consequences of the replica path ('queues instead of writing ... is not an error'). Alternatives and exclusions are named, not inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolveADestructiveIdempotent
Code lane: settles an item with more than one current head - what get reports as DIVERGED, from two machines revising the same fact apart. Read history first; never guess which head is real. Name the surviving revision hash in keep and every other current head in discard - leaving one out fails rather than silently discarding it. On a replica this queues instead of writing ('queued for the main machine' is not an error). The head set is rechecked under the write lock, so a head that appears mid-decision fails the call loudly instead of being dropped. Replies 'resolved onto (event seq N)', or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The diverged id. | |
| keep | Yes | The revision hash that survives. | |
| discard | Yes | Every other current head, in full. Leaving one out fails rather than silently discarding it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this destructive, idempotent, and non-open-world, and the description goes well beyond them: replica runs queue rather than write ('queued for the main machine' is not an error), the head set is rechecked under the write lock so a mid-decision head fails loudly, and the exact success reply format is given. No contradiction with the destructiveHint=true annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the 'Code lane: settles...' purpose, then the procedure, then edge cases and the reply format — a logical order with no filler sentences. It is dense and slightly jargon-heavy ('Code lane', 'event seq N'), but every sentence carries distinct operational information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by specifying the return string ('resolved <id> onto <keep> (event seq N)') and the refusal text. Combined with replica-queueing and lock-recheck semantics, an agent has everything needed to call this safely and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, and the description's parameter content ('surviving revision hash in keep', 'every other current head in discard', 'leaving one out fails') largely restates what the schema already says verbatim. It adds the procedural hint to consult history first, but little syntax or format detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — settles an item with more than one current head — and names the exact condition it targets ('what get reports as DIVERGED'). This distinguishes it cleanly from siblings like get (reads state), revise (moves a head), and history (which it defers to), so an agent can route without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly gates usage on get reporting DIVERGED, commands 'Read history first; never guess which head is real,' and warns that omitting a head fails rather than silently discarding. It names the prerequisite tool (history), the trigger condition, and the exclusion behavior — nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
retractADestructiveIdempotent
Code lane: removes an item that is simply WRONG or no longer applies - it stops being live everywhere (session start, the moment of action, lookup), but nothing is deleted, and history still walks it. Use revise instead when the item merely changed. A reason is required; a blank one is refused. On a replica this queues instead of writing ('queued for the main machine' is not an error). Bringing the fact back later is a fresh remember, never a revise of the tombstone. Replies 'retracted () (event seq N)', or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The id to retract. | |
| reason | Yes | Why it is wrong or no longer applies. Required, and a blank one is refused: without it nobody can later tell a decision from an accident. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: soft-delete mechanics ('nothing is deleted, and history still walks it'), the scope of suppression ('session start, the moment of action, lookup'), replica behavior ('on a replica this queues instead of writing') with an explicit non-error clarification, and the refusal path. The 'nothing is deleted' wording is a mechanistic nuance of destructiveHint=true rather than a contradiction, since liveness is irreversibly removed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the lane and the core distinction before edge cases, and every clause carries information about behavior, error handling, or return text. Slightly dense with stacked parentheticals ('queued for the main machine', the reply template), which costs a little readability against a five.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the return contract ('retracted <id> (<reason>) (event seq N)', or the refusal text), covers the distributed-replica edge case, and defines the retraction semantics end to end. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description lifts it by restating the hard rejection condition operationally ('A reason is required; a blank one is refused'), which tells the agent a blank value produces a refusal rather than a silent success. It adds no new format or syntax detail for 'id' beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('removes an item that is simply WRONG or no longer applies') and immediately scopes it against the closest sibling by naming the alternative ('Use revise instead when the item merely changed'). An agent can distinguish retract from revise, mark, and shelve without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use ('simply WRONG or no longer applies'), explicit when-not and alternative ('Use revise instead when the item merely changed'), and a further rule for a related case ('Bringing the fact back later is a fresh remember, never a revise of the tombstone'). Preconditions (reason required, blank refused) are stated up front.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reviseA
Code lane: corrects an EXISTING item by id through the same write gate as remember; a field left unmentioned keeps its current value, and none may silently vanish - clear one with clear_severity/clear_project/clear_expires/clear_key/clear_falsifier/clear_check; an empty string on the field is the harness-only equivalent, and a flag plus a real value for that field is refused. Weakening a checked rule (its check, severity, a binding, or scope) needs because: one sentence, kept in history. On a replica this queues instead of writing ('queued for the main machine' is not an error). Prefer this over remember for an existing item that merely changed; retract, with its own reason, is for one that is simply wrong. Refuses, with the exact reason, on remember's grounds (a secret token newly written into the text or falsifier included), plus a dropped field or an unexplained weakening. A revise that changes its text, anchors, check, project or severity is tried again (a revise naming only the id tries a rule no trial has decided yet); one that changes only tags, falsifier, expires or key keeps its verdict. Replies with the revised id and event sequence, or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The id of the existing item to correct. | |
| key | No | Omit to keep the current key; pass "" to clear it (see `clear_key` below for the spelling that reaches this server from an assistant). | |
| tags | No | Replaces the whole tag list. Omit to keep the current tags; pass an empty list to clear them on purpose - the same omit-keeps/empty-clears convention as severity/project/expires/key/falsifier, spelled with a list: omitted means unmentioned, an empty array means deliberately cleared, a real list replaces the whole set. | |
| text | No | New text, replacing the whole body. Omit to keep the current text unchanged. For a SMALL correction to a long item, prefer `append` or `replace_from`/`replace_to` below - retyping a 290-character rule to fix one word is friction on exactly the maintenance this memory needs most, and it is the reason corrections get skipped. | |
| always | No | Replaces whether this item is bound Always - see `moments`' own note. | |
| append | No | Add this to the END of the current text, with one space between. Refused together with `text` (say what the body is, or say what to add to it, never both). The result still goes through the whole gate, so a 300-character limit is enforced on what comes out, not on what you typed. | |
| because | No | Required when this revise WEAKENS a Rule/Orientation: clearing or changing its check, lowering or clearing severity, removing a binding (a command, path or dir anchor on any rule; any binding on one that carries a check or is marked expensive), narrowing scope from global to one project, taking a fragment THOR builds teeth from (a backtick span, a quoted call, a flag or a path) out of its text, or moving it off the rule track. Say in one sentence why - it is written into this item's own history (see `history`), the same way retract's reason is, so the owner can read later why a rule lost its teeth. Blank or missing on one of those is refused outright. Accepted and stored on any other revise too, but never required for one - except that a revise naming legitimate_calls, may_change or accept_refusing always needs it: at least 20 characters saying why the span may change or the call is legitimate while the rule stays true. | |
| expires | No | Omit to keep the current expiry; pass "" to clear it (see `clear_expires` below for the spelling that reaches this server from an assistant). | |
| moments | No | Replaces the moment bindings. Give this, `targets`, and/or `always` TOGETHER to replace the WHOLE binding list in one call - when none of the three are given, the existing bindings are kept untouched. See RememberArgs' own note on which moments actually fire - a NEW answer/ claim_done binding is refused here too, though one the item already carried stays correctable. | |
| project | No | Omit to keep the current project; pass "" to make it global (see `clear_project` below for the spelling that reaches this server from an assistant). | |
| targets | No | Replaces the target bindings - see `moments`' own note on how the three binding fields combine. | |
| severity | No | One of: irreversible, costly, house_style. Omit to keep the current value; pass "" to clear it (see `clear_severity` below for the spelling of a clear that actually reaches this server from an assistant). | |
| clear_key | No | Set true to clear key - same fix and convention as `clear_severity` above. Refused, naming the conflict, if `key` is also given here as a real, non-empty value. | |
| falsifier | No | Omit to keep the current falsifier; pass "" to clear it (a Rule or Orientation left with none is refused, same as at creation - see `clear_falsifier` below for the spelling that reaches this server from an assistant). | |
| check_kind | No | One of: path_exists, contains, absent, absent_all, forbidden, requires. Omit all four check_* fields to keep the current check untouched; pass check_kind as "" to clear it (refused if check_path/check_literal/check_literals is also given) - see `clear_check` below for the spelling that reaches this server from an assistant. Give check_kind plus whichever of check_path/check_literal/check_literals the kind takes, together, to replace the check wholesale - see RememberArgs' own check_kind note for what each kind needs and which to prefer. | |
| check_path | No | See check_kind's own note on the omit/clear/replace convention, and RememberArgs' own note on check_path for the directory shape contains/absent/absent_all also accept (every regular file DIRECTLY inside it, never a subdirectory). Refused outright if check_kind is "forbidden" - that kind carries no path at all. | |
| may_change | No | ONLY after a refusal said THOR derived a contains check from this rule's text and a file: the span you name as one that MAY CHANGE in that file - e.g. ["version"] for a rule that names the version line of package.json. It must be exactly the derived check's literal. Then the rule is stored as a note by dispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise. | |
| replace_to | No | What `replace_from` becomes. Pass an empty string to delete the substring. | |
| clear_check | No | Set true to clear the check - the same clear `check_kind: ""` above documents, same fix and convention as `clear_severity`'s own doc comment (see there for the defect and the evidence). Refused, naming the conflict, together with a non-empty check_kind, or with check_path/check_literal/check_literals - clearing takes none of the four; give a real check_kind (plus whatever it needs) to replace the check instead. | |
| replace_from | No | Replace the FIRST occurrence of this substring in the current text with `replace_to`. Refused unless `replace_to` is given too, refused together with `text`, and refused when the substring is not actually in the current text - a silent no-op would report success while changing nothing. | |
| check_literal | No | See check_kind's own note on the omit/clear/replace convention. | |
| clear_expires | No | Set true to clear expires - same fix and convention as `clear_severity` above. Refused, naming the conflict, if `expires` is also given here as a real, non-empty value. | |
| clear_project | No | Set true to clear project (make it global) - same fix and convention as `clear_severity` above. Refused, naming the conflict, if `project` is also given here as a real, non-empty value. | |
| check_literals | No | The set form of check_literal, for check_kind absent_all or forbidden - see RememberArgs' own note on why this is a repeatable field rather than a delimited string. Same omit/clear/replace convention as check_kind: an empty list here reads the same as omitting it, since a list has no separate way to say 'given, but deliberately empty'. | |
| clear_severity | No | Set true to clear severity - the same clear `severity: ""` above documents, run through the identical code path, never a second mechanism. THE DEFECT THIS FIXES, bitten twice (2026-09-09 and 2026-09-11): an assistant's tool-call layer drops an empty-string argument before it ever reaches this server (the field arrives as though it was never mentioned, or the call itself is rejected before that), and a literal '""' arrives as two quote characters, not an empty value - so the one documented way to clear a field was never actually reachable from an assistant. Both sessions gave up, retracted the rule and stored a fresh one with no check, silently losing its history. This flag is the one that works from an assistant; the empty string above still works for a caller that can send one (the JSON-RPC harness). Refused, naming the conflict, if `severity` is ALSO given here as a real, non-empty value - say one or the other, never both. | |
| accept_refusing | No | ONLY after a refusal said your check would refuse most of the real calls it reaches: one of the calls it listed, named because refusing it IS the intent - e.g. ["git push origin main"] for a "never push this repository until the owner says so" ban. The rule stays on the rule track, and doctor lists every rule kept this way. Needs `because`. Otherwise narrow the check instead. | |
| clear_falsifier | No | Set true to clear falsifier - same fix and convention as `clear_severity` above (still refused outright on a Rule/Orientation, same as `falsifier: ""` above, by the same ground that guards creation). Refused, naming the conflict, if `falsifier` is also given here as a real, non-empty value. | |
| legitimate_calls | No | ONLY after a refusal said THOR built a tooth from this rule's own text and it bites: a real, whole call you name as LEGITIMATE although that tooth refuses it - e.g. ["git push --force-with-lease origin main"] for a rule whose text names `--force`. It must reach the tooth's command, be refused by it, differ from the forbidden form THOR built itself, and carry something beyond the command and the literal. Then the rule is stored as a note by dispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise. | |
| new_collection_named_by_owner | No | THE OWNER JUST NAMED A NEW COLLECTION - repeat that name here, exactly as he gave it. Same field, same rule and same one flow as on remember: only after nothing fitted, you showed him the refusal and he answered with a name. It must match the project (or key) this call files the item under. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only give readOnly=false, destructive=false, idempotent=false. The description goes well beyond them: omit-keeps/empty-clears semantics, that 'none may silently vanish', the clear_* flag-plus-real-value conflict refusal, the because requirement for weakening a checked rule, and the non-idempotent retry behavior ('tried again' vs 'keeps its verdict'). Nothing here contradicts destructiveHint=false or idempotentHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the sibling routing are correctly front-loaded, but the body is a single dense run-on paragraph of semicolon-chained clauses covering clearing, refusals, replica behavior and retry semantics. It is information-rich yet hard to scan, and a few clauses (e.g. the append/replace retyping aside) restate schema notes.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 29-parameter mutation with no output schema, it covers the full lifecycle: what gets corrected, what is preserved when omitted, the refusal grounds (secrets, dropped fields, unexplained weakening), replica queueing, and the return shape ('the revised id and event sequence, or the refusal text'). Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-field meaning the schema only states per-field: the global omit/empty convention, that a flag plus a real value for the same field is refused, and that because: is mandatory specifically when a check, severity, binding or scope is weakened. It consolidates rules an agent would otherwise have to infer from 29 separate field notes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'corrects an EXISTING item by id through the same write gate as remember.' It immediately distinguishes itself from the two nearest siblings by name (remember for changed items, retract for wrong ones), so an agent can route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use and when-not: 'Prefer this over remember for an existing item that merely changed; retract, with its own reason, is for one that is simply wrong.' It also states the replica fallback ('this queues instead of writing... is not an error') and the retry verdict rule, which are usage conditions rather than restated capability.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_codeARead-onlyIdempotent
Code lane: searches the indexed SOURCE CODE of the current project, not the memory - a case-insensitive substring search. Use lookup instead for facts stored in memory, or where_used for one symbol's callers. Read-only. Every answer names the commit the text was read at and whether the working copy has since moved on - open the real file before trusting a line number. States plainly when no code index is configured, rather than returning an empty result. Replies with up to 10 matching snippets as path:start-end plus text.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Most hits to return. Defaults to 10. | |
| query | Yes | Case-insensitive substring to find in the indexed source. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent, and non-destructive behavior, so the description adds significant extra context: every result names the commit read, warns that the working copy may have moved on, advises opening the file before trusting line numbers, and states it reports a missing config instead of returning an empty result. This goes well beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and each sentence contributes a distinct fact. The only minor redundancy is 'Read-only', which repeats the readOnlyHint annotation, and the 'Code lane' opener adds little; otherwise it is tightly structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With only two simple parameters and no output schema, the description fully covers what an agent needs: return value shape, staleness caveats, missing-index behavior, and result limits. Nothing important is left out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes both parameters fully, including defaults and case-insensitivity, so the baseline is 3. The description adds the result format and the 'up to 10' cap, but it mostly echoes what the schema already provides rather than adding new parameter-level meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'searches the indexed SOURCE CODE of the current project'. It also explicitly distinguishes itself from memory lookups and names the sibling tools lookup and where_used, so an agent can immediately tell this tool apart from its alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing guidance: 'Use lookup instead for facts stored in memory, or where_used for one symbol's callers.' This clearly states when to choose this tool versus its siblings and leaves no ambiguity about the selection criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shelveA
Library lane: files one new entry on an existing shelf, or corrects or retires one by id - never the code lane. Use remember instead for code or how to work, never the owner's own life. On a replica this queues instead of writing ('queued for the main machine' is not an error). Refused, naming the shelves that exist, when none fits, unless new_shelf_named_by_owner repeats the owner's new name - then it is created (refused at the ceiling) and the entry filed on it in one call. Refused on a near-duplicate already there, pointing at it; refused past roughly 600 characters unless one_thing_because names the single thing the entry is. retire (id alone) removes it from the listing and search; library still shows it by number, refused without id, with a title/body/label change, or without retire_because. Replies 'filed ', 'revised ' or 'retired ', or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | CORRECT AN ENTRY THAT ALREADY EXISTS instead of filing a new one: its number, as the shelf listing shows it. The fields given replace what is there; the number stays, and the version replaced stays readable. Use this whenever a filed entry turns out wrong, badly worded or missing a label - a second entry saying the same thing better makes a shelf unreadable. Omit it to file something new. Required together with `retire`. | |
| body | No | The rest, at any length. Optional. See `title`'s own note on `retire`. | |
| shelf | Yes | An EXISTING shelf, or the one just named in `new_shelf_named_by_owner` on this same call. | |
| title | No | One line that stands on its own. This is the index. When correcting an entry (see `id`), leave it empty to keep the title it has. Leave it empty on a `retire` too - retire is refused together with a title, body or label change. | |
| labels | No | Optional labels for filtering inside a shelf. See `title`'s own note on `retire`. | |
| retire | No | Take this entry out of the shelf listing and out of search, without deleting it - `library` still returns it whole, marked retired, when asked for by its number. Works only together with `id`, and only alone: refused together with a title, body or label change (one thing per call), and refused without `id`. Requires `retire_because`. | |
| retire_because | No | Required together with `retire: true`: why this entry no longer belongs on the shelf, in a real sentence - the same requirement `retract` makes on the code lane, and for the same reason: without it nobody can tell a decision from an accident later. Ignored when retire is not set. | |
| one_thing_because | No | WHY THIS LONG BODY IS STILL ONE THING - required past the length where an entry is usually several things glued together, ignored below it. Name the single thing it is (e.g. "one pizza dough recipe") in a real sentence. Cannot name it in one? Then it is more than one thing - file separate entries on the same shelf with labels instead. Filler here does not get a pile past the question. | |
| new_shelf_named_by_owner | No | THE OWNER JUST NAMED A NEW SHELF - repeat that name here exactly as he gave it, and it is created (the shelf ceiling still applies) and this entry filed onto it in the same call. THE GAP THIS CLOSES: creating a shelf used to live only behind the `library` command-line binary's own `shelf-new` - an agent that asked and was answered still had no way to act on the answer, which was a dead end at a new user's very first recipe. Never fill this in on your own judgement or to get past a refusal - only after the owner himself named it. Must match `shelf` on this same call, or the write is refused. Meaningless together with `id`: correcting or retiring an entry never creates a shelf. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only indicate readOnlyHint=false and destructiveHint=false, but the description adds substantial behavior: replica queuing (not an error), retirement semantics (removed from listing/search but still visible by number), refusal reasons, and exact reply strings. This goes far beyond the annotations and enriches the agent's understanding.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but each sentence adds value, covering the three operation modes, refusal conditions, replica behavior, and reply formats. It is front-loaded with the primary purpose, though the dense run-on style could be broken into clearer sentences. It earns its length despite being verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (9 parameters, multiple modes, no output schema), the description is remarkably complete: it specifies output reply strings, all refusal conditions, the replica queue caveat, and the interaction between parameters (e.g., retire requires id and retire_because). Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents all 9 parameters with 100% coverage, including detailed descriptions for each (e.g., id, title, retire, one_thing_because). The description does not add new parameter-level meaning beyond what the schema provides, but it does reference some parameters in context. Baseline 3 is appropriate given full schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a precise verb ('shelve') and resource ('a library entry') and clearly distinguishes itself from the code lane ('never the code lane') and from the sibling 'remember' for code or personal life. It covers the three modes (file new, correct, retire) without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly directs when to use 'remember' instead for code or how-to-work, and describes refusal conditions (no matching shelf, near-duplicate, length limit) and the special case of creating a new shelf when the owner names it. This leaves no doubt about when this tool is the right choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statusARead-onlyIdempotent
Code lane: reports what the memory holds right now - live item counts per kind, how many Rule/Orientation items exist, how many were declared but have never once fired, how many were served repeatedly without ever being marked useful, and how many carry no falsifier. Use get or history instead for one specific item. Read-only, takes no arguments. Replies with a 'THOR ' line first, so a pasted reply always names the build, then one count per line.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explicitly states 'Read-only, takes no arguments,' which aligns with the annotations (readOnlyHint=true, idempotentHint=true, destructiveHint=false). It also describes the output format (version line followed by counts per line), providing transparency about the tool's behavior without contradicting the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is somewhat verbose but not excessive. It lists several specific counts, which adds useful detail but could be condensed. The structure is logical: purpose, distinction from siblings, then behavior. It earns a 4 for being informative without being overly wordy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description explains the output format and enumerates the types of counts included, which is helpful for understanding what to expect. It does not mention error handling or edge cases, but for a simple status tool with no parameters, this is sufficient. Overall, it provides enough context for an agent to use the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are no parameters in the schema, so the description cannot add meaning beyond the schema. The baseline score of 3 is appropriate since the schema coverage is effectively 100% (no parameters to describe).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: it reports live item counts per kind in the memory store. The verb 'reports' is specific, and the resource ('memory holds') is identified. It also distinguishes itself from sibling tools like get and history by explicitly mentioning they are for specific item retrieval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description indicates when not to use the tool ('Use get or history instead for one specific item'), which implicitly guides when to use status for an overview. However, it does not explicitly state conditions like 'when you need a summary' or 'when you need counts,' so it falls slightly short of fully explicit guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unpinAIdempotent
Code lane: removes the Always binding from an existing item; every other binding and field stays untouched. Use revise instead when anything besides the binding needs to change. Idempotent - unpinning an item with no Always binding changes nothing and is not an error. On a replica this queues instead of writing ('queued for the main machine' is not an error). Refused, loudly, when removing Always would leave the item with no binding left to ever fire on - give it a Moment or Target binding first, or leave it pinned. Replies 'unpinned' with the event sequence, 'already unpinned', or the refusal text.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The id to unpin (remove the Always binding from it). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry idempotentHint=true and destructiveHint=false, but the description adds genuinely useful behavioral context: replica queueing behavior, idempotency semantics, refusal conditions, and exact reply values. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but every sentence earns its place: main operation, alternative tool, idempotency, replica behavior, refusal condition, and response values. It is front-loaded with the core action and contains no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with no output schema, the description is fully self-contained. It covers normal behavior, edge cases, failure modes, and all possible replies, so an agent can invoke it correctly without external context.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the sole required parameter id is already described as 'The id to unpin (remove the Always binding from it).' The description repeats that semantic but adds no new parameter-level meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'removes the Always binding from an existing item.' It clearly distinguishes itself from revise by noting revise is for changes beyond the binding, and the sibling set includes pin as the inverse operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to use revise instead when anything besides the binding needs to change, and instructs what to do if unpinning would leave no binding: give it a Moment or Target binding first, or leave it pinned. This is strong when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
where_usedARead-onlyIdempotent
Code lane: answers who defines and who uses one symbol name - the question to ask before changing a function, struct or variable, since the reference list IS the blast radius. Use outline instead to see everything one file declares. Read-only. Resolution is by bare name only, so two unrelated things sharing a name come back together - open the files rather than treating the list as a conclusion. Replies with every definition and use site as file:line, the indexed commit, and whether the checkout has since moved on.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The bare symbol name: a function, class, struct or variable. | |
| limit | No | Most sites to return per side. Defaults to 30. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral detail beyond annotations: resolution is by bare name only, results can mix unrelated same-name symbols, and the reply includes file:line sites, the indexed commit, and whether the checkout has moved on.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact yet information-dense, with the core purpose front-loaded in the first clause. Every sentence earns its place: purpose, blast-radius framing, alternative tool, read-only note, resolution caveat, and return-value summary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema, the description clearly states what the reply contains: every definition and use site as file:line, the indexed commit, and checkout drift status. Combined with annotations covering the read-only and idempotent behavior, an agent has everything needed to invoke this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both parameters are already documented in the input schema. The description reinforces that name is a bare symbol name and mentions definitions/use sites, but it does not add substantive new meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'answers who defines and who uses one symbol name,' and frames it as the question to ask before changing a function, struct, or variable. It also distinguishes itself from outline by naming the alternative explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear when-to-use context ('before changing a function, struct or variable') and names an alternative tool ('Use outline instead to see everything one file declares'). It also warns about the bare-name resolution caveat and tells the agent to open files rather than treat the list as a conclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v2.6.0- Changed
get1 field changed- added
Input schema / properties / firedAdded value: +{ + "default": null, + "description": "true also shows where the item fired recently in THIS session (newest\nfirst, at most 10 firings): when, and the command or file it fired on.\nWhat an evaluation judges a verdict by.", + "type": [ + "boolean", + "null" + ] +}
- Changed
lookup2 fields changed- changed
Input schema / properties / key / descriptionPrevious value: -"An exact Lookup key. When given, this is the ONLY parameter used -\n`query` and `scope` are ignored - and only a real Lookup item can ever\nanswer it."New value: +"An exact Lookup key. When given, this is the ONLY parameter used -\n`query`, `scope` and `kind` are all ignored - and only a real Lookup\nitem can ever answer it." - added
Input schema / properties / kindAdded value: +{ + "default": null, + "description": "Narrow a search to one kind: rule, orientation, report or chunk -\ncase-insensitive, and an obvious plural (\"rules\") is accepted too.\nApplied AFTER the search has already run and AFTER `scope`, so it\nonly ever removes hits, never adds or reorders any. `lookup` (the\nLookup kind) is refused outright rather than silently answered empty -\nsee `key` above for the door that actually answers one.", + "type": [ + "string", + "null" + ] +}
- Changed
remember5 fields changed- added
Input schema / properties / accept_refusingAdded value: +{ + "default": [], + "description": "ONLY after a refusal said your check would refuse most of the real calls it reaches: one of\nthe calls it listed, named because refusing it IS the intent - e.g. [\"git push origin main\"]\nfor a \"never push this repository until the owner says so\" ban. The rule stays on the rule\ntrack, and doctor lists every rule kept this way. Needs `because`. Otherwise narrow the check instead.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / becauseAdded value: +{ + "default": null, + "description": "REQUIRED with legitimate_calls, may_change or accept_refusing, and never needed otherwise:\none sentence of at least 20 characters saying WHY the named span may change, or why the\ncall is legitimate, while the rule stays true. It is kept in this item's history and shown\nto the owner at the next evaluation. First try to hang a check on the literal that IS the\nrule's subject; dispute only an incidental span.", + "type": [ + "string", + "null" + ] +} - changed
Input schema / properties / check_literals / descriptionPrevious value: -"A SET of literals to forbid together, for check_kind absent_all (in one file) or forbidden\n(everywhere, no file). One rule forbidding several things at once (e.g. every banned\npunctuation character) is ONE item with a set here, never several near-identical items each\nforbidding one literal. Each literal is its own array entry, never joined into one delimited\nstring. Refused together with check_literal, refused empty, and refused with any other\ncheck_kind."New value: +"A SET of literals to forbid together, for check_kind absent_all (in one file) or forbidden\n(everywhere, no file). One rule forbidding several things at once (e.g. every banned\npunctuation character) is ONE item with a set here, never several near-identical items each\nforbidding one literal. Each literal is its own array entry, never joined into one delimited\nstring. Refused together with check_literal, refused empty, and refused with any other\ncheck_kind except requires, which takes the trigger first - one of this item's own command\nbindings, or a specific literal inside the bound command such as \"-p my-dev\" in an ssh call -\nthen every answer that satisfies it." - added
Input schema / properties / legitimate_callsAdded value: +{ + "default": [], + "description": "ONLY after a refusal said THOR built a tooth from this rule's own text and it bites: a real,\nwhole call you name as LEGITIMATE although that tooth refuses it - e.g. [\"git push\n--force-with-lease origin main\"] for a rule whose text names `--force`. It must reach the\ntooth's command, be refused by it, differ from the forbidden form THOR built itself, and\ncarry something beyond the command and the literal. Then the rule is stored as a note by\ndispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / may_changeAdded value: +{ + "default": [], + "description": "ONLY after a refusal said THOR derived a contains check from this rule's text and a file: the\nspan you name as one that MAY CHANGE in that file - e.g. [\"version\"] for a rule that names\nthe version line of package.json. It must be exactly the derived check's literal. Then the\nrule is stored as a note by dispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise.", + "items": { + "type": "string" + }, + "type": "array" +}
- Changed
revise4 fields changed- added
Input schema / properties / accept_refusingAdded value: +{ + "default": [], + "description": "ONLY after a refusal said your check would refuse most of the real calls it reaches: one of\nthe calls it listed, named because refusing it IS the intent - e.g. [\"git push origin main\"]\nfor a \"never push this repository until the owner says so\" ban. The rule stays on the rule\ntrack, and doctor lists every rule kept this way. Needs `because`. Otherwise narrow the check instead.", + "items": { + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / because / descriptionPrevious value: -"Required when this revise WEAKENS a Rule/Orientation that carries a\ncheck: clearing or changing the check, lowering or clearing severity,\nremoving a binding (target, moment or Always), or narrowing scope\nfrom global to one project. Say in one sentence why - it is written\ninto this item's own history (see `history`), the same way retract's\nreason is, so the owner can read later why a rule that could refuse a\nwrite lost its teeth. Blank or missing on one of those five is\nrefused outright. Accepted and stored on any other revise too, but\nnever required for one."New value: +"Required when this revise WEAKENS a Rule/Orientation: clearing or\nchanging its check, lowering or clearing severity, removing a binding\n(a command, path or dir anchor on any rule; any binding on one that\ncarries a check or is marked expensive), narrowing scope from global\nto one project, taking a fragment THOR builds teeth from (a backtick\nspan, a quoted call, a flag or a path) out of its text, or moving it\noff the rule track. Say in one sentence why - it is written into this\nitem's own history (see `history`), the same way retract's reason is,\nso the owner can read later why a rule lost its teeth. Blank or\nmissing on one of those is refused outright. Accepted and stored on\nany other revise too, but never required for one - except that a revise\nnaming legitimate_calls, may_change or accept_refusing always needs it:\nat least 20 characters saying why the span may change or the call is\nlegitimate while the rule stays true." - added
Input schema / properties / legitimate_callsAdded value: +{ + "default": [], + "description": "ONLY after a refusal said THOR built a tooth from this rule's own text and it bites: a real,\nwhole call you name as LEGITIMATE although that tooth refuses it - e.g. [\"git push\n--force-with-lease origin main\"] for a rule whose text names `--force`. It must reach the\ntooth's command, be refused by it, differ from the forbidden form THOR built itself, and\ncarry something beyond the command and the literal. Then the rule is stored as a note by\ndispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / may_changeAdded value: +{ + "default": [], + "description": "ONLY after a refusal said THOR derived a contains check from this rule's text and a file: the\nspan you name as one that MAY CHANGE in that file - e.g. [\"version\"] for a rule that names\nthe version line of package.json. It must be exactly the derived check's literal. Then the\nrule is stored as a note by dispute, which doctor lists for the owner. Needs `because`. Leave it out otherwise.", + "items": { + "type": "string" + }, + "type": "array" +}
1 tool update
v2.4.1- Changed
revise12 fields changed- changed
Input schema / properties / check_kind / descriptionPrevious value: -"One of: path_exists, contains, absent, absent_all, forbidden, requires. Omit all four\ncheck_* fields to keep the current check untouched; pass check_kind as \"\" to clear it\n(refused if check_path/check_literal/check_literals is also given). Give check_kind plus\nwhichever of check_path/check_literal/check_literals the kind takes, together, to replace\nthe check wholesale - see RememberArgs' own check_kind note for what each kind needs and\nwhich to prefer."New value: +"One of: path_exists, contains, absent, absent_all, forbidden, requires. Omit all four\ncheck_* fields to keep the current check untouched; pass check_kind as \"\" to clear it\n(refused if check_path/check_literal/check_literals is also given) - see `clear_check`\nbelow for the spelling that reaches this server from an assistant. Give check_kind plus\nwhichever of check_path/check_literal/check_literals the kind takes, together, to replace\nthe check wholesale - see RememberArgs' own check_kind note for what each kind needs and\nwhich to prefer." - added
Input schema / properties / clear_checkAdded value: +{ + "default": false, + "description": "Set true to clear the check - the same clear `check_kind: \"\"` above\ndocuments, same fix and convention as `clear_severity`'s own doc\ncomment (see there for the defect and the evidence). Refused, naming\nthe conflict, together with a non-empty check_kind, or with\ncheck_path/check_literal/check_literals - clearing takes none of the\nfour; give a real check_kind (plus whatever it needs) to replace the\ncheck instead.", + "type": "boolean" +} - added
Input schema / properties / clear_expiresAdded value: +{ + "default": false, + "description": "Set true to clear expires - same fix and convention as\n`clear_severity` above. Refused, naming the conflict, if `expires` is\nalso given here as a real, non-empty value.", + "type": "boolean" +} - added
Input schema / properties / clear_falsifierAdded value: +{ + "default": false, + "description": "Set true to clear falsifier - same fix and convention as\n`clear_severity` above (still refused outright on a Rule/Orientation,\nsame as `falsifier: \"\"` above, by the same ground that guards\ncreation). Refused, naming the conflict, if `falsifier` is also given\nhere as a real, non-empty value.", + "type": "boolean" +} - added
Input schema / properties / clear_keyAdded value: +{ + "default": false, + "description": "Set true to clear key - same fix and convention as `clear_severity`\nabove. Refused, naming the conflict, if `key` is also given here as a\nreal, non-empty value.", + "type": "boolean" +} - added
Input schema / properties / clear_projectAdded value: +{ + "default": false, + "description": "Set true to clear project (make it global) - same fix and convention\nas `clear_severity` above. Refused, naming the conflict, if `project`\nis also given here as a real, non-empty value.", + "type": "boolean" +} - added
Input schema / properties / clear_severityAdded value: +{ + "default": false, + "description": "Set true to clear severity - the same clear `severity: \"\"` above\ndocuments, run through the identical code path, never a second\nmechanism. THE DEFECT THIS FIXES, bitten twice (2026-09-09 and\n2026-09-11): an assistant's tool-call layer drops an empty-string\nargument before it ever reaches this server (the field arrives as\nthough it was never mentioned, or the call itself is rejected before\nthat), and a literal '\"\"' arrives as two quote characters, not an\nempty value - so the one documented way to clear a field was never\nactually reachable from an assistant. Both sessions gave up,\nretracted the rule and stored a fresh one with no check, silently\nlosing its history. This flag is the one that works from an\nassistant; the empty string above still works for a caller that can\nsend one (the JSON-RPC harness). Refused, naming the conflict, if\n`severity` is ALSO given here as a real, non-empty value - say one or\nthe other, never both.", + "type": "boolean" +} - changed
Input schema / properties / expires / descriptionPrevious value: -"Omit to keep the current expiry; pass \"\" to clear it."New value: +"Omit to keep the current expiry; pass \"\" to clear it (see\n`clear_expires` below for the spelling that reaches this server from\nan assistant)." - changed
Input schema / properties / falsifier / descriptionPrevious value: -"Omit to keep the current falsifier; pass \"\" to clear it (a Rule or\nOrientation left with none is refused, same as at creation)."New value: +"Omit to keep the current falsifier; pass \"\" to clear it (a Rule or\nOrientation left with none is refused, same as at creation - see\n`clear_falsifier` below for the spelling that reaches this server\nfrom an assistant)." - changed
Input schema / properties / key / descriptionPrevious value: -"Omit to keep the current key; pass \"\" to clear it."New value: +"Omit to keep the current key; pass \"\" to clear it (see `clear_key`\nbelow for the spelling that reaches this server from an assistant)." - changed
Input schema / properties / project / descriptionPrevious value: -"Omit to keep the current project; pass \"\" to make it global."New value: +"Omit to keep the current project; pass \"\" to make it global (see\n`clear_project` below for the spelling that reaches this server from\nan assistant)." - changed
Input schema / properties / severity / descriptionPrevious value: -"One of: irreversible, costly, house_style. Omit to keep the current\nvalue; pass \"\" to clear it."New value: +"One of: irreversible, costly, house_style. Omit to keep the current\nvalue; pass \"\" to clear it (see `clear_severity` below for the\nspelling of a clear that actually reaches this server from an\nassistant)."
2 tool updates
v2.3.2- Changed
revise1 field changed- added
Input schema / properties / becauseAdded value: +{ + "default": null, + "description": "Required when this revise WEAKENS a Rule/Orientation that carries a\ncheck: clearing or changing the check, lowering or clearing severity,\nremoving a binding (target, moment or Always), or narrowing scope\nfrom global to one project. Say in one sentence why - it is written\ninto this item's own history (see `history`), the same way retract's\nreason is, so the owner can read later why a rule that could refuse a\nwrite lost its teeth. Blank or missing on one of those five is\nrefused outright. Accepted and stored on any other revise too, but\nnever required for one.", + "type": [ + "string", + "null" + ] +}
- Changed
shelve8 fields changed- changed
Input schema / properties / body / descriptionPrevious value: -"The rest, at any length. Optional."New value: +"The rest, at any length. Optional. See `title`'s own note on `retire`." - changed
Input schema / properties / id / descriptionPrevious value: -"CORRECT AN ENTRY THAT ALREADY EXISTS instead of filing a new one: its number, as the shelf\nlisting shows it. The fields given replace what is there; the number stays, and the version\nreplaced stays readable. Use this whenever a filed entry turns out wrong, badly worded or\nmissing a label - a second entry saying the same thing better makes a shelf unreadable. Omit\nit to file something new."New value: +"CORRECT AN ENTRY THAT ALREADY EXISTS instead of filing a new one: its number, as the shelf\nlisting shows it. The fields given replace what is there; the number stays, and the version\nreplaced stays readable. Use this whenever a filed entry turns out wrong, badly worded or\nmissing a label - a second entry saying the same thing better makes a shelf unreadable. Omit\nit to file something new. Required together with `retire`." - changed
Input schema / properties / labels / descriptionPrevious value: -"Optional labels for filtering inside a shelf."New value: +"Optional labels for filtering inside a shelf. See `title`'s own note on `retire`." - added
Input schema / properties / new_shelf_named_by_ownerAdded value: +{ + "default": null, + "description": "THE OWNER JUST NAMED A NEW SHELF - repeat that name here exactly as he gave it, and it is\ncreated (the shelf ceiling still applies) and this entry filed onto it in the same call.\nTHE GAP THIS CLOSES: creating a shelf used to live only behind the `library` command-line\nbinary's own `shelf-new` - an agent that asked and was answered still had no way to act on the\nanswer, which was a dead end at a new user's very first recipe. Never fill this in on your own\njudgement or to get past a refusal - only after the owner himself named it. Must match `shelf`\non this same call, or the write is refused. Meaningless together with `id`: correcting or\nretiring an entry never creates a shelf.", + "type": [ + "string", + "null" + ] +} - added
Input schema / properties / retireAdded value: +{ + "default": false, + "description": "Take this entry out of the shelf listing and out of search, without deleting it - `library`\nstill returns it whole, marked retired, when asked for by its number. Works only together\nwith `id`, and only alone: refused together with a title, body or label change (one thing per\ncall), and refused without `id`. Requires `retire_because`.", + "type": "boolean" +} - added
Input schema / properties / retire_becauseAdded value: +{ + "default": null, + "description": "Required together with `retire: true`: why this entry no longer belongs on the shelf, in a\nreal sentence - the same requirement `retract` makes on the code lane, and for the same\nreason: without it nobody can tell a decision from an accident later. Ignored when retire is\nnot set.", + "type": [ + "string", + "null" + ] +} - changed
Input schema / properties / shelf / descriptionPrevious value: -"An EXISTING shelf. If none fits, ask the owner - you may not create one."New value: +"An EXISTING shelf, or the one just named in `new_shelf_named_by_owner` on this same call." - changed
Input schema / properties / title / descriptionPrevious value: -"One line that stands on its own. This is the index. When correcting an\nentry (see `id`), leave it empty to keep the title it has."New value: +"One line that stands on its own. This is the index. When correcting an entry (see `id`),\nleave it empty to keep the title it has. Leave it empty on a `retire` too - retire is refused\ntogether with a title, body or label change."
16 tool updates
v0.1.0- First observed
get - First observed
history - First observed
library - First observed
lookup - First observed
mark - First observed
outline - First observed
pin - First observed
remember - First observed
resolve - First observed
retract - First observed
revise - First observed
search_code - First observed
shelve - First observed
status - First observed
unpin - First observed
where_used
TDQS
Scored across 16 tools
The set carefully draws boundaries between each tool: lookup (search) vs get (fetch by id), revise (changed) vs retract (wrong), lookup (memory) vs search_code vs where_used (code), remember (code lane) vs shelve (life lane), and read/write pairs like library/shelve and pin/unpin. Descriptions explicitly cross-reference the right alternative, so an agent can always pick the correct tool.
Most tools use a single lowercase word (lookup, get, mark, remember, resolve, retract, revise, pin, unpin, shelve), while a few use snake_case (search_code, where_used) and several are nouns rather than verbs (library, history, status, outline). Still readable and predictable overall, with only minor stylistic deviation.
16 tools cover three coherent sub-domains (memory lifecycle, code navigation, and the library lane), and each tool maps to a distinct operation. It sits at the heavier end of the ideal range but no tool feels redundant or filler.
Full lifecycle is present for the memory lane (remember/revise/retract/get/history plus resolve for conflicts and mark for feedback), the library lane (library/shelve), and code reasoning (search_code/outline/where_used), with status for overview and pin/unpin for binding management. No obvious dead ends or missing operations for the stated purpose.
Maintenance
Related MCP Connectors
Team memory for coding agents: rules you approve, served to every agent, and which ones it cited.
Agent memory that refuses to guess: evidence-gated recall, exact-source reads, verifiable deletion.
Hosted agent memory with provenance, contradiction surfacing, and snapshot rollback.
Keeps AI agents from repeating costly mistakes: past decisions, rules and incidents, shared by all.
Related MCP Servers
- AlicenseAqualityFmaintenanceSelf-improving, verifiable memory for AI coding agents. Learns how you work, stops repeating mistakes, models each project, recalls the right lesson at the right moment. Every memory is signed and tamper-evident. Local-first.82Apache 2.0
- AlicenseAqualityCmaintenanceLocal-first project memory for AI coding agents. Records failed attempts, fragile files, and decisions per repo, and warns the agent via hooks before it repeats a recorded mistake.660 npmMIT
- AlicenseBqualityAmaintenanceLocal-first, auditable memory for Codex, Claude Code, and MCP clients. It stores scoped user/project memory in SQLite or Postgres, serves read-only recall and inspection tools by default, and supports opt-in governed writeback with review and forget controls.8277 npm19MIT
- AlicenseNot gradedqualityAmaintenanceA local-first memory for AI coding agents. AgentRecall turns the feedback and failures you run into while coding into reusable rules, then serves the right ones back — on the command line or directly to Claude Code over MCP. Everything stays on your machine: no cloud sync, no web UI, no API keys.9MIT