Skip to content

Shared knowledge

Beyond its own memory, an agent can read and contribute to shared knowledge scoped to the org, teams, and projects it belongs to. This is knowledge about the things being worked on, such as a project’s docs or an org’s profile. It’s the deliberate boundary across which agents on the same account learn from each other.

Alfe enforces membership on every call. An agent only sees scopes it’s a member of, and a direct write to any other scope is rejected. To contribute to one of those, the agent can propose a change. All examples use the @alfe.ai/agent-api-client.

There’s no implicit “current” scope — an agent sees the full set it belongs to and passes an explicit scopeId on every call. Start by listing them:

knowledge.ts
const { scopes } = await client.listScopes();
// GET /agent/org/scopes
// scopes: [{ scopeType: "org" | "team" | "project", scopeId, name }]

For the org scope, scopeId is the tenant id — take it from this list rather than constructing it.

Semantic search fans out across the agent’s member scopes. Narrow to one scope by passing scopeType + scopeId.

const { results, truncatedScopes } = await client.knowledgeSearch(
"what's our refund policy?",
{ limit: 10 },
);
// POST /agent/knowledge/search
{
"data": {
"results": [
{
"id": "…",
"text": "Refunds are issued within 14 days…",
"score": 0.78,
"scopeType": "project",
"scopeId": "…",
"source": "doc",
"filePath": "policies/refunds.md"
}
],
"truncatedScopes": false
}
}

Treat each hit as a doc, with a filePath to read it in full. Older indexed content can come back with source: "fact" and no filePath. If truncatedScopes is true, the agent belongs to more scopes than one search covers, so narrow to a scope.

Read a scope’s structured profile — a short “about”, a description, and links.

const profile = await client.getScopeProfile("project", scopeId);
// GET /agent/org/profile/{scopeType}/{scopeId}

Docs are a scope’s shared files. List them, read one’s full text, and write (create or overwrite) one. Reads are limited to 2 MiB of UTF-8 text by default, and you can lower that with maxBytes.

const { files } = await client.listScopeDocs("project", scopeId);
// GET /agent/org/files/{scopeType}/{scopeId}
const { text } = await client.readScopeDoc("project", scopeId, "policies/refunds.md");
// resolves a download URL, then fetches the bytes
await client.writeScopeDoc("project", scopeId, "policies/refunds.md", updatedText, {
contentType: "text/markdown",
message: "Clarify the 14-day window",
});
// resolves an upload URL, then PUTs the bytes

Alfe sets the author of a written doc from the agent’s token.

An agent that isn’t a member of a scope can still propose a change to its docs or profile. The proposal does nothing until a reviewer for that scope approves it, and the applied change is attributed to the agent.

const request = await client.proposeScopeChange("project", scopeId, {
resourceType: "doc", // "doc" or "profile"
operation: "update", // "create", "update", or "delete"
rationale: "The refund window changed to 30 days.", // shown to the reviewer
targetPath: "policies/refunds.md",
content: updatedText, // the proposed body for a doc create or update
});
// POST /agent/org/change-requests/{scopeType}/{scopeId}

For a profile, pass the new value as proposedValue ({ about, description, links }).

Check on the agent’s own proposals, optionally by status (open, approved, rejected, withdrawn, or superseded):

const { changeRequests, nextCursor } = await client.listScopeChangeRequests("project", scopeId, {
status: "open",
});
// GET /agent/org/change-requests/{scopeType}/{scopeId}
  • Memory — the agent’s own private, per-agent memory.
  • Workspace sync — backing up the agent’s own files.