Hanzo

Knowledge

Package knowledge is your team's wiki and your agents' memory, searchable by meaning.

Package knowledge is your team's wiki and your agents' memory, searchable by meaning.

Base URLhttps://api.hanzo.ai
Operations9
AuthAuthorization: Bearer $HANZO_API_KEY

Specification

HIP-1260 · Knowledge — Wiki and Agent Memory — Draft · read the specification →

/v1/knowledge is one organization's knowledge, searchable by meaning: wiki pages a person writes, memories an agent files, and documents a connector ingests are ONE document store, indexed into that organization's own vector namespace on every save and read back as semantic search, a link graph, or an imported vault. It is implemented in hanzoai/cloud at apps/knowledge. This HIP states the property everything rests on — human wiki and agent memory are one store indexed once, so an agent retrieves exactly what the team can read — and the surface that exposes it.

Motivation

A team wiki and an agent's memory are usually two systems: two stores, two permission models, two search indexes, and an integration that copies one into the other and drifts. Here a wiki page IS a document, a memory IS a document, an ingested Slack thread IS a document (apps/knowledge/kb.go:15-24), and one indexing path serves them all — so "what does this org know about X" has one answer whether a person or an agent asks.

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

It owns no store

The documents are the framework engine's, as module kb (apps/knowledge/kb.go:40): CRUD, permissions and tenant isolation are the framework's generic surface, and this capability adds behaviour, not storage. The vectors are the shared vector store's, one collection per organization, written only through the one index path (apps/knowledge/index.go:22-27). Both stores are owned elsewhere; this capability MUST NOT open a store of its own, and any new document kind MUST enter as a framework DocType so the same hooks index it.

The address

The capability answers under /v1/knowledge: semantic search (the RAG entry point), the link graph, vault import, and the connector set — list, catalog, connect, callback, sync, disconnect (apps/knowledge/subsystem.go:84-99). Today's router still serves this surface at /v1/kb; that pair is carried by hanzoai/cloud openapi/misfiled.txt and closes by fold, the route group being one literal (apps/knowledge/subsystem.go:82).

Every operation is typed except the import, which cannot be: its body is the upload itself — a vault zip, an .enex XML document or a JSON export chosen by ?format= — not JSON a typed input could decode, so it is declared with prose beside the route (apps/knowledge/subsystem.go:92-99, apps/knowledge/import.go:129-150). An importer normalizes to one pure shape (apps/knowledge/vault/vault.go) and files through the same ingest path a connector uses; no importer MAY write the store or the index directly.

Tenant

Every handler resolves its organization from the validated principal — principal.Acting (apps/knowledge/subsystem.go:141, apps/knowledge/connectors.go:223) — and a request without one is refused. Isolation at the index is physical AND filtered: each organization has its own collection and every point carries the organization in its payload, so a search must pass both (apps/knowledge/index.go:31-35, :297).

Meter, events, observability, stage

Metered, and the unit is one connector piece run (plugin/knowledge/main.go, Price: cloud.Metered): a long-tail connector's sync executes a JavaScript piece on the auto engine's sandbox pods, and reaching that capacity by in-cluster URL does not make the pod cheaper. The fee is CLOUD_KB_FEE_CENTS_PIECE over CLOUD_KB_FEE_CENTS, defaulting to one cent — sized like the compute it buys, one bounded execution on a pod already held — gated before the engine is asked and debited only after it answers (apps/knowledge/meter.go). The native-Go connectors start no pod and stay free, as does everything else on the surface. The other debit lands through ai: embeddings for index and query go the metered gateway path with the same model on both sides (apps/knowledge/index.go:50-51).

It publishes no events on the bus. Beyond the request span it registers nothing; its degradations are on the wire instead — indexing is fail-open (a save never blocks on the index) and query is fail-honest, answering an empty result with degraded: true rather than a 5xx or a fabricated hit (apps/knowledge/index.go:37-42, apps/knowledge/subsystem.go:124-127).

Its stage is ga.

Upstreams

