workspace-visibility.ts3.0 KBView on GitHub /**
* Which rows the `/brain` workspace draws — the ONE rule its tree, its search box and its
* graph all share, so a file one of them hides cannot walk back in through another.
*/
/**
* `{user|organisation}/agent-…` — an agent's own namespace at the root of a workspace.
*
* Two shapes live there and both are machine-managed: `agent-{agentId}`, the folder an
* agent writes its output, config and memory into, and `agent-instructions`, the
* per-playbook instruction documents the routing surface owns. Neither is a file anyone
* keeps by hand, and there are as many of the first as the user has agents — twenty rows
* reading "Agent 4008f724 71dc 4d3f 8f52 Afe58ae927b9" sat above the first folder the user
* actually made. Each has a surface of its own (`/agents/:agentId`, `/brain/playbooks/routing`)
* where it is editable in context, which is where it belongs.
*
* Matched on the two shapes EXACTLY, not on an `agent-` prefix. A folder a person names
* "Agent Notes" slugifies to `agent-notes` (services/file-system/paths.ts) and lands at
* `user/agent-notes` — a prefix test hides it from the tree, the search AND the graph at
* once, which is a user's own folder gone from every way there is to look for it. An agent
* id is a UUID, and `instructions` is the one other name the namespace answers to.
*
* ── Why a UUID and not something looser ──
*
* `aop_agents.id` is `text`, so nothing in the SCHEMA forces a UUID, and a looser pattern was
* argued for on that basis. Checked against production before choosing: 2215 agents and 414
* distinct `agent-*` root segments, none of them anything but a UUID or `agent-instructions`.
* There is also no second signal to lean on — a namespace root is a plain `folder` row, the
* same document type a person's own folder has — so this is a choice between two regexes, and
* their failure modes are not comparable:
*
* too loose → a folder someone MADE disappears from every view. Reads as data loss.
* too strict → a hypothetical non-UUID agent folder shows up as one extra row. Clutter.
*
* So it is deliberately strict. If agent ids ever stop being UUIDs this is the line that has to
* change with them, and `workspaceVisibility.test.ts` is where that shows up.
*
* Conversation-scoped agent folders (`conversation/{id}/agent-{id}`) need no mention here —
* `/brain` shows nothing under `conversation/` at all.
*/
const AGENT_NAMESPACE =
/^(?:user|organisation)\/agent-(?:instructions|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:\/|$)/i;
export function isAgentWorkspacePath(path: string | null | undefined): boolean {
return AGENT_NAMESPACE.test(path ?? '');
}
/** Whether a document belongs in `/brain` at all — the tree, the search and the graph. */
export function isBrainWorkspaceDoc(doc: { path: string | null | undefined }): boolean {
// Conversation-scoped docs are not workspace files; `/brain` never shows them.
if ((doc.path ?? '').startsWith('conversation/')) return false;
if (isAgentWorkspacePath(doc.path)) return false;
return true;
}