Configure documentation corpora, ownership routing, conformance, and gates.
View raw Markdown · llms.txt · For agents
doc-bridge config contract v1
doc-bridge.config.ts (or .js, .mjs, .json, or package.json → docBridge) is the alpha integration point for any project. Layer 0 fields are sufficient to run index, query, and MCP without an LLM.
Reconciliation summaries also expose deterministic diagnosticsByCode and
diagnosticsByStatus maps. They are additive rollups for agents and dashboards;
the canonical diagnostics array remains the source of evidence.
| npm package | @agentskit/doc-bridge |
| CLI binary | ak-docs |
| Config file | doc-bridge.config.ts |
Standalone CLI — not merged into a framework or OS CLI.
Design rules
- Progressive — only
schemaVersion+corpus.agentrequired; everything else defaults sensibly. - Plugin-shaped — doc sites and monorepo layout are plugins, not hardcoded paths.
- No provider in core — adapter config lives under
intelligence, never required. - Deterministic output — paths in config are resolved at build time; no timestamps in index hash input.
- One config per repo — monorepo root config; packages inherit via
routing/ plugin discovery.
Discovery order
doc-bridge.config.ts
doc-bridge.config.mts
doc-bridge.config.js
doc-bridge.config.mjs
doc-bridge.config.json
package.json → "docBridge" field (subset, JSON only)TypeScript/JavaScript configs are static in v0.1 alpha: defineConfig imports are supported, but arbitrary imports are not. YAML config files are planned.
Dynamic-loading coverage is evidence-backed. Literal strings, constant aliases,
parenthesized strings, and string concatenations are resolved without executing
repository code. Runtime-dependent import() and require() expressions remain
partial/not-analyzed, and the coverage entry records representative
file-and-line evidence for each observed loading site (up to the schema limit).
TypeScript shape (authoritative)
import type { DocBridgeConfigV1 } from '@agentskit/doc-bridge/config'
export default {
schemaVersion: 1,
/** Optional display name; defaults to package.json name or directory basename */
project?: { name?: string; root?: string }
/** Agent-readable knowledge (required) */
corpus: {
agent: AgentCorpusConfig
human?: HumanCorpusConfig | HumanCorpusConfig[]
}
/** Where deterministic artifacts are written */
index?: IndexConfig
/** Ownership, intents, change routes — monorepo plugin fills this */
routing?: RoutingConfig
/** CI gate presets */
gates?: GatesConfig
/** CLI + MCP surfaces */
surfaces?: SurfacesConfig
/** Optional: chat, memory, retriever — any provider */
intelligence?: IntelligenceConfig
/** Optional: Playbook / Registry / remote OKF bundles */
federation?: FederationConfig
/** Optional deterministic documentation conformance profiles */
conformance?: ConformanceConfig
/** Optional language analyzers and runtime-wiring coverage */
analysis?: AnalysisConfig
/** Optional reconciliation scope and orphan-document policy */
reconciliation?: ReconciliationConfig
/** Optional resumable workflow state */
workflow?: WorkflowConfig
/** Optional report publication privacy; private is the default */
report?: { privacy?: 'private' | 'anonymized' }
} satisfies DocBridgeConfigV1corpus.agent (required)
Agent corpus = dense markdown for coding agents (OKF or for-agents layout).
type AgentCorpusConfig = {
/** Root directory, relative to project root */
root: string // e.g. 'docs/for-agents' | '.agent-docs' | 'docs'
/** Jump table entrypoint (recommended) */
index?: string // default: '{root}/INDEX.md'
/**
* Glob patterns under root, relative to root.
* Default: ['**/*.md'] excluding INDEX conventions
*/
include?: string[]
exclude?: string[] // default: ['**/node_modules/**', '**/.git/**']
/** OKF frontmatter: require `type` field (soft warn vs hard gate) */
okf?: {
requireType?: boolean // default: false (warn); true in strict preset
allowedTypes?: string[] // optional vocabulary enforcement
}
}Minimal solo project
corpus: {
agent: { root: 'docs' }
}corpus.human (optional)
Human wiki / doc site. Always via plugin — doc-bridge does not ship a site generator.
type HumanCorpusConfig = {
plugin: HumanCorpusPluginId
/** Plugin-specific options (see plugin docs) */
options?: Record<string, unknown>
}
type HumanCorpusPluginId =
| 'plain-markdown' // docs/**/*.md, frontmatter `package`/`module`/`id`
| 'fumadocs' // markdown scan with index routes, (group) slugs, pages allowlists
| 'docusaurus' // markdown scan with id/slug frontmatter + static sidebars.js
| 'mkdocs' // planned
| 'vitepress' // file routes, srcDir/docsDir, optional cleanUrls
| 'starlight' // Astro content routes, slug and draft frontmatter
| 'nextra' // content-directory routes and contentDirBasePath
| 'custom' // path to user plugin moduleVitePress options accept docsDir (also root or srcDir), urlPrefix,
cleanUrls, and up to 64 declarative srcExclude glob patterns. Doc Bridge
uses .html routes unless cleanUrls: true, matching
VitePress routing without loading or executing .vitepress/config.*. Route
rewrites must therefore be reflected in the configured corpus or URL prefix.
Starlight options accept contentDir (also docsDir or root) and
urlPrefix. The adapter reads the standard slug and draft frontmatter,
follows the default filename sluggifier, excludes underscore-prefixed
partials, and never executes astro.config.*. Sites using a custom
docsLoader({ generateId }) should add explicit slug frontmatter so Doc
Bridge can resolve the same public route without executing project code.
Nextra options accept contentDir (also docsDir or root), urlPrefix,
and contentDirBasePath. The adapter maps index.md and index.mdx to the
containing route and uses Doc Bridge package, module, or id frontmatter
as the join key. urlPrefix takes precedence over contentDirBasePath. Point
contentDir at either content or src/content; Doc Bridge never imports or
executes next.config.*, _meta.*, themes, or other project code. This
adapter targets Nextra's content-directory convention; app-router page.mdx
trees are not inferred by this plugin.
Bridge to agent docs
When corpus.human is set, plugins MUST:
- Emit resolvable
humanDocURLs/paths intoAgentHandoff - Support
## Human guidelink validation (gatehuman-guide-links) - Map by stable id (
packageId,moduleId,slug) — config defines the join key
corpus: {
agent: { root: 'docs/for-agents' },
human: {
plugin: 'fumadocs',
options: {
contentDir: 'apps/web/content/docs',
urlPrefix: '/docs', // public path prefix
metaFile: 'meta.json',
},
},
}Multiple human corpora (e.g. marketing + internal):
human: [
{ plugin: 'fumadocs', options: { contentDir: 'apps/web/content/docs', urlPrefix: '/docs' } },
{ plugin: 'plain-markdown', options: { root: 'docs/internal', urlPrefix: null } },
]index (optional)
type IndexConfig = {
/** Output path for DocBridgeIndex JSON */
outFile?: string // default: '.doc-bridge/index.json'
/** Optional llms.txt alongside index */
llmsTxt?: {
enabled?: boolean // default: true
outFile?: string // default: 'llms.txt' at project root
preamble?: string // project-specific intro paragraph
}
/** Optional Self-Describe companion artifact */
capabilities?: {
enabled?: boolean // default: true
outFile?: string // default: '.doc-bridge/capabilities.json'
}
/** Hash algorithm for contentHash field */
contentHash?: 'sha256-normalized-v1' // only algo in v1
}routing (optional — monorepo-first)
Without routing, handoffs are inferred from agent corpus links only. Monorepo plugin populates ownership graph.
type RoutingConfig = {
plugin?: 'pnpm-monorepo' | 'npm-workspaces' | 'yarn-workspaces' | 'nx' | 'pattern-files' | 'custom'
options?: {
/** Workspace globs; default from package manager */
packages?: string[] // e.g. ['packages/*', 'apps/*']
/** Map package id → metadata (auto-discovered if omitted) */
ownership?: Record<string, OwnershipEntry>
/** Curated reading paths for tasks */
intents?: IntentEntry[]
/** "I want to change X" → start here */
changes?: ChangeRouteEntry[]
}
}
type OwnershipEntry = {
path: string // 'packages/auth'
group?: string // logical layer / team
layer?: string // L0–L4 or custom
purpose?: string // one line
checks?: string[] // default gates for this owner
agentDoc?: string // override path; default inferred
humanDoc?: string // filled by human plugin join
}
type IntentEntry = {
id: string // kebab-case
title: string
paths: string[] // read-before-editing list
}
type ChangeRouteEntry = {
id: string // e.g. 'add-api-endpoint'
title: string
startHere: string
relatedPackages?: string[]
}routing.plugin: 'nx' reads project.json and package manifests with an nx
object. It does not load Nx plugins or execute workspace code. Project roots must
resolve inside the configured project root. Declared test targets become Nx test
checks; non-minimal gate presets also include declared lint targets. Explicit
routing.options.ownership remains authoritative. Targets created only at runtime
by Nx plugins are intentionally not inferred by this read-only adapter.
Join keys (agent ↔ human ↔ ownership)
| Entity | Primary key | Human plugin maps via |
|---|---|---|
| Package / module | id (folder name or package.json name) | frontmatter package or path convention |
| Screen / feature | id in screens/ or features/ | MDX slug |
| Flow / recipe | id in flows/ | docs slug |
Plugins document their join convention; gates fail on orphan links.
gates (optional)
type GatesConfig = {
preset?: 'minimal' | 'standard' | 'strict' | 'playbook'
/** Enabled gate ids; merged with preset */
include?: GateId[]
exclude?: GateId[]
/** Gate-specific options */
options?: {
'human-guide-links'?: { strict?: boolean }
'index-freshness'?: { failOnDrift?: boolean }
'okf-type'?: { requireType?: boolean }
'docs-style'?: {
profile?: 'google-dev-docs' | 'playbook-okf' | 'custom'
required?: Array<
| 'title'
| 'purpose'
| 'audience'
| 'task-orientation'
| 'examples'
| 'owner-source'
| 'no-stale-wording'
>
}
}
}
type GateId =
| 'index-freshness'
| 'human-guide-links'
| 'link-rot' // reserved; emits a diagnostic and is not executed
| 'okf-type'
| 'docs-style'
| 'routing-currency' // reserved; emits a diagnostic and is not executed
| 'bootstrap-size' // reserved; emits a diagnostic and is not executed
| 'documentation-standard-v1' // opt-in ecosystem documentation profile| Preset | Gates |
|---|---|
minimal | index-freshness |
standard | + human-guide-links in v0.1 alpha |
strict | + okf-type in v0.1 alpha |
Implemented gates include index-freshness, human-guide-links, okf-type, docs-style, and the opt-in documentation-standard-v1. For v1 compatibility, link-rot, routing-currency, and bootstrap-size remain accepted as reserved IDs; including one emits AK_DOCS_RESERVED_GATE and does not claim that the gate ran. Unknown IDs are rejected.
Structural vs style validation
Alpha gates are deterministic lint checks, not editorial grading:
| Gate | Kind | What it proves |
|---|---|---|
index-freshness | structural | Generated index matches current docs/config |
human-guide-links | structural | Local humanDoc links resolve through configured human-doc adapters |
okf-type | OKF lint | Agent docs have required type: frontmatter when strict/required |
docs-style | style lint | Opt-in deterministic profile checks for title, purpose, audience, examples, owner/source, task orientation, and stale wording |
docs-style supports google-dev-docs, playbook-okf, and custom profiles. It is not part of the default alpha path and does not grade prose quality; it checks for explicit structural signals. LLM critique remains planned optional behavior.
conformance (optional)
Documentation Standard v1 is an opt-in, deterministic ecosystem profile. It validates repository evidence without executing configured commands or making network/model calls.
type ConformanceConfig = {
documentationStandardV1?: {
rawSources?: string[]
contributionPaths?: string[]
metadata?: Array<{ path: string; contains: string[] }>
links?: Array<{ url: string; paths: string[] }>
quickstarts?: Array<{
id: string
doc: string
test: string
command: string
testContains: string[]
}>
visuals?: string[]
diagrams?: Array<{ path: string; contains: string[] }>
ecosystemContract?: {
manifest: string
claims: string
productId: string
}
exceptions?: Array<{
ruleId: DocumentationStandardRuleId
reason: string
approvedBy: string
trackingUrl: string
}>
}
}See Documentation Standard v1 for rule semantics, report status, commands, and the recorded stable-publication HITL decision.
reconciliation (optional)
type ReconciliationConfig = {
/** Semantic comparison level; discovery still preserves raw file relations. */
scope?: 'file' | 'module' | 'package'
/** Observed relation kinds that require documentation declarations. */
requiredRelationKinds?: string[]
/** Limit missing-declaration findings to relations between internal project entities. */
requiredRelationTargets?: 'all' | 'internal'
/** Emit info findings for documentation with no observed package/module join. */
includeOrphanedDocuments?: boolean
}Use scope: 'package' for monorepos where file imports should be compared as package-level architecture evidence. Omit requiredRelationKinds to require all observed kinds; an empty array intentionally disables undocumented-relation findings and must be treated as an explicit exemption.
Use requiredRelationTargets: 'internal' when the repository wants package or module architecture declarations without requiring Markdown to enumerate every external library import. External relations remain in the raw snapshot and report as evidence; they simply do not generate missing-declaration findings.
The reconciliation documentation summary reports package health separately from
relation findings: fresh means the package has coverage documentation and no
known discrepancy; stale means a declared relation conflicts with observed
architecture; missing means no coverage document was found; and unverified
means coverage exists but at least one relevant relation or analyzer boundary
could not be verified. Package-level aggregation preserves the relation
endpoints used for this classification, so an undocumented relation cannot be
reported alongside a falsely fresh package.
The same summary keeps document inventory separate from coverage claims:
documentCount and documentClassificationCounts describe every discovered
Markdown document, while documentedDocumentCount and
documentedDocumentClassificationCounts describe documents that declare a
knowledge relation. The classification keys are analyzer output (for example
agent, human, project, archive, and unclassified); consumers must not
interpret total repository Markdown coverage as agent-corpus coverage. Use the
agent pair when measuring the configured agent documentation surface.
report (optional)
report?: {
/** Replace project identity, names, paths, snippets, and finding text in HTML output. */
privacy?: 'private' | 'anonymized'
}private is the default and keeps local evidence useful for debugging. anonymized is intended for reports shared outside the repository: it preserves counts, relation kinds, topology, and coverage status while removing project-specific identity and evidence content. The generated HTML and every lazy chunk use the same mode.
safety (optional)
type RepositorySafetyConfig = {
/** Additional project-relative glob patterns excluded from repository discovery. */
exclude?: string[]
maxFiles?: number
maxBytes?: number
maxTimeMs?: number
maxMemoryMb?: number
redactSecrets?: boolean
}Discovery always excludes unsafe or generated trees by default, including
.git, node_modules, dist, build, coverage, .doc-bridge, .next,
out, .turbo, .svelte-kit, .mcpb-build, and .mcpb-output, plus common
secret files. safety.exclude adds project-specific patterns; it does not
replace the built-in safety boundary. Excluded files remain outside the
snapshot and are represented by analyzer coverage when relevant.
analysis (optional)
type AnalysisConfig = {
/** Ordered language/framework analyzer plugins. */
plugins?: Array<{
id: string
enabled?: boolean
order?: number
options?: Record<string, unknown>
reason?: string
}>
jsTs?: {
/** Property-access methods considered runtime wiring entry points. */
runtimeWiringMethods?: string[]
/** Additional adapter methods that represent runtime wiring. */
runtimeWiringAdapters?: Array<{ id: string; methods: string[] }>
/** Include test/spec modules in runtime-wiring coverage. Default: false. */
includeTestRuntimeWiring?: boolean
}
}The JS/TS analyzer defaults to register, use, mount, and attach.
Generic APIs such as bind and listen are intentionally opt-in to avoid
classifying ordinary function binding and server startup as architecture.
When a configured method receives an identifier bound to a
static import, Doc Bridge records a runtime-wiring relation with
metadata.detection: 'runtime-wiring-static'. Reflective, computed, or
otherwise unbound targets remain explicit not-analyzed coverage entries.
Dynamic import() and require() targets are resolved when their specifier is
a literal, a const string binding, a parenthesized static expression, or a
concatenation of other statically known strings. Expressions that depend on
runtime values remain explicit not-analyzed coverage entries; Doc Bridge does
not execute repository code to guess their targets.
Test/spec modules are excluded from this signal by default because their
registrations usually construct fixtures rather than production architecture;
set includeTestRuntimeWiring: true when test wiring is part of the contract.
This keeps runtime behavior useful without claiming that arbitrary dependency
injection or reflection was resolved. Analyzer plugins must implement the
versioned contract in docs/spec/analyzer-plugin-v1.md; malformed or
unsupported output remains explicit not-analyzed evidence.
workflow.stateDir optionally relocates the content-addressed workflow
artifacts. Runs are resumable and idempotent; pipeline and analyzer versions
are part of the run identity.
surfaces (optional)
type SurfacesConfig = {
cli?: {
/** Published binary name (package.json bin) */
bin?: string // default: 'ak-docs'
/** Default output: json | text */
defaultFormat?: 'json' | 'text'
}
mcp?: {
enabled?: boolean // default: true
/** Tool ids to expose; default: core set */
tools?: McpToolId[]
transport?: 'stdio' | 'http'
http?: { port?: number; path?: string }
}
}
type McpToolId =
| 'handoff.resolve'
| 'doc.search' // deterministic index search
| 'doc.get'
| 'gate.status'
| 'playbook.pattern.get' // requires federationintelligence (optional — any provider)
Absent intelligence = Layer 0 only. AgentsKit is the reference implementation of this block.
type IntelligenceConfig = {
/** When false, ignore all other intelligence fields */
enabled?: boolean // default: false
adapter?: {
/** Provider id or path to custom adapter module */
provider: 'openai' | 'anthropic' | 'ollama' | 'openrouter' | 'custom'
model?: string
/** Env var name for API key; never inline secrets in config */
apiKeyEnv?: string
baseUrl?: string
options?: Record<string, unknown>
}
chat?: {
enabled?: boolean
/** Corpus scopes for retrieval */
sources?: ('agent' | 'human' | 'federation')[]
/** Prefer deterministic handoff before RAG when confidence high */
handoffFirst?: boolean // default: true
}
retriever?: {
enabled?: boolean
/** local | remote | bm25-only */
mode?: 'local' | 'remote' | 'bm25'
embedModel?: string
chunkSize?: number
}
memory?: {
enabled?: boolean
adapters?: MemoryAdapterId[]
ingestDir?: string // default: '.agent-memory'
classify?: boolean // default: false — opt-in
promote?: {
enabled?: boolean
targets?: ('agent' | 'human' | 'agents-md')[]
requireApproval?: boolean // default: true
}
}
/** Reference runtime; custom path for non-AgentsKit engines later */
runtime?: 'agentskit' | 'custom'
runtimeModule?: string
registry?: {
enabled?: boolean
agentId?: string
agentRoot?: string
runnerModule?: string
cli?: {
/** Executable name or absolute path; arguments are passed without a shell. */
command: string
args?: string[]
}
deterministic?: boolean
maxInputBytes?: number
timeoutMs?: number
maxTokens?: number
maxResponseBytes?: number
maxConcurrency?: number
}
}
type MemoryAdapterId =
| 'playbook-memory' // .agent-memory/MEMORY.md layout
| 'cursor-rules' // .cursor/rules/*.mdc
| 'session-export' // manual JSON/md drop folder
| 'bootstrap-delta' // git diff on AGENTS.mdRegistry agents are advisory and must come from the AgentsKit Registry. The
adapter redacts secrets, validates the proposal contract, bounds execution and
response size, and requires human approval before any change is applied. The
default agent is ecosystem-doc-bridge-corpus-scanner; compatible Registry
agents may be selected explicitly.
federation (optional — ecosystem)
Not required for any project. Private dogfood enables this profile to validate scale; public consumers do not depend on private repos.
type FederationConfig = {
enabled?: boolean
sources?: FederationSource[]
}
type FederationSource = {
id: string // 'playbook' | 'agentskit' | custom
llmsTxt?: string // URL or local path
rawBaseUrl?: string // e.g. 'https://playbook.agentskit.io/raw'
includeInRetriever?: boolean
includeInChat?: boolean
}Layer 0 exports a local retriever helper over DocBridgeIndex:
import { createDocBridgeRetriever } from '@agentskit/doc-bridge'
const retriever = createDocBridgeRetriever(index, { property: 'my-project' })
const chunks = retriever.retrieve('auth ownership')Chunk keys are stable: {property}:{type}:{id}. Deterministic CLI search and exact handoff resolution stay first; semantic/RAG runtimes can inject this retriever and add federated sources later.
AgentHandoff emission rules
When ak-docs query <target> --agent runs:
type AgentHandoffV1 = {
type: 'agent-handoff'
schemaVersion: 1
source: string // index.outFile path
target: { type: TargetType; id: string }
startHere: string
readBeforeEditing: string[]
editRoots: string[]
checks: string[]
humanDoc?: string | null
playbookPatterns?: string[] // only if federation enabled
notes: string[]
}
type TargetType =
| 'package' | 'module' | 'app'
| 'screen' | 'flow' | 'component'
| 'intent' | 'change'
| 'search' // --agent on search picks best matchMerge precedence (later wins):
- Agent corpus frontmatter (
checks,humanDoc) routing.ownership[id]gates.presetdefault checks- Global
handoff.defaults(if set in future minor version)
Example configs
1. Solo library (minimal)
// doc-bridge.config.ts
import { defineConfig } from '@agentskit/doc-bridge'
export default defineConfig({
schemaVersion: 1,
corpus: {
agent: {
root: 'docs',
index: 'docs/INDEX.md',
},
},
})2. pnpm monorepo + ownership
import { defineConfig } from '@agentskit/doc-bridge'
export default defineConfig({
schemaVersion: 1,
corpus: {
agent: { root: 'docs/for-agents' },
},
routing: {
plugin: 'pnpm-monorepo',
options: {
packages: ['packages/*', 'apps/*'],
},
},
gates: { preset: 'standard' },
})3. Monorepo + Fumadocs (standard profile)
import { defineConfig } from '@agentskit/doc-bridge'
export default defineConfig({
schemaVersion: 1,
corpus: {
agent: { root: 'docs/for-agents' },
human: {
plugin: 'fumadocs',
options: {
contentDir: 'apps/web/content/docs',
urlPrefix: '/docs',
},
},
},
routing: { plugin: 'pnpm-monorepo' },
gates: { preset: 'standard' },
intelligence: {
enabled: true,
adapter: { provider: 'ollama', model: 'llama3', apiKeyEnv: '' },
chat: { enabled: true, handoffFirst: true },
},
})4. Docusaurus + optional memory
import { defineConfig } from '@agentskit/doc-bridge'
export default defineConfig({
schemaVersion: 1,
corpus: {
agent: { root: '.agent-docs' },
human: {
plugin: 'docusaurus',
options: {
docsDir: 'website/docs',
sidebarsFile: 'website/sidebars.js',
urlPrefix: '/docs',
},
},
},
intelligence: {
enabled: true,
adapter: { provider: 'openrouter', model: 'openai/gpt-4o-mini', apiKeyEnv: 'OPENROUTER_API_KEY' },
chat: { enabled: true, sources: ['agent', 'human'] },
memory: {
enabled: true,
adapters: ['cursor-rules', 'playbook-memory'],
classify: true,
promote: { enabled: true, requireApproval: true },
},
},
})5. JSON config (no TypeScript)
{
"schemaVersion": 1,
"corpus": {
"agent": { "root": "docs/for-agents" }
},
"routing": {
"plugin": "npm-workspaces"
},
"gates": { "preset": "minimal" }
}CLI mapping
| Command | Config sections used |
|---|---|
ak-docs init | scaffolds minimal corpus.agent + optional plugin prompt |
ak-docs index | corpus, routing, index, plugins |
ak-docs query <t> --agent | index + routing + handoff merge |
ak-docs search <q> | index |
ak-docs retrieve <q> | index + federation |
ak-docs gate run | gates |
ak-docs conformance run documentation-standard-v1 | corpus, routing, index, conformance |
ak-docs mcp | surfaces.mcp |
ak-docs chat | planned; intelligence.* |
ak-docs memory ingest | deterministic local ingest; MemoryCandidate[] |
ak-docs memory classify | deterministic route classifier |
ak-docs memory promote | draft promotion + safety scan |
ak-docs registry topology | doc-curator topology |
ak-docs playbook draft | draft Playbook feedback payload |
Validation
- Config validated with Zod at CLI startup (
ak-docs validate-config). - Unknown
schemaVersion→ hard error with migration link. - Unknown plugin id → hard error listing built-in +
custompath. intelligence.enabled: truewithoutadapter→ warn + chat/memory subcommands disabled.
Versioning
| Version | Scope |
|---|---|
| v1 | This document. Additive fields only in v1.x. |
| v2 | Breaking changes require schemaVersion: 2 + codemod. |
See also
The AgentsKit ecosystem