16 tools and 3 resources, read from the server source.
Recognition (turn-start)#
Call these when a turn begins. They are bounded in time by contract and never wait on retrieval.
prepare_recognition_context#
prepare_recognition_context(prompt: str, access_level: str = 'team', include_private: bool = False, federation_hop: int = 0) -> dict
Return immediate recognition and a bounded prompt-context fragment.
This is the MCP-facing timing layer: agents can call it at turn start,
prepend the returned prompt_context to their own model prompt, and
continue with deeper retrieval in parallel.
When peers are configured (--peer flag, Phase 1.6+), the local
recognition fires first (~1.2 ms substrate) then peers are queried
in parallel under a tight per-peer timeout. Peer-matched entities
are merged into matched_entities with agents tagged
peer:<peer-name>:<agent>. Slow / dead peers are dropped and
reported in peer_latencies_us so the response is bounded.
federation_hop is an internal depth guard: peer L6 servers pass
1 so the query answers from the local store only (depth-1
federation, #139). End clients leave it at 0.
When one or more local participant surfaces have a persisted drift
verdict (the export watermark says a store that used to yield has
stopped, P1-11), the response additionally carries
drifting_surfaces: [{agent, checked_at, reason}]. The key is
PRESENT only when non-empty -- a healthy machine says nothing --
and it degrades to absent when the watermark state is unreadable.
get_deeper_context#
get_deeper_context(prompt: str, access_level: str = 'team', include_private: bool = False) -> dict
Return post-recognition deeper context for the prompt.
This companion tool is intentionally separate from
prepare_recognition_context so immediate recognition never waits on
retrieval. Context is assembled from the local store -- free, no model
call -- and an enabled L2 backend is appended when one is configured.
The response carries its own provenance: source, entities,
doors (which retrieval door matched), l1_documents,
truncated, and reason when the context is empty. Callers that
want prose synthesize it with their own model; see hydration_hint.
compile_codex_turn#
compile_codex_turn(prompt: str, cwd: str | None = None, access_level: str = 'team', max_items: int = 6, max_chars: int = 1800) -> dict
Compile a turn-scoped Codex recognition brief.
This is the active recognition-orchestration surface for Codex: it ranks prompt, cwd/repo identity, local Codex thread metadata, and L6 federation context into a compact prompt fragment without depending on native Stage 1 summarization.
Read#
Query the federation library. Every read re-applies visibility at query time through access_level.
find_entity#
find_entity(name: str, access_level: str = 'public', include_private: bool = False, federation_hop: int = 0) -> dict
Find an entity by name across all agents.
include_private defaults to False. Callers that genuinely need
unredacted output must pass True explicitly -- this is a second
line of defense on top of per-manifest visibility policy.
When the server has peer L6 servers configured (--peer flag),
the result also merges matches from each peer's library, tagging
peer-sourced agents as peer:<peer-name>:<agent>.
federation_hop is an internal depth guard: peer L6 servers pass
1 so the query answers from the local store only (depth-1
federation, #139). End clients leave it at 0.
query_agent_memory#
query_agent_memory(agent: str, topic: str, access_level: str = 'public', include_private: bool = False) -> dict
Find entries in one agent's L5 that match a topic.
Parameters
agent : strAgent ID (e.g. "claude-code", "codex", "alpha-agent").topic : strThe entity name or topic to look for. Case-insensitive.
Returns
- dict
{"agent": str, "matches": list[EntityMatch-as-dict]}
get_cross_agent_summary#
get_cross_agent_summary(project: str, access_level: str = 'public', include_private: bool = False, federation_hop: int = 0) -> dict
Aggregate everything the federation knows about a project.
Returns agents that touched it, recent sessions whose
project_focus references it, and entity matches. When peers are
configured (--peer flag), peer libraries are merged in with
agents tagged as peer:<peer-name>:<agent>.
federation_hop is an internal depth guard: peer L6 servers pass
1 so the query answers from the local store only (depth-1
federation, #139). End clients leave it at 0.
list_recent_work#
list_recent_work(since: str | None = None, agent: str | None = None, access_level: str = 'public', include_private: bool = False, limit: int | None = None, cursor: str | None = None, summary: bool = False, federation_hop: int = 0) -> dict
Return a page of sessions across agents (or a single agent).
Parameters
since : str, optionalISO 8601 date (YYYY-MM-DD) or datetime. When omitted ANDcursoris omitted, the store applies a 14-day default window so the first call from a naive caller doesn't pull the entire history.agent : str, optionalFilter to one agent's sessions.limit : int, optionalPage size. Defaults to 20, capped at 100.cursor : str, optionalOpaque token from a previous response'snext_cursor. Pagination loop: call once, then keep passing the most recentnext_cursoruntilhas_moreis false. Re-pass anysince/agentfilters on each page.summary : bool, optionalWhen true, omitkey_actionsandfiles_touchedfrom each session row. Useful for timeline/dashboard callers that only need date + agent + project focus.federation_hop : int, optionalInternal depth guard. Peer L6 servers pass1so a federated query answers from the local store only, federation is depth-1 by contract (#139). End clients leave this at0.
list_workstreams#
list_workstreams(status: str | None = None, agent: str | None = None, access_level: str = 'public', include_private: bool = False) -> dict
List workstreams -- ongoing multi-session initiatives, distinct from a single dated Session and from a named glossary Entity.
Parameters
status : str, optionalFilter to one lifecycle state:active/paused/done/archived. Omit to return all statuses.agent : str, optionalFilter to one agent's workstreams.
Unlike list_recent_work, this is not paginated -- workstreams
are a small, named, bounded set (capped at 200/agent per the L5
schema). Dedupes by name across agents, same as find_entity.
Federation note: this queries the LOCAL store only. Cross-peer workstream federation is not yet wired (tracked as a follow-up to the entity/session federated query paths).
list_notes#
list_notes(since: str | None = None, agent: str | None = None, access_level: str = 'public', include_private: bool = False, limit: int | None = None, cursor: str | None = None) -> dict
Return a page of freestanding notes across agents (or a single agent) -- unstructured journal entries, not tied to a specific named entity or a single session's action log.
Pagination and default-since-window behavior mirror
list_recent_work exactly.
Federation note: this queries the LOCAL store only. Cross-peer note federation is not yet wired (tracked as a follow-up to the entity/session federated query paths).
list_agents#
list_agents(federation_hop: int = 0) -> dict
List agent IDs known to this L6 server, plus any peers' agents.
Peer-sourced agents are NOT prefix-tagged here, call sites that need
provenance use the more detailed find_entity / get_cross_agent_summary
tools where each agent is tagged peer:<peer-name>:<agent>.
federation_hop is an internal depth guard: peer L6 servers pass
1 so the query answers from the local store only (depth-1
federation, #139). End clients leave it at 0.
export_agents#
export_agents() -> dict
Export THIS server's LOCAL agents only, source-attributed for the tray.
Returns the bourdon.agents/v1 envelope for this machine's own
*.l5.yaml manifests -- each agent redacted and tagged
source=<this machine> / source_kind="local".
Critically, this tool does NOT fan out to peers. The federated merge
(local + every peer's export_agents) happens caller-side in
core.l6_store.L6Store.export_agents_federated, which re-tags
each peer's agents with that peer's name. Keeping this tool local-only
is what prevents the bidirectional-federation echo: when peer A calls
peer B's export_agents, B returns only B's agents, never A's agents
bounced back.
describe_caller#
Annotations: openWorldHint=false, readOnlyHint=true
describe_caller() -> dict[str, object]
Describe this authenticated member and current meetings authority.
Requires explicit library enrollment and member-bound credentials. A descriptor is a policy observation, not a reusable write permit.
Write#
The single write path. Quarantined members are staged, never live.
commit_to_federation#
commit_to_federation(agent_id: str, agent_type: str | None = None, instance: str | None = None, role_narrative: str | None = None, entities: list[dict] | None = None, sessions: list[dict] | None = None, workstreams: list[dict] | None = None, notes: list[dict] | None = None, mode: str = 'merge', session_id: str | None = None, transcript_ref: str | None = None, expected_digest: str | None = None) -> dict
Write a contribution to the federation under agent_id.
The write-side companion to the read tools. Lets MCP-aware cloud agents (Claude Desktop, ChatGPT desktop, other webview/cloud-only agents that have no readable on-disk store for Bourdon to scrape) push their own L5 contributions into the federation by calling this tool when they decide a piece of context is worth sharing.
Parameters
agent_id : strAgent slug, e.g.claude-desktop. Must match^[a-z0-9][a-z0-9_-]*$.agent_type : str, optionalRequired when creating a NEW manifest for this agent_id; one of the L5 schema enum values (code-assistant,note-capture,other, etc.). Ignored when merging into an existing manifest that already has agent.type set.instance : str, optionalOptional machine/deployment identifier.role_narrative : str, optionalFree-text description of the agent's role within a fleet.entities : list of dict, optionalEach entity dict needs at minimum a non-emptyname(other L5 entity fields -- type, summary, tags, visibility, aliases, valid_from, valid_to -- pass through as-is).sessions : list of dict, optionalEach session dict needs at minimum adate: an ISO 8601 calendar date (YYYY-MM-DD), or exactly""when the source carried no recognisable timestamp (the schema's empty-date provision -- never substitute the current date). Other L5 session fields -- cwd, project_focus, key_actions, files_touched, visibility -- pass through.workstreams : list of dict, optionalEach workstream dict needs at minimum a non-emptyname. Astatus(one of active/paused/done/archived) defaults toactiveif omitted. Other fields -- summary, started, last_touched, related_entities, tags, visibility -- pass through.notes : list of dict, optionalEach note dict needs at minimum adateand non-emptytext. Other fields -- related_entities, tags, visibility -- pass through.mode : "merge" or "replace"merge(default) unions new rows with the existing manifest. Entities dedupe byname.lower(); sessions dedupe by(date, cwd). List fields (tags, aliases, key_actions, files_touched, project_focus) are unioned on dupe; non-list fields are overwritten.replacewipes the manifest and writes only the provided content.
Returns
- dict with the write summary (counts added/updated/total, path,
- agent identity, last_updated). On invalid input, returns a
- structured error response with an
errorkey. When the merged - result is semantically identical to the current manifest, nothing
- is written (no version snapshot, no timestamp bump) and the
- summary carries
no_op: truewith the unchanged digest; the no_opkey is absent on a real write (B3-P2-01).
Quarantined callers (v0.9.0): the write is STAGED under
<library>/staging/<caller>/ instead of touching the live store,
and only the caller's own agent_id namespace is writable.
Staged content is invisible to every read until the operator runs
bourdon staging promote <agent>.
DURABILITY (issue #134): commits are durable only on commit-only
slugs (claude-desktop-chat, alpha-agent, other self-authoring
agents). Reader-backed manifests (claude-code, codex,
cursor, ...) are REGENERATED from their native stores by
bourdon export-all / the per-agent export hooks, which discards
rows previously merged in via this tool. Commit under your own
self-authoring agent_id, not a reader's.
History and rollback#
Every commit archives the manifest it replaced, so memory has an undo history with provenance.
list_memory_versions#
list_memory_versions(agent_id: str, limit: int | None = None) -> dict
Prior states of one agent's memory, newest first.
Every commit archives the manifest it replaced, so this is the undo
history. Each row carries an opaque version_id to pass to
rollback_agent_memory, and a digest8 that joins to the
provenance entry explaining which session produced that state.
Read access follows the same rules as any other read: quarantined callers may only list history for namespaces they were granted (or org-readable namespaces), and only because this tool is on the quarantined allowlist -- the central check is applied here like everywhere else (B3-P1-18).
explain_memory_change#
explain_memory_change(agent_id: str, digest: str) -> dict
Which session produced a given state of an agent's memory.
Hand it a manifest digest (or a version's digest8) and it
returns the write that created it -- caller, session, transcript,
and what changed. This is the join that turns "this row looks wrong"
into "this run put it there, here is its transcript."
⚠ session_id and transcript_ref are caller-asserted and
unverified. The recorded caller identity is not.
Access follows the same rules as any other read: the quarantined allowlist gates the tool, and read grants (or org-readability) gate the namespace (B3-P1-18).
rollback_agent_memory#
rollback_agent_memory(agent_id: str, version_id: str, expected_digest: str | None = None, session_id: str | None = None) -> dict
Restore an archived version of an agent's memory. TRUSTED ONLY.
⚠ This is the most destructive operation the server exposes. It discards every contribution made after the chosen version -- including contributions from OTHER agents, which had no part in the bad update and were never consulted about undoing it. Quarantined callers cannot reach it at all, and they cannot reach it by staging either: staging is for adding content, and a rollback is a deletion wearing a restore's clothes.
Pass expected_digest when the decision took a while. Choosing a
version is a human-length window, and a commit that lands meanwhile
would otherwise be erased by the restore without anyone seeing it.
The restore is itself snapshotted first, so a rollback is undoable.
Resources#
MCP resources are read-only URIs a client can list and fetch without a tool call.
agent-library://agents#
list_agents_resource() -> list[str] | dict
List of all agent IDs known to the federation.
agent-library://agents/{agent_id}/memory#
get_agent_memory_resource(agent_id: str) -> dict
Full visibility-filtered L5 manifest for one agent.
Returns an empty dict with an error key when the agent is
unknown (MCP resources can't signal 404 cleanly, so we surface
it in the payload).
agent-library://entities/{name}#
get_entity_resource(name: str) -> list[dict] | dict
Cross-agent view of one entity by name.