Skip to content

[bug] Knowledge → Documents, Files and Index are shown on agents that declare no tool to read them — the gate the Indexing surface got was never applied one level in #509

Description

@serge-ivo

The Knowledge tab offers Documents, Files and Index to agents that hold no tool to read any of them

Found while auditing why the owner reports "tools are missing in coder agents and coder lead
agents". This one is the mirror image: the tool is genuinely absent and correctly so, but the
console still offers the place to put the data.

Not reproduced end-to-end — recorded as a latent trap, with the negative measurement. Checked
GET /v1/instances/:id/{knowledge,files} on the three instances in question today:

f8ddc272… Heartfull    (coder-repo)  {"documents":[]}  {"files":[]}
bd43f4de… Chess coder 2(coder-repo)  {"documents":[]}  {"files":[]}
5fab318d… Coder Lead   (coder-lead)  {"documents":[]}  {"files":[]}

Nothing has been uploaded yet, so nobody has been silently ignored. The first document he drops
into a Repo Coder's Knowledge → Documents will be.

Verified

coder-repo declares ten tools and coder-lead ten; neither list contains a single knowledge or
file tool
(search_knowledge, list_knowledge, read_knowledge, add_knowledge,
update_knowledge, delete_knowledge, upload_file, list_files, read_file, delete_file).
toolNamesFor (workers/api/src/agent-do-tools.ts:187-193) makes a declared list authoritative, so
BASE adds none of them back. Confirmed live via list_instance_tools on both instances.

The console's top-level surface registry already applies exactly this gate. Indexing
(store/console/src/lib/surfaces.tsx:255-265):

// The vector store behind RAG. An agent with no knowledge tools has nothing indexed and
// nothing that searches it, so this rendered an empty panel on every coding agent — the
// same "shown because nobody asked whether the agent declares it" failure as the second chat.
show: (caps) => caps.surfaces.includes("repo") || canUse(caps, KB_TOOLS),

and Data (:267-276) does the same for collection tools. Knowledge does not (:229-239):

// Deliberately NOT gated on KB tools. It is a composite: Documents/Files need them, but
// Memory and Rules & Tips are per-instance and universal … Splitting the composite is the
// real fix and is a separate change.
show: () => true,

The deferral is honest and the reason is right. But the sub-tab list inside it is a static array
with no capability input at all
(store/console/src/tabs/KnowledgeTab.tsx:418-428):

const subTabs = [
    { id: "docs", label: "Documents" }, { id: "memory", label: "Memory" },
    { id: "tasks", label: "Tasks" },    { id: "files", label: "Files" },
    { id: "index", label: "Index" },    { id: "credentials", label: "Credentials" },
    { id: "rules", label: "Rules & Tips" },
];

So on every Repo Coder and on the Coder Lead the owner is shown a Documents editor, a file uploader,
and — note — the Index panel (:716, <VectorsSection …>), which is the very panel the
indexing surface was gated to stop showing on coding agents. Gating the top-level tab and leaving
the same component reachable one level in means that fix is half-applied.

Why it matters more than a stray tab

Uploading into Documents works: the API stores it, and the DO vectorises it. Nothing errors. The
agent then cannot search, list or read it, and — having no tool for the request — answers
conversationally, which is the failure tool-reachability.test.ts's header describes and #444
measured three times. The owner's reasonable conclusion is "the agent ignored my document", and the
true answer, "this agent has no knowledge tools", is stated nowhere in the UI.

What to do — cheapest first

1. Gate the three sub-tabs on the same predicate the surfaces already use. KnowledgeTab takes
the instance capabilities it can already reach (InstanceDetail resolves them for the tab bar) and
filters: docs/files on canUse(caps, KB_TOOLS) / the file tools, index on the identical
expression surfaces.includes("repo") || canUse(caps, KB_TOOLS) — imported from
surfaces.tsx, not restated, so the two cannot drift. Memory, Tasks, Credentials and Rules & Tips
stay universal, which is exactly what the deferral comment wanted to protect. If the active sub-tab
is filtered out, fall back to memory.

2. Then finish the split the comment asks for. Once Documents/Files/Index are gated, the
Knowledge tab on a coding agent is Memory · Tasks · Credentials · Rules & Tips — which is a
different tab than the one the label promises. Whether it becomes "Memory & Rules" for those agents
is a naming decision, not a bug; raise it separately rather than bundling it here.

3. Add the guard. surfaces.test.ts already asserts "show must key off declared capability
surfaces, never an agent's identity"
(:55-56) by reading the source. The same file should assert
the sub-tab list for a {surfaces:["coding"], tools:["repo_git"]} capability contains neither
docs, files nor index — otherwise the next sub-tab added to that array repeats this.

Alternatives considered and rejected

  • Gate the whole Knowledge tab. Explicitly rejected by the code, correctly: it would take Memory
    and Rules & Tips — which every agent has and every subscriber can write — away from every coding
    agent to hide two sub-tabs.
  • Grant the coders KB tools instead. That is a product decision, not a fix for a UI leak, and it
    would reverse a deliberate one: toolNamesFor's header explains that withholding search_knowledge
    from coding agents "is what stops the empty-index hallucination at the source, not just in the
    prompt" (agent-do-tools.ts:170-176).
  • Leave it and add an empty-state message. Weaker: the upload still succeeds, so the message has
    to appear after the owner has spent effort, and it has to be written in three panels instead of
    one predicate.

Acceptance criteria

  • On a coder-repo instance the Knowledge tab shows Memory, Tasks, Credentials, Rules & Tips —
    and no Documents, Files or Index.
  • On repo-chat (surfaces:["repo"], KB reads declared) and on any agent declaring the KB or
    file tools, all seven sub-tabs are unchanged.
  • The index sub-tab's predicate is the same expression the indexing surface uses, imported
    rather than copied.
  • surfaces.test.ts fails if a future sub-tab is added ungated.

Regression risk

  • Hiding a sub-tab from an agent that legitimately has data behind it. The population at risk is
    agents with documents already stored but no declared KB tool. Worth a one-off query before
    shipping; on this account the answer is measured above and is zero.
  • A deep link to …/knowledge?sub=docs on a gated agent. Must fall back to memory, not render
    blank — the same fallback instanceRoute.ts already does for a surface an instance does not expose.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfrontendFrontend / UI work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions