Blog
How AI agents find specifications by meaning
You ask an AI coding agent to plan a fix for "sign-in problems". Somewhere in your project there is already a specification about exactly that. It is titled "Authentication errors", and it never uses the words "sign-in" or "problems". The agent searches, finds nothing, and does the reasonable thing: it writes a new specification. Now you have two documents describing the same work in different words, and the new one knows nothing about the session change that the old one was waiting for.
Nothing went wrong in the agent's reasoning. It was missing a fact that your project already held. This article is about closing that gap: what an agent needs to find before it plans, why matching words is not enough for specifications, and how to work with a search that matches meaning. We'll use one example throughout: a product whose specification tree has an Accounts branch, and a new request about sign-in.
Why word search fails on specifications
Searching code by words works well, because code is full of exact names. Specifications are different in three ways:
- They are written in people's words. One author writes "sign-in", another "login", a third "authentication". All three mean the same screen. A word search treats them as unrelated.
- They describe intent, not identifiers. "Customers should not lose their cart when a payment fails" contains no term you could guess from the phrase "declined card handling", yet it is the same requirement.
- They are written over months by different people. The vocabulary of a project shifts. The specification from last spring uses the terms of last spring.
The larger the tree, the worse this gets. With twenty specifications you remember what exists. With four hundred, nobody does, and the agent least of all: it starts every session knowing only what it can find.
What an agent needs to know before it plans
Before an agent writes or plans anything, three questions need an answer, and all three are search questions:
- Where does this belong? A request about sign-in errors is a child of something. Under which branch of the tree should it go?
- What does it overlap? Is there an existing specification that already covers part of it, or all of it?
- What must be done first? Does other planned work have to land before this can start?
A person answers these from memory. An agent answers them from search results, or not at all. An agent that cannot find the related specification does not stop and report that it is unsure. It plans as if the related work did not exist.
What search by meaning changes
Search by meaning, also called semantic search, matches a query against what a text says, not only against the words it uses. A query for "sign-in problems" can return the specification about authentication errors although the two share no words.
Three things make it useful in practice:
- It is one search, not two. Matches by word and matches by meaning should arrive in one ranked list. Exact terms still count: a query for an error code or a field name finds the specification that contains it.
- It covers the whole document. A match can come from the title, the summary or the content, so a requirement in the fourth paragraph is as findable as a title.
- It accepts the request as it was phrased. The agent can search with the user's own sentence instead of guessing which keywords the original author chose.
That last point matters most for agents. A person who gets no results tries a synonym. An agent often takes an empty result as an answer.
Step 1: Search before you write a new specification
Make the search the first step of planning, not an optional one. Before a new specification is created, search the tree for the request and read what comes back.
For the sign-in request, the search returns three things: "Authentication errors" under Accounts, "Password reset by email" next to it, and "Session expiry" under a Security branch. Each changes the plan:
- The first may already be the specification you were about to write. Extend it instead of duplicating it.
- The second is a neighbour. It tells you where the new work belongs: next to it, under Accounts.
- The third is planned work that touches the same code.
Search more than once, with different wording: the request as the user phrased it, then the technical term, then the visible symptom. Three short searches cost little and catch what a single phrasing misses.
Step 2: Read matches with their ancestors
A match on its own is half an answer. "Session expiry" could be a finished detail of a login page or an open piece of a security review. What tells you which is its position in the tree: its parent, and the parent above that.
So ask for matches together with their ancestors, not as a flat list:
- Accounts
- Sign-in
- Authentication errors <- match
- Password reset by email <- match
- Security
- Session handling
- Session expiry <- matchRead this way, the results answer the first planning question directly. Two matches sit under Accounts, Sign-in, so that is where the new work belongs. The third sits in another branch, which is a sign of a dependency between branches, not of a duplicate.
Ancestors also carry decisions. If the Sign-in specification says that accounts are locked after five failed attempts, every child inherits that, including the one you are about to write.
Step 3: Turn related specifications into blockers
A related specification that you only read is forgotten by the next session. Record the relationship. If the sign-in fix cannot be finished before the session expiry change lands, make the second a blocker of the first: "this specification can't start until that one is done".
Treat what the search returns as candidates, not as conclusions. A match by meaning says that two texts are about similar things. It does not say that one depends on the other. For each candidate, decide:
- Duplicate: the same work. Merge the request into the existing specification.
- Blocker: different work that has to come first. Record it.
- Neighbour: related, with no order between them. Mention it and move on.
- Noise: similar words, different subject. Ignore it.
The agent can propose which is which, and it should say why. You confirm. A wrong blocker is not harmless: it holds work back for no reason. For how blockers give you a build order, see how to break down a spec for AI coding agents.
Step 4: Write specifications that are easy to find
Search by meaning forgives vocabulary. It does not forgive vagueness. A specification that says little cannot be matched to much. A few habits make every specification easier to find:
- Give it a title that says what changes. "Authentication errors" is findable. "Fixes, part 2" is not.
- Write a summary. Two sentences on what the specification is for give a search the clearest statement of its meaning.
- Keep one topic per leaf. A specification that covers sign-in, billing and email at once matches everything weakly and nothing well.
- Say what users see. Include the symptom ("the form shows a blank page") next to the cause, because the next request will describe the symptom.
- Spell out the terms. Write the full name at least once next to an internal abbreviation.
These are the same habits that make a specification good for an agent to implement. Being easy to find and being easy to carry out come from the same clarity.
What semantic search does not do
It is worth being exact about the limits:
- It does not decide. It returns similar texts. Whether they are duplicates, blockers or noise is a judgement.
- It does not guarantee a match by meaning for every query. Some searches return only word matches, and a good search falls back to them without failing. Treat an empty result as "search again with other wording", not as proof that nothing exists.
- It is not instant for new text. A specification written a moment ago may be findable only by its words at first.
- It does not read the code. It finds what was written down. Work that was never specified cannot be found.
- It does not replace structure. A tree with parents, summaries and recorded blockers is what makes a match meaningful. Search finds the place. The tree tells you what the place means.
How to do this with Athenode
Athenode keeps specifications as a tree and searches them by meaning: matches by word and matches by meaning are combined into one ranked list, across each specification's title, summary and content.
- Search before writing:
/atn-mindmapsearches the tree to find where a new specification belongs and which existing specifications it relates to or is blocked by, before it writes anything. - Search at every stage:
/atn-decomposedoes the same for each stage it proposes, so blocker candidates turn up while the work is being split. The skill records the blockers it finds and lists every link it added in its report, so you can review them. - Matches with ancestors: agents call
specs_treewith a query, which returns up to 20 matches nested with their ancestors, as in Step 2. A match found by meaning comes with the text that matched. - Matches only:
specs_searchreturns the matching specifications without their ancestors, for when the agent needs a quick check. - Honest fallback: when matching by meaning is not available, a search returns the word matches, without an error. New and changed specifications become findable by meaning after a short delay, and are found by their words until then.
The same search is behind the search box of the web app, the specification tools of the MCP server and the specs commands of the CLI. See how it works for the tree itself, or read what spec-driven development is for the bigger picture.
Checklist
Before an agent plans new work:
- The tree is searched for the request before a new specification is written.
- The search is repeated with other wording: the user's phrase, the technical term, the symptom.
- Matches are read with their ancestors, not as a flat list.
- Each related specification is classed as a duplicate, a blocker, a neighbour or noise.
- Blocker candidates are confirmed by a person and then recorded.
- New specifications have a clear title, a summary and one topic each.
- An empty result leads to another search, not to a duplicate.