It derives from none: no OSS project is forked, embedded or mirrored. The importers implement third-party export formats from their public shapes, in pure Go with no upstream code taken — the Lexical EditorState JSON the editor renders (apps/knowledge/lexical/lexical.go), Obsidian vault markdown, Roam's JSON export, Evernote ENEX/ENML, and the Notion API's result shapes (apps/knowledge/{obsidian,roam,evernote,notion}).

Rationale

The alternative is a dedicated knowledge service with its own database and its own permission model. It buys nothing the framework does not already have and costs a second tenancy implementation — the exact place a wiki leaks. Attaching behaviour to the framework's store means the fourth app lane after cms, erp and help reuses isolation that is already tested, and the only new code is the one index path and the pure normalizers.

Fail-open indexing was chosen because the store is the record and the index is derived: losing a search hit until reindex is recoverable; losing a save is not.

Security Considerations

The surface is an organization's institutional memory — the most valuable single corpus a tenant hands us — so the wrong implementation leaks a whole company at once. The cross-tenant argument is doubled on purpose: a collection-name bug cannot leak because the payload filter still excludes foreign points, and vice versa (apps/knowledge/index.go:31-35).

Connector tokens are third-party credentials (Slack, GitHub, Google). They live in KMS at a per-org path; the connector document holds only the path and non-secret metadata, and the token is never logged (apps/knowledge/connectors.go:13-15). The OAuth state is HMAC-bound to the organization (apps/knowledge/connectors.go:16), so a callback cannot be replayed into another tenant's connection.

The import route parses attacker-supplied archives; every read is bounded (apps/knowledge/import.go:142, :174), so a crafted zip exhausts a limit, not the process. And because everything indexed is retrieved into agent context, ingested text is data, never instructions — the retrieval surface returns documents and MUST NOT execute them.

Four surfaces

SurfaceReaches this capability asCoverage
RESTknowledge at its own prefix9 operations
CLIno command reaches it yet — use HTTP or an SDK
SDKno published client declares one yet — regenerating the clients is what adds them
MCPtool knowledge on https://api.hanzo.ai/v1/mcp9 operations, 0 under the document's own id — ask describe for the rest

Quickstart

export HANZO_API_KEY=sk-...   # console.hanzo.ai → API keys

Then the first call — a read that needs nothing but the key. GET /v1/knowledge/graph, operation get_knowledge_graph:

hanzo has no subcommand for this operation — the CLI serves only what cloud's live route table confirms. Use HTTP or an SDK.

Answers 200 with object — ok.

Endpoints

EndpointWhat it does
GET /v1/knowledge/connectors/{provider}/callbackCompleteConnectorOAuth finishes an OAuth connection: it exchanges the provider's code for a token, seals that token in KMS, and records the…
GET /v1/knowledge/connectors/{provider}/connectStartConnectorOAuth returns the provider authorize URL the console opens to connect this org's account.
POST /v1/knowledge/connectors/{provider}/syncPulls the provider's documents for the caller's org and files them as knowledge sources, which the store's own hook then indexes — so a synced…
DELETE /v1/knowledge/connectors/{provider}Revokes a connection: it tombstones the stored credential so a later sync cannot reuse it, purges this provider's points from the org's vector…
GET /v1/knowledge/connectors/catalogReturns the ONE catalog of everything a caller can connect: every first-party connector and every long-tail one, in a single list sorted by provider.
GET /v1/knowledge/connectorsReturns every supported knowledge connector with THIS org's connection state and the REAL number of documents each has ingested into the org's store.
GET /v1/knowledge/graphReturns the caller org's knowledge as a node/edge graph shaped for a force-directed renderer: pages, memories and synced sources as nodes; the page…
POST /v1/knowledge/importImport an Obsidian, Notion, Roam or Evernote export into the org's knowledge base
POST /v1/knowledge/searchRuns a semantic search over the caller org's own knowledge — its wiki pages, its agent memories and everything its connectors have synced — and…

All Hanzo APIs · Interactive reference

How is this guide?

On this page