Project API
A Context knowledge workspace has two durable declarations with separate jobs:
| File | Declares |
|---|---|
src/index.ts | Source references, document capture, custom non-knowledge orchestration, and package outputs — through the @c4a/context SDK |
src/indexers.yaml | Long-term reader requirements, authorized target and supporting sources, and confirmed exclusions |
Never describe the same knowledge transformation in both. The Agent edits these declarations when the current Route asks for a configuration change; you do not need to write code yourself.
defineProject
import { defineProject } from "@c4a/context";
export default defineProject({
sources: [],
phases: [],
packages: [],
});The definition is declarative: loading it must not change knowledge or runtime state.
Sources
const repo = source("20260901", "component-lib");
const docs = source("20260901/product-docs", { type: "file" });
const handbook = source("20260901/handbook", { type: "lark" });
const note = source("20260908/decision-context.md", { type: "note" });
const session = source("20260908/design-discussion.md", { type: "sessions" });
const everyRepo = allSources("repo"); // spread inside sources: [...everyRepo]| Type | Resolves against | Registered with |
|---|---|---|
repo (default), file, lark | sources/<type>/index.yaml; the name includes the registration date and module | context source add … |
note, sessions | Saved Markdown under sources/note/YYYYMMDD/ or sources/sessions/YYYYMMDD/; no separate registry or capture phase | context source import |
Saving a source does not select it — include its reference in sources. The source list enables acquisition and initial selection; the requirements and each Indexer's target and read scopes decide what it owns and may read.
Capture phases
captureFile({ source: docs });
captureFile({ source: docs, processor: mdxJsonDocs() });
captureLark({ source: handbook });Capture only creates a deterministic, readable snapshot; classification and writing follow the selected Indexer. Adding --configure to context source add repo|file|lark|batch generates the source references and default capture phases in src/index.ts for you. It keeps existing settings, is idempotent, and leaves custom or dynamic entries untouched with a configuration.status: manual hint.
For many documents with the same settings, map the registry instead of repeating declarations:
const registry = await loadSourcesRegistry({ rootDir: workspaceRoot });
const documents = registry.larks.map(entry => source(entry.name, { type: "lark" }));
export default defineProject({
sources: documents,
phases: documents.map(document => captureLark({ source: document })),
packages: [],
});File documents use registry.files with captureFile. Filter entries for a subset. allSources("lark") selects a whole collection and cannot be mapped into per-document phases. Capture boundaries do not dictate article boundaries.
customPhase
customPhase("project:refresh-catalog", async (ctx) => {
await ctx.ensureSources();
});For project orchestration that neither publishes knowledge nor bypasses the Indexer lifecycle. Declare stable reads and writes when the phase has them.
Packages
kbPackage({
name: "component-kb",
template: "src/package-templates/kb",
select: { collections: ["codeindex", "architecture"] },
site: { title: "Component knowledge", base: "/" },
});
llmsPackage({
name: "component-context",
template: "src/package-templates/llms",
select: { collections: ["codeindex"] },
});| Field | Required | Meaning |
|---|---|---|
name | Yes | Lowercase, path-safe; output goes to dist/<name>/ |
template | Yes | Template directory, or { path, vars } |
select | No | collections, okfRoots, include, exclude; omit for all approved knowledge |
navigation | No | Directory-index policy; default { foldDirectoryIndexes: true, maxInlineEntries: 50 } |
assets | No | { delivery: "bundle" } (default), "git-raw" with urlPrefix, or "omit"; optional optimize |
site | No (kbPackage only) | Adds a documentation site at dist/<base>-site/, where <base> is the name without one trailing -kb |
Packages read approved knowledge/ only; dist/ is generated. Details are in Package Templates.
Site options
| Option | Meaning |
|---|---|
title, description | Site title and description |
lang | Primary language, default en-US |
base | Deployment path such as / or /docs/ |
titleLink | Target of the top-bar title; defaults to the site home |
home | title, slogan, description, hero actions (text, link, theme), and resources (each needs href, command or both) |
locales | Additional reader languages keyed by BCP 47 tag, each with optional label, title, description, home; must differ from lang |
nav | Top links after the knowledge sections: text, link, optional per-locale locales text |
more | Items placed in the More menu before the built-in LLM Docs and Changelog entries: text with exactly one of link or target.artifact_ref (an approved article shown only there) |
socialLinks | icon (github, discord, x, youtube, slack, linkedin, mastodon, npm), an https link, optional ariaLabel |
localePreferenceKey | Shared storage key so sites on one origin keep the same reader language |
theme | light and dark colors: brand, accent, background, surface, text, mutedText, border as hex values |
extensions | Trusted presentation code: root (default src/site), slots (brand, banner, knowledge, resources, footer, floating; false hides one) and custom Markdown pages |
Links accept https or mailto: URLs, root-relative paths or page anchors. Custom pages are placed in the knowledge map with target.artifact_ref: "site:<page-key>". See Documentation Sites and Page and Theme Customization.
Requirements and Indexer Skills
When src/indexers.yaml is missing, the configuration Route supplies its schema. Write requirements only — no protocol, indexers, Provider selections or profiles. Which installed Indexer Skills to use, and their optional configuration, belongs to indexer_usage in the temporary production plan, not to this durable file. The Agent writes drafts and references under the returned temporary directory; the CLI accepts them and owns candidates, review and formal output.
Durable and runtime state
Source registries and snapshots, saved notes and summaries, project declarations, package templates and approved knowledge are durable inputs, versioned in Git when Git operations are authorized. .tmp/context-runtime/ holds unfinished execution state and stays out of Git. knowledge/structure.yaml keeps shared page and source metadata and compact processed_scopes; a partial update or failed build does not advance a whole range's processed version. Use the CLI to adjust or roll back work rather than editing these baselines.
The workspace package.json also accepts context.convertVisuals (default true): a capable Agent may convert source diagrams and tables into faithful text structures, keeping the original image when it cannot preserve the meaning.
Project API
Context 知识工作区有两份长期保存的声明,各自承担不同的职责:
| 文件 | 声明内容 |
|---|---|
src/index.ts | 通过 @c4a/context SDK 声明来源引用、文档采集、不产出知识的自定义编排,以及知识包输出 |
src/indexers.yaml | 长期的读者需求、已授权的目标来源和辅助来源,以及已确认的排除项 |
不要在两处描述同一种知识转换。当前 Route 要求修改配置时,由 Agent 编辑这些声明;你不需要自己写代码。
defineProject
import { defineProject } from "@c4a/context";
export default defineProject({
sources: [],
phases: [],
packages: [],
});该定义是声明式的:加载它不得改变知识或运行时状态。
来源
const repo = source("20260901", "component-lib");
const docs = source("20260901/product-docs", { type: "file" });
const handbook = source("20260901/handbook", { type: "lark" });
const note = source("20260908/decision-context.md", { type: "note" });
const session = source("20260908/design-discussion.md", { type: "sessions" });
const everyRepo = allSources("repo"); // spread inside sources: [...everyRepo]| 类型 | 解析依据 | 登记方式 |
|---|---|---|
repo(默认)、file、lark | sources/<type>/index.yaml;名称包含登记日期和模块 | context source add … |
note、sessions | 保存在 sources/note/YYYYMMDD/ 或 sources/sessions/YYYYMMDD/ 下的 Markdown;没有单独的登记表或采集 phase | context source import |
保存来源并不等于选用它——还要把它的引用加入 sources。来源列表负责启用获取和初始选择;需求以及每个 Indexer 的目标范围和读取范围,决定它负责哪些内容、可以读取哪些内容。
采集 phase
captureFile({ source: docs });
captureFile({ source: docs, processor: mdxJsonDocs() });
captureLark({ source: handbook });采集只负责生成确定、可读的快照;分类和写作由选中的 Indexer 完成。给 context source add repo|file|lark|batch 加上 --configure,就会自动在 src/index.ts 中生成来源引用和默认的采集 phase。它会保留已有设置,可重复执行,并且不会改动自定义或动态条目,只给出 configuration.status: manual 提示。
如果有许多设置相同的文档,可以映射登记表,而不必重复声明:
const registry = await loadSourcesRegistry({ rootDir: workspaceRoot });
const documents = registry.larks.map(entry => source(entry.name, { type: "lark" }));
export default defineProject({
sources: documents,
phases: documents.map(document => captureLark({ source: document })),
packages: [],
});文件类文档使用 registry.files 搭配 captureFile。需要子集时,可以过滤条目。allSources("lark") 选择整个集合,无法映射为按文档划分的 phase。采集边界并不决定文章边界。
customPhase
customPhase("project:refresh-catalog", async (ctx) => {
await ctx.ensureSources();
});用于既不发布知识、也不绕过 Indexer 生命周期的项目编排。如果该 phase 有稳定的读取和写入,请声明出来。
知识包
kbPackage({
name: "component-kb",
template: "src/package-templates/kb",
select: { collections: ["codeindex", "architecture"] },
site: { title: "Component knowledge", base: "/" },
});
llmsPackage({
name: "component-context",
template: "src/package-templates/llms",
select: { collections: ["codeindex"] },
});| 字段 | 是否必填 | 含义 |
|---|---|---|
name | 是 | 小写、可安全用作路径;输出到 dist/<name>/ |
template | 是 | 模板目录,或 { path, vars } |
select | 否 | collections、okfRoots、include、exclude;省略时包含全部已批准的知识 |
navigation | 否 | 目录索引策略;默认为 { foldDirectoryIndexes: true, maxInlineEntries: 50 } |
assets | 否 | { delivery: "bundle" }(默认)、搭配 urlPrefix 的 "git-raw",或 "omit";可选 optimize |
site | 否(仅限 kbPackage) | 在 dist/<base>-site/ 生成文档站点,其中 <base> 是去掉末尾一个 -kb 后的名称 |
知识包只读取已批准的 knowledge/;dist/ 是生成产物。详见包模板。
站点选项
| 选项 | 含义 |
|---|---|
title、description | 站点标题和描述 |
lang | 主语言,默认为 en-US |
base | 部署路径,例如 / 或 /docs/ |
titleLink | 顶栏标题的链接目标;默认为站点首页 |
home | title、slogan、description、首屏 actions(text、link、theme),以及 resources(每项需要 href、command 或两者兼有) |
locales | 额外的读者语言,以 BCP 47 标签为键,每项可选 label、title、description、home;不能与 lang 相同 |
nav | 知识分区之后的顶部链接:text、link,可选按语言提供的 locales 文本 |
more | 放在“更多”菜单中内置的 LLM Docs 和 Changelog 之前的条目:text,并且 link 与 target.artifact_ref(仅在此处显示的已批准文章)二者只能选一 |
socialLinks | icon(github、discord、x、youtube、slack、linkedin、mastodon、npm)、一个 https link,可选 ariaLabel |
localePreferenceKey | 共享的存储键,让同一源下的多个站点保持相同的读者语言 |
theme | light 和 dark 两套颜色:brand、accent、background、surface、text、mutedText、border,均为十六进制值 |
extensions | 受信任的展示代码:root(默认 src/site)、slots(brand、banner、knowledge、resources、footer、floating;设为 false 可隐藏其中之一)以及自定义 Markdown pages |
链接可以是 https 或 mailto: URL、以根目录开头的相对路径,或页面锚点。自定义页面通过 target.artifact_ref: "site:<page-key>" 放入知识地图。参见文档站和页面与主题定制。
需求与 Indexer 技能
当 src/indexers.yaml 缺失时,配置 Route 会提供它的 schema。只写 requirements——不要写 protocol、indexers、Provider 选择或 profile。使用哪些已安装的 Indexer 技能及其可选配置,属于临时生产计划中的 indexer_usage,而不属于这份长期保存的文件。Agent 在返回的临时目录下写入草稿和引用;CLI 负责接收它们,并掌管候选、审核和正式输出。
持久状态与运行时状态
来源登记表和快照、已保存的笔记和摘要、项目声明、知识包模板以及已批准的知识,都是持久输入;在获准执行 Git 操作时,它们纳入 Git 版本管理。.tmp/context-runtime/ 保存未完成的执行状态,不纳入 Git。knowledge/structure.yaml 保存共享的页面和来源元数据,以及精简的 processed_scopes;部分更新或构建失败不会推进整个范围的已处理版本。请使用 CLI 调整或回滚工作,而不要直接编辑这些基线。
知识工作区的 package.json 还支持 context.convertVisuals(默认 true):有能力的 Agent 可以把来源中的图表和表格转换为忠实的文本结构;无法保留原意时,则保留原始图片。