Skip to content

What a search covers

When you ask an agent to search Hadron and don't name a memory, the search does not necessarily look at everything you can read. On MCP it looks at the first view that applies to you: a scope you named, a scope you selected earlier, the memories attached to your active App, or your organization's memories. When a view narrowed the search, the result says which view answered, so you can see what it covered. A search that names memories directly and no scope is the exception, and so is a bare CLI search; both are covered below. This page explains how that choice is made, what a scope is, and the cases where a surface behaves differently.

You don't need a terminal to use any of this. You can ask your agent "which memories did that search cover?", "show me what the research scope looks at" or "search my whole organization". The tool names and commands are further down, and the exact signatures are in the MCP tools and CLI references.

Statements below are marked as either spec (a rule in the platform specs, cited) or behaviour (what the server does today, read from source at the revision named in Where this was checked). Behaviour can change without a spec changing.

What a scope is

A scope, also called a lens, is a named, ordered list of memories. Exactly one owner holds it: an organization, an Agent or an App (cor:acl:120:03). A scope narrows what a search looks at.

A scope never grants. What a search covers under a scope is the scope's memories intersected with the memories you may read. It can only be smaller than your own access, never larger (cor:acl:120:01). That is why a scope is safe to share with a team or hand to an agent.

Two halves of that rule are easy to miss:

  • A dropped memory is disclosed, not refused. If a scope lists a memory you can't read, the search still runs over the rest. The result tells you how many memories were dropped. It is never an error and never silent.
  • A scope doesn't reveal names. The count is always shown. Identifiers of dropped memories appear only where the ordinary discoverability rules already let you see them. Naming a memory in a scope does not make it visible to you.

Which memories a search covers by default

The answer depends on the surface, because the three surfaces keep different state.

MCP (your agent): the ladder

MCP walks this ladder and uses the first rung that applies (cor:acl:120:02, behaviour in resolveSearchScope):

  1. A scope named in the call. A scope id, a scope name, or one of the two reserved names below.
  2. The active scope you selected earlier (hadron_set_active_scope).
  3. The active App (app): the memories attached to it.
  4. The active organization (global): your organization's readable memories.
  5. If you have no organization at all, your own user-owned memories.

The active memory is not a rung. A search never falls back to it.

What this means in the three common situations:

Your situation A bare search covers
An App is active That App's attached memories (unless an active scope is selected, which wins)
No App, but an organization resolves That organization's view
Neither Your own user-owned memories

Two names are reserved, and no scope can be created with either: app (the active App's view) and global (the active organization's view). You can pass either as scope to pick that view on purpose, for example when an active scope is selected and you want the App view for one call.

The organization is not always resolvable. If you belong to several organizations and nothing picks one (no org-owned App, no selected organization), a search that needs the organization refuses with ORG_REQUIRED and lists your memberships. That is the one refusal on this path, and it comes from the organization lookup rather than from a rung of the ladder. Choose one with hadron_set_active_org (CLI: hadron org use). A personal App has no organization.

GraphQL: explicit only

GraphQL has no ambient rungs. With no scope named, findNodes keeps its older meaning: it searches the set of memories you can read, optionally narrowed by an organization you pass. A scope applies only when the call names one, and a bare scope name also needs an App context (appRef). An App key is its App, so its credential supplies that context (behaviour, resolveNamedScopeForQuery).

The CLI: your stored choice, nothing ambient

The CLI applies no App or organization rung. With no -m and no --scope, hadron search covers every memory you can read, unless you saved a default scope with hadron scope set-active <scope> (alias use). In that case it searches that scope and says so on the first line of the result. --scope on the command line beats the saved default. --scope global uses the organization you chose with hadron org use.

Naming memories in the call

You can also name memories directly (memoryUrn, memoryUrns, allMemories or parentRel on MCP, -m on the CLI). How that combines with a scope depends on whether the same call names a scope (cor:acl:120:02):

  • A scope named in the call, plus memories: the scope is resolved first and the memories you named narrow within it. A memory outside the scope is not searched, so naming one can produce an empty result that says the memory is outside the scope.
  • No scope named, plus memories: the explicit memories replace the ambient rungs (the active scope, the active App, the active organization). You answered the question those rungs exist to answer, and a remembered selection should not quietly shrink an explicit request.

In both cases the result is still intersected with what you may read. Naming memories changes which view answers and never widens it.

A narrowed result says which view answered

When a scope or view narrowed the search, the result opens with a scope: line naming the view that answered and which rung chose it (via call, via session, via active-app or via active-org), plus the dropped count when it is above zero. When a result surprises you, read that line first.

The line is not on every result. It is absent in these cases (behaviour):

  • MCP: a hadron_find_nodes call that names memories directly and names no scope. The explicit memories replaced the ambient rungs, so no view applied and no scope: line is printed.
  • CLI: a bare hadron search, and hadron search -m <memory> with no scope. Both start straight with the SCORE, LOC and NAME table. With --scope, or with a default saved by hadron scope set-active, the CLI prints scope: ... (app, via call) or the equivalent.

No scope: line therefore means "no scope or view narrowed this search", not "a view you can't see applied".

Who wins when two memories hold the same address

General search has no winners. If two memories in the search's view hold a node at the same address, both appear in the results. Nothing is hidden because another memory "won".

Two facts stop this from being misread:

  • Scope order does not rank results. A scope stores its memories in order, but search ignores that order (cor:acl:120:00). Don't read a ranked list as reflecting the order of the scope.
  • Precedence is about scope names, not nodes. When several owners offer a scope with the same name, the most specific owner wins: App, then Agent, then organization. The losing scopes are not merged in (cor:acl:120:03). That says nothing about two nodes at one address.

The only "which one wins?" answer is ScopeExplanation.winner, which you get by asking a scope to explain an address: hadron scope explain <scope> --loc <address>, or hadron_scope_explain with loc. It answers for one scope and one address.

What does and doesn't narrow

  • Search (hadron_find_nodes, hadron_search) takes the ladder above.
  • Browsing a memory (hadron_list_nodes) takes no scope. It shows the tree of the one memory you name, and the source applies no scope narrowing to it (behaviour).
  • Entity listings (memories, Apps, and so on) are not narrowed by your active App. An active App routes where a write lands; it is not an access filter on a read (cor:acl:020:03, rules 1 and 2).

Note that the ladder's App rung is a narrowing of search only. It is not a statement that selecting an App narrows reads in general.

Where this was checked

  • Spec: cor:acl:120 (:00 to :03) for scopes, the ladder and precedence; cor:acl:020:03 for "selection routes" and entity listings.
  • Behaviour: read from hadron-server at d984e5c3 (the commit the alpha server was serving on 4 November 2026, image tags 0.0.1687 and d984e5c3): src/lib/scopes.ts (resolveSearchScope, resolveNamedScopeForQuery, RESERVED_SCOPE_NAMES), src/mcp/server.ts (mcpSearchScope, the scope: result line, hadron_list_nodes). The served-revision receipt is team chat #74127 (read from the running alpha container); the server itself does not report its revision, and this page did not check production separately. The CLI statements were read against hadron-cli v0.35.0.
  • Not specified: the user-owned fallback (rung 5), the scope: result line, and hadron_list_nodes taking no scope are current behaviour. No spec states them as rules, and they can change.