Knowledge Bases & Workspace Context

Applies to: ChengOS v0.1.0+ | Last verified: 2026-08-12 | Source: crates/cheng-core/src/domain/knowledge_base, crates/cheng-core/src/domain/workspace, crates/cheng-nodes/src/nodes/builtin/workspace, crates/cheng-engine/src/executor/context.rs

A workspace is the container everything else lives in — documents, tables, conversations, files, and knowledge bases. A knowledge base is a workspace-scoped vector collection: the searchable half of a workspace.

Understanding how the active workspace reaches a running node is what makes the rest of this page (and most of the data nodes) make sense, so start there.

Workspaces

Workspace (aggregate root)
  ├── tenant_id, owner_id
  ├── WorkspaceMember[]   (owner / admin / editor / viewer)
  └── WorkspaceSettings
        ├── default_workflow_id     (workflow used for AI conversations)
        ├── features                (per-workspace feature flags)
        ├── storage_quota
        ├── trace_retention
        └── artifacts               (upload limits, LLM preview budget, retention)

Member roles are owner, admin, editor, viewer. Only owner and admin can change workspace settings.

Workspaces are soft-deleted (deleted_at), so removing one does not immediately destroy the documents and tables inside it.

trace_retention and artifacts are worth knowing about because they are the per-workspace overrides for two things people usually look for in global config: how long execution traces are kept, and how large an artifact may be before the store rejects it.

Ambient context: how a node knows its workspace

Most data nodes have a workspace_id input that is hidden on the canvas (x-hidden) and normally left blank. The engine injects it at runtime.

Three fields are treated this way — AMBIENT_CONTEXT_FIELDS:

conversation_id   workspace_id   document_id

They are resolved from the agent context's metadata first, then from execution metadata (conversation_id additionally falls back to the agent's session_id).

The security-relevant detail: for tool calls, ambient injection force-overrides whatever the model supplied. An LLM cannot widen its own scope by inventing a workspace_id in a tool call, because the engine replaces the field after the model produces it. This is the same principle as the sandbox root, where a model-supplied sandbox_root is dropped outright in favour of the static canvas value.

workspace/context exposes the injected value as a normal node output — workspace_id plus a has_workspace boolean — for when a workflow needs to branch on it or log it. has_workspace is false when the workflow was triggered outside any workspace, which is a real case for channel and API entry points.

Cross-workspace overrides are deliberately not available as canvas nodes. App and API entry points own workspace selection; a workflow cannot reach sideways into another workspace.

Workspace bootstrap

When a workspace record is created, a bootstrap service optionally populates it. Every option defaults to off; callers opt in:

OptionCreates
create_foldersThe root folder tree (documents / tables / conversations / workflows)
create_welcome_documentA welcome document (requires create_folders)
create_default_conversationA starter conversation (requires create_folders)
create_default_tableA starter table (requires create_folders)
create_knowledge_baseA default knowledge base
configure_aiFeature flags and default_workflow_id

The dependency rules are enforced by normalize(), so an inconsistent combination is corrected rather than silently half-applied. The default_full() preset creates only the folder tree — documents, tables, conversations, and knowledge bases are created lazily by their own nodes when a user actually needs them.

Knowledge bases

KnowledgeBase
  ├── workspace_id
  ├── name, description
  ├── collection_name      ← the Qdrant collection
  ├── status               ← active | building | error | archived
  ├── document_count
  └── config { embedding_model, chunk_size, chunk_overlap, ... }

The collection name is generated as kb_<workspace_id>_<kb_id> unless you supply one. That naming is the isolation boundary: two workspaces can never collide in the vector store, because the workspace id is part of the collection name.

Status matters when you script against it. A knowledge base is building while it is being created or indexed, and querying it then is premature; error means indexing failed; archived means disabled but retained.

config carries the embedding parameters — embedding_model, chunk_size, chunk_overlap — plus arbitrary extra settings. These are per-knowledge-base, not global: two knowledge bases in one workspace can use different embedding models. That is also why they are not interchangeable — vectors written with one embedding model cannot be searched with another.

The knowledge base node

workspace/knowledge_base has three modes:

ModeRequiresReturns
select (default)kb_idThe chosen knowledge base
list—Every knowledge base in the workspace
createname (optional description, embedding_model)The new knowledge base

The output exposes workspace_id and kb_id as flat top-level fields in addition to the structured knowledge_base object, precisely so they can be wired straight into a RAG node's input without an intermediate mapping step.

In select mode, kb_id is a dynamic dropdown populated from GET /api/v1/workspaces/current/knowledge-bases?limit=200 — you pick by name, the node stores the UUID.

REST access

Knowledge bases are managed under a workspace:

GET|POST      /workspaces/:workspace_id/knowledge-bases
GET|PUT|DELETE /workspaces/:workspace_id/knowledge-bases/:kb_id
GET           /workspaces/current/knowledge-bases

The current route resolves the workspace from the request context, which is what the node's dropdown uses.

Putting it together

The usual arrangement is:

workspace/knowledge_base (select)
        │ kb_id
        ▼
rag/document_indexer   ──►  writes vectors into the collection
        …
rag/retriever          ──►  reads them back at query time

Create the knowledge base once, then reference it by id from both the indexing workflow and the answering workflow. RAG Pipeline Design covers what happens inside those two nodes.

Next steps