Skip to main content
The canonical path is /topics. /watchers still works as a deprecated alias for old CLIs and is removed in a later release.

Core CRUD

MethodPathPurpose
GET/workspaces/:slug/topicsList topics (visible to the caller), relevance-ranked (drifted-first). ?limit=&offset= bounds the page; archived topics are hidden unless ?status=archived
POST/workspaces/:slug/topicsCreate a topic (a Note, or status: proposed to put it up for review)
GET/workspaces/:slug/topics/:topicGet topic detail
PATCH/workspaces/:slug/topics/:topicUpdate a topic
DELETE/workspaces/:slug/topics/:topicDelete a topic
The read response is the canonical context. It includes a flat trust verdict (reviewed | proposed | draft) plus classification.status and a governance block: the trust signal an agent consumes. Key on trust directly:
{
  "trust": "reviewed",
  "classification": { "status": "reviewed" },
  "governance": { "authoritative": true, "approved_by": "u_cto", "approved_at": "..." }
}

Search & Matching

MethodPathPurpose
GET/workspaces/:slug/topics/searchFull-text search, relevance-ranked. ?tags=a,b scopes to topics carrying ANY of those tags; ?limit= caps the result set (default 50); ?stale=true|false filters by freshness; archived topics are never returned
POST/workspaces/:slug/topics/match-filesMatch files to topics
GET /workspaces/:slug/topics also accepts ?tags=a,b (comma-separated, OR semantics). Tag names are normalized server-side (lowercase, whitespace→dashes).

Tags

The workspace tag registry: tags as first-class objects so they can be pre-created with a description before any topic uses them. Attaching an unregistered tag via a topic write auto-registers it.
MethodPathPurpose
GET/workspaces/:slug/tagsList with per-tag topic counts, paginated (?limit=&offset=, default 50, most-used first), returns { tags, total, has_more }
POST/workspaces/:slug/tagsCreate { name, description? }, idempotent (existing tag merges the description)
PATCH/workspaces/:slug/tags/:nameRename ({ name }, rewrites every topic carrying the tag; owner/admin) and/or describe ({ description })
DELETE/workspaces/:slug/tags/:nameDelete + detach from every topic (owner/admin)

Health & Graph

MethodPathPurpose
GET/workspaces/:slug/topics/auditContext health audit
GET/workspaces/:slug/topics/eventsTopic event timeline
GET/workspaces/:slug/topics/graphTopic graph

Governance

A topic becomes Knowledge only once an owner/admin merges it in. See Governance. approve / reject and Suggested-edit merge / reject require owner/admin authority. They succeed for an owner/admin principal on any surface (dashboard, owned CLI key, or an OAuth/MCP token the owner/admin authorized), and the merge is stamped approved_via (human or agent). A faceless or non-owner principal is rejected.
MethodPathPurpose
POST/workspaces/:slug/topics/:topic/proposedraft → proposed
POST/workspaces/:slug/topics/:topic/approve→ reviewed (reviewed)
POST/workspaces/:slug/topics/:topic/rejectproposed → draft
POST/workspaces/:slug/topics/:topic/archive→ archived
GET/workspaces/:slug/topics/:topic/proposalsList Suggested edits
POST/workspaces/:slug/topics/:topic/proposalsOpen a Suggested edit ({ summary, patch })
POST/workspaces/:slug/topics/:topic/proposals/:id/mergeMerge a Suggested edit
POST/workspaces/:slug/topics/:topic/proposals/:id/rejectClose a Suggested edit

Relations

MethodPathPurpose
POST/workspaces/:slug/topics/:topic/relationsAdd a typed relation
GET/workspaces/:slug/topics/:topic/relationsList relations
DELETE/workspaces/:slug/topics/:topic/relations/:relationIdDelete a relation
POST /topics and PATCH /topics/:topic responses may include anchor_validation: per-pattern match counts against the repo’s default branch (ok / overbroad / zero, with samples and warnings). Advisory only: it never blocks the write, and it’s omitted when no repo is linked. POST …/relations is reachable by OAuth (MCP) principals with topics:write; deleting relations stays human-only.

Share

MethodPathPurpose
POST/workspaces/:slug/topics/:topic/shareCreate a public read-only link
DELETE/workspaces/:slug/topics/:topic/shareRevoke the link
GET/s/:tokenPublic page (no auth)
GET/s/:token/rawPublic markdown (no auth)