@agentskit/doc-bridge 0.1.0-alpha.1 → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +1 -1
  3. package/dist/cli/program.js +283 -105
  4. package/dist/cli/program.js.map +1 -1
  5. package/dist/config/index.d.ts +1 -1
  6. package/dist/config/index.js +6 -3
  7. package/dist/config/index.js.map +1 -1
  8. package/dist/{index-CD_zmKXf.d.ts → index-CPUJbTbg.d.ts} +19 -10
  9. package/dist/index.d.ts +5 -4
  10. package/dist/index.js +278 -100
  11. package/dist/index.js.map +1 -1
  12. package/docs/DOGFOOD.md +92 -0
  13. package/package.json +27 -9
  14. package/scripts/prepare.mjs +44 -0
  15. package/src/cli/program.ts +933 -0
  16. package/src/config/defaults.ts +63 -0
  17. package/src/config/define-config.ts +6 -0
  18. package/src/config/index.ts +15 -0
  19. package/src/config/load-config.ts +138 -0
  20. package/src/config/schema.ts +294 -0
  21. package/src/federation/llms.ts +145 -0
  22. package/src/gates/run-gates.ts +274 -0
  23. package/src/index-builder/build-handoffs.ts +217 -0
  24. package/src/index-builder/build-index.ts +137 -0
  25. package/src/index-builder/capabilities.ts +37 -0
  26. package/src/index-builder/content-hash.ts +19 -0
  27. package/src/index-builder/human-adapters/core.ts +100 -0
  28. package/src/index-builder/human-adapters/docusaurus.ts +113 -0
  29. package/src/index-builder/human-adapters/fumadocs.ts +70 -0
  30. package/src/index-builder/human-adapters/index.ts +52 -0
  31. package/src/index-builder/human-adapters/plain-markdown.ts +10 -0
  32. package/src/index-builder/llms-txt.ts +19 -0
  33. package/src/index-builder/plugins/human-markdown.ts +7 -0
  34. package/src/index-builder/plugins/pnpm-monorepo.ts +72 -0
  35. package/src/index-builder/scan-corpus.ts +181 -0
  36. package/src/index.ts +120 -0
  37. package/src/intelligence/adapter.ts +90 -0
  38. package/src/intelligence/chat.ts +148 -0
  39. package/src/intelligence/peers.ts +59 -0
  40. package/src/intelligence/rag.ts +98 -0
  41. package/src/lib/glob-expand.ts +33 -0
  42. package/src/lib/markdown.ts +90 -0
  43. package/src/lib/package-manager.ts +104 -0
  44. package/src/lib/paths.ts +6 -0
  45. package/src/lib/walk.ts +45 -0
  46. package/src/mcp/server.ts +276 -0
  47. package/src/memory/ingest.ts +51 -0
  48. package/src/memory/pipeline.ts +119 -0
  49. package/src/query/load-index.ts +25 -0
  50. package/src/query/query.ts +142 -0
  51. package/src/query/search.ts +58 -0
  52. package/src/retriever/doc-bridge-retriever.ts +62 -0
  53. package/src/schemas/agent-handoff.ts +82 -0
  54. package/src/schemas/doc-bridge-index.ts +106 -0
  55. package/src/schemas/json-schemas.ts +156 -0
  56. package/src/schemas/memory-candidate.ts +37 -0
  57. package/src/shims/agentskit-peers.d.ts +80 -0
  58. package/src/validate.ts +67 -0
  59. package/src/version.ts +1 -0
  60. package/tsconfig.json +21 -0
  61. package/tsup.config.ts +15 -0
@@ -0,0 +1,142 @@
1
+ import type { DocBridgeConfigV1 } from '../config/schema.js'
2
+ import {
3
+ normalizeAgentHandoff,
4
+ type AgentHandoffV1,
5
+ type AgentSearchV1,
6
+ } from '../schemas/agent-handoff.js'
7
+ import type { DocBridgeIndexV1 } from '../schemas/doc-bridge-index.js'
8
+ import { searchIndex } from './search.js'
9
+
10
+ export type QueryKind = 'package' | 'ownership' | 'intent' | 'change' | 'search'
11
+
12
+ export type QueryRequest = {
13
+ readonly kind: QueryKind
14
+ readonly id?: string
15
+ readonly term?: string
16
+ readonly agent?: boolean
17
+ }
18
+
19
+ export type QueryResult =
20
+ | { readonly type: 'package' | 'ownership' | 'intent' | 'change' | 'search'; readonly data: unknown }
21
+ | AgentHandoffV1
22
+ | AgentSearchV1
23
+
24
+ const handoffForPackage = (
25
+ index: DocBridgeIndexV1,
26
+ id: string,
27
+ config: DocBridgeConfigV1,
28
+ ): AgentHandoffV1 => {
29
+ const fromIndex = index.handoffs?.[id]
30
+ if (fromIndex) return normalizeAgentHandoff(fromIndex)
31
+
32
+ const owner = index.lookup?.ownership?.[id]
33
+ if (!owner) throw new Error(`Unknown package/ownership id "${id}". Try: ak-docs list packages`)
34
+
35
+ return normalizeAgentHandoff({
36
+ type: 'agent-handoff',
37
+ source: config.index?.outFile ?? '.doc-bridge/index.json',
38
+ target: {
39
+ type: 'package',
40
+ id,
41
+ path: owner.path,
42
+ ...(owner.group ? { group: owner.group } : {}),
43
+ ...(owner.layer ? { layer: owner.layer } : {}),
44
+ },
45
+ startHere: owner.agentDoc ?? config.corpus.agent.index ?? '',
46
+ readBeforeEditing: [owner.agentDoc, 'AGENTS.md'].filter(Boolean),
47
+ editRoots: [owner.path],
48
+ checks: [...owner.checks],
49
+ ...(owner.humanDoc ? { humanDoc: owner.humanDoc } : {}),
50
+ notes: owner.purpose ? [owner.purpose] : [],
51
+ })
52
+ }
53
+
54
+ export const runQuery = (
55
+ index: DocBridgeIndexV1,
56
+ config: DocBridgeConfigV1,
57
+ req: QueryRequest,
58
+ ): QueryResult => {
59
+ if (req.kind === 'search') {
60
+ const term = req.term ?? req.id ?? ''
61
+ const matches = searchIndex(index, term)
62
+ if (req.agent) {
63
+ const payload: AgentSearchV1 = {
64
+ type: 'agent-search',
65
+ schemaVersion: 1,
66
+ source: config.index?.outFile ?? '.doc-bridge/index.json',
67
+ term,
68
+ count: matches.length,
69
+ bestMatch: matches[0]
70
+ ? {
71
+ type: matches[0].type,
72
+ id: matches[0].id,
73
+ path: matches[0].path,
74
+ ...(matches[0].summary ? { summary: matches[0].summary } : {}),
75
+ score: matches[0].score,
76
+ }
77
+ : null,
78
+ matches: matches.slice(0, 8).map((m) => ({
79
+ type: m.type,
80
+ id: m.id,
81
+ path: m.path,
82
+ ...(m.summary ? { summary: m.summary } : {}),
83
+ score: m.score,
84
+ })),
85
+ nextCommands: [...new Set(matches.slice(0, 5).map((m) =>
86
+ m.type === 'ownership' || index.lookup?.ownership?.[m.id]
87
+ ? `ak-docs query ownership ${m.id} --agent`
88
+ : 'ak-docs list knowledge --text',
89
+ ))],
90
+ }
91
+ return payload
92
+ }
93
+ return { type: 'search', data: { term, count: matches.length, matches } }
94
+ }
95
+
96
+ const id = req.id
97
+ if (!id) throw new Error(`Missing id for query kind "${req.kind}"`)
98
+
99
+ if (req.kind === 'package' || req.kind === 'ownership') {
100
+ if (req.agent) return handoffForPackage(index, id, config)
101
+ const owner = index.lookup?.ownership?.[id]
102
+ return { type: req.kind, data: owner ?? index.handoffs?.[id] ?? null }
103
+ }
104
+
105
+ if (req.kind === 'intent') {
106
+ const intent = index.lookup?.intents?.[id]
107
+ if (!intent) throw new Error(`Unknown intent "${id}"`)
108
+ if (req.agent) {
109
+ return normalizeAgentHandoff({
110
+ type: 'agent-handoff',
111
+ source: config.index?.outFile ?? '.doc-bridge/index.json',
112
+ target: { type: 'intent', id },
113
+ startHere: intent.paths[0] ?? '',
114
+ readBeforeEditing: [...intent.paths],
115
+ editRoots: [],
116
+ checks: [],
117
+ notes: [intent.title],
118
+ })
119
+ }
120
+ return { type: 'intent', data: intent }
121
+ }
122
+
123
+ if (req.kind === 'change') {
124
+ const change = index.lookup?.changes?.[id]
125
+ if (!change) throw new Error(`Unknown change route "${id}"`)
126
+ if (req.agent) {
127
+ return normalizeAgentHandoff({
128
+ type: 'agent-handoff',
129
+ source: config.index?.outFile ?? '.doc-bridge/index.json',
130
+ target: { type: 'change', id },
131
+ startHere: change.startHere,
132
+ readBeforeEditing: ['AGENTS.md', config.corpus.agent.index ?? ''].filter(Boolean),
133
+ editRoots: [change.startHere],
134
+ checks: [],
135
+ notes: [change.title],
136
+ })
137
+ }
138
+ return { type: 'change', data: change }
139
+ }
140
+
141
+ throw new Error(`Unsupported query kind: ${req.kind as string}`)
142
+ }
@@ -0,0 +1,58 @@
1
+ import type { DocBridgeIndexV1 } from '../schemas/doc-bridge-index.js'
2
+
3
+ export type SearchMatch = {
4
+ readonly type: string
5
+ readonly id: string
6
+ readonly path: string
7
+ readonly summary?: string
8
+ readonly score: number
9
+ }
10
+
11
+ const tokenize = (value: string): string[] =>
12
+ value
13
+ .toLowerCase()
14
+ .split(/[^a-z0-9]+/)
15
+ .filter((t) => t.length >= 2)
16
+
17
+ export const searchIndex = (index: DocBridgeIndexV1, term: string, limit = 20): SearchMatch[] => {
18
+ const tokens = tokenize(term)
19
+ if (!tokens.length) return []
20
+
21
+ const matches: SearchMatch[] = []
22
+
23
+ for (const entry of index.knowledge) {
24
+ const hay = `${entry.id} ${entry.title} ${entry.description ?? ''} ${entry.path}`.toLowerCase()
25
+ let score = 0
26
+ for (const token of tokens) {
27
+ if (hay.includes(token)) score += token.length
28
+ }
29
+ if (score > 0) {
30
+ matches.push({
31
+ type: 'knowledge',
32
+ id: entry.id,
33
+ path: entry.path,
34
+ ...(entry.description ? { summary: entry.description } : {}),
35
+ score,
36
+ })
37
+ }
38
+ }
39
+
40
+ for (const [id, owner] of Object.entries(index.lookup?.ownership ?? {})) {
41
+ const hay = `${id} ${owner.path} ${owner.purpose ?? ''} ${owner.group ?? ''}`.toLowerCase()
42
+ let score = 0
43
+ for (const token of tokens) {
44
+ if (hay.includes(token)) score += token.length * 2
45
+ }
46
+ if (score > 0) {
47
+ matches.push({
48
+ type: 'ownership',
49
+ id,
50
+ path: owner.agentDoc ?? owner.path,
51
+ ...(owner.purpose ? { summary: owner.purpose } : {}),
52
+ score,
53
+ })
54
+ }
55
+ }
56
+
57
+ return matches.sort((a, b) => b.score - a.score).slice(0, limit)
58
+ }
@@ -0,0 +1,62 @@
1
+ import type { DocBridgeIndexV1 } from '../schemas/doc-bridge-index.js'
2
+ import { searchIndex } from '../query/search.js'
3
+
4
+ export type DocBridgeRetrieverOptions = {
5
+ readonly property?: string
6
+ readonly limit?: number
7
+ }
8
+
9
+ export type DocBridgeRetrievedChunk = {
10
+ readonly chunkKey: string
11
+ readonly property: string
12
+ readonly type: string
13
+ readonly id: string
14
+ readonly path: string
15
+ readonly title?: string
16
+ readonly summary?: string
17
+ readonly score: number
18
+ }
19
+
20
+ export type DocBridgeRetriever = {
21
+ readonly retrieve: (
22
+ query: string,
23
+ options?: Pick<DocBridgeRetrieverOptions, 'limit'>,
24
+ ) => DocBridgeRetrievedChunk[]
25
+ }
26
+
27
+ const chunkKey = (property: string, type: string, id: string): string =>
28
+ `${property}:${type}:${id}`
29
+
30
+ export const retrieveDocBridgeChunks = (
31
+ index: DocBridgeIndexV1,
32
+ query: string,
33
+ options: DocBridgeRetrieverOptions = {},
34
+ ): DocBridgeRetrievedChunk[] => {
35
+ const property = options.property ?? index.project?.name ?? 'local'
36
+ const limit = options.limit ?? 8
37
+
38
+ return searchIndex(index, query, limit).map((match) => {
39
+ const knowledge = index.knowledge.find((entry) => entry.id === match.id && entry.path === match.path)
40
+ const owner = index.lookup?.ownership?.[match.id]
41
+ const type = match.type === 'ownership' ? 'ownership' : (knowledge?.type ?? match.type)
42
+ const summary = match.summary ?? owner?.purpose
43
+ return {
44
+ chunkKey: chunkKey(property, type, match.id),
45
+ property,
46
+ type,
47
+ id: match.id,
48
+ path: match.path,
49
+ ...(knowledge?.title ? { title: knowledge.title } : {}),
50
+ ...(summary ? { summary } : {}),
51
+ score: match.score,
52
+ }
53
+ })
54
+ }
55
+
56
+ export const createDocBridgeRetriever = (
57
+ index: DocBridgeIndexV1,
58
+ options: DocBridgeRetrieverOptions = {},
59
+ ): DocBridgeRetriever => ({
60
+ retrieve: (query, req = {}) =>
61
+ retrieveDocBridgeChunks(index, query, { ...options, ...req }),
62
+ })
@@ -0,0 +1,82 @@
1
+ import { z } from 'zod'
2
+
3
+ export const HANDOFF_SCHEMA_VERSION = 1 as const
4
+
5
+ export const HandoffTargetTypeSchema = z.enum([
6
+ 'package',
7
+ 'module',
8
+ 'app',
9
+ 'screen',
10
+ 'flow',
11
+ 'component',
12
+ 'intent',
13
+ 'change',
14
+ 'search',
15
+ ])
16
+
17
+ export type HandoffTargetType = z.infer<typeof HandoffTargetTypeSchema>
18
+
19
+ export const HandoffTargetSchema = z
20
+ .object({
21
+ type: HandoffTargetTypeSchema,
22
+ id: z.string().min(1).max(256),
23
+ path: z.string().min(1).max(512).optional(),
24
+ group: z.string().min(1).max(128).optional(),
25
+ layer: z.string().min(1).max(32).optional(),
26
+ })
27
+ .strict()
28
+
29
+ export type HandoffTarget = z.infer<typeof HandoffTargetSchema>
30
+
31
+ /** v1 — canonical AgentHandoff. Legacy payloads may omit schemaVersion. */
32
+ export const AgentHandoffV1Schema = z
33
+ .object({
34
+ type: z.literal('agent-handoff'),
35
+ schemaVersion: z.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
36
+ source: z.string().min(1).max(512),
37
+ target: HandoffTargetSchema,
38
+ startHere: z.string().min(1).max(512),
39
+ readBeforeEditing: z.array(z.string().min(1).max(512)).max(64),
40
+ editRoots: z.array(z.string().min(1).max(512)).max(32),
41
+ checks: z.array(z.string().min(1).max(256)).max(32),
42
+ humanDoc: z.string().min(1).max(512).nullable().optional(),
43
+ playbookPatterns: z.array(z.string().url()).max(16).optional(),
44
+ notes: z.array(z.string().min(1).max(1024)).max(16),
45
+ })
46
+ .strict()
47
+
48
+ export type AgentHandoffV1 = z.infer<typeof AgentHandoffV1Schema>
49
+
50
+ /** Accept legacy handoffs without schemaVersion. */
51
+ export const AgentHandoffLegacySchema = AgentHandoffV1Schema.omit({ schemaVersion: true }).extend({
52
+ schemaVersion: z.literal(HANDOFF_SCHEMA_VERSION).optional(),
53
+ })
54
+
55
+ export const AgentSearchMatchSchema = z
56
+ .object({
57
+ type: z.string().min(1).max(64),
58
+ id: z.string().min(1).max(256),
59
+ path: z.string().min(1).max(512),
60
+ summary: z.string().max(2048).optional(),
61
+ score: z.number().optional(),
62
+ refs: z.number().int().nonnegative().optional(),
63
+ })
64
+ .strict()
65
+
66
+ export const AgentSearchV1Schema = z
67
+ .object({
68
+ type: z.literal('agent-search'),
69
+ schemaVersion: z.literal(HANDOFF_SCHEMA_VERSION).default(HANDOFF_SCHEMA_VERSION),
70
+ source: z.string().min(1).max(512),
71
+ term: z.string().min(1).max(512),
72
+ count: z.number().int().nonnegative(),
73
+ bestMatch: AgentSearchMatchSchema.nullable(),
74
+ matches: z.array(AgentSearchMatchSchema).max(32),
75
+ nextCommands: z.array(z.string().min(1).max(512)).max(16),
76
+ })
77
+ .strict()
78
+
79
+ export type AgentSearchV1 = z.infer<typeof AgentSearchV1Schema>
80
+
81
+ export const normalizeAgentHandoff = (input: unknown): AgentHandoffV1 =>
82
+ AgentHandoffV1Schema.parse(AgentHandoffLegacySchema.parse(input))
@@ -0,0 +1,106 @@
1
+ import { z } from 'zod'
2
+
3
+ import { AgentHandoffLegacySchema } from './agent-handoff.js'
4
+
5
+ export const INDEX_SCHEMA_VERSION = 1 as const
6
+
7
+ export const ContentHashAlgoSchema = z.literal('sha256-normalized-v1')
8
+
9
+ export const EcosystemPropertySchema = z
10
+ .object({
11
+ id: z.string().min(1).max(64),
12
+ name: z.string().min(1).max(128),
13
+ url: z.string().url().optional(),
14
+ llms: z.string().url().optional(),
15
+ })
16
+ .strict()
17
+
18
+ export const KnowledgeEntrySchema = z
19
+ .object({
20
+ id: z.string().min(1).max(256),
21
+ type: z.string().min(1).max(128),
22
+ title: z.string().min(1).max(256),
23
+ path: z.string().min(1).max(512),
24
+ description: z.string().max(1024).optional(),
25
+ links: z.array(z.string().min(1).max(512)).max(64).optional(),
26
+ tags: z.array(z.string().min(1).max(64)).max(32).optional(),
27
+ })
28
+ .strict()
29
+
30
+ export const CapabilityRefSchema = z
31
+ .object({
32
+ id: z.string().min(1).max(256),
33
+ kind: z.string().min(1).max(64),
34
+ description: z.string().max(512).optional(),
35
+ })
36
+ .strict()
37
+
38
+ export const OwnershipRecordSchema = z
39
+ .object({
40
+ id: z.string().min(1).max(256),
41
+ path: z.string().min(1).max(512),
42
+ group: z.string().min(1).max(128).optional(),
43
+ layer: z.string().min(1).max(32).optional(),
44
+ purpose: z.string().max(1024).optional(),
45
+ checks: z.array(z.string().min(1).max(256)).max(32),
46
+ agentDoc: z.string().min(1).max(512).optional(),
47
+ humanDoc: z.string().min(1).max(512).optional(),
48
+ readme: z.string().min(1).max(512).optional(),
49
+ })
50
+ .strict()
51
+
52
+ export const IndexLookupSchema = z
53
+ .object({
54
+ packages: z.array(z.string().min(1).max(256)).max(2_000),
55
+ ownership: z.record(z.string().min(1).max(256), OwnershipRecordSchema).optional(),
56
+ intents: z
57
+ .record(
58
+ z.string().min(1).max(128),
59
+ z
60
+ .object({
61
+ id: z.string().min(1).max(128),
62
+ title: z.string().min(1).max(256),
63
+ paths: z.array(z.string().min(1).max(512)).max(32),
64
+ })
65
+ .strict(),
66
+ )
67
+ .optional(),
68
+ changes: z
69
+ .record(
70
+ z.string().min(1).max(128),
71
+ z
72
+ .object({
73
+ id: z.string().min(1).max(128),
74
+ title: z.string().min(1).max(256),
75
+ startHere: z.string().min(1).max(512),
76
+ relatedPackages: z.array(z.string().min(1).max(256)).max(32).optional(),
77
+ })
78
+ .strict(),
79
+ )
80
+ .optional(),
81
+ })
82
+ .strict()
83
+
84
+ export const DocBridgeIndexV1Schema = z
85
+ .object({
86
+ schemaVersion: z.literal(INDEX_SCHEMA_VERSION),
87
+ contentHash: z.string().regex(/^[a-f0-9]{64}$/),
88
+ contentHashAlgo: ContentHashAlgoSchema,
89
+ generatedAt: z.string().datetime().optional(),
90
+ project: z
91
+ .object({
92
+ name: z.string().min(1).max(128),
93
+ root: z.string().min(1).max(512).optional(),
94
+ })
95
+ .strict()
96
+ .optional(),
97
+ properties: z.array(EcosystemPropertySchema).max(16).optional(),
98
+ knowledge: z.array(KnowledgeEntrySchema).max(10_000),
99
+ capabilities: z.array(CapabilityRefSchema).max(5_000).optional(),
100
+ handoffs: z.record(z.string().min(1).max(256), AgentHandoffLegacySchema).optional(),
101
+ lookup: IndexLookupSchema.optional(),
102
+ })
103
+ .strict()
104
+
105
+ export type DocBridgeIndexV1 = z.infer<typeof DocBridgeIndexV1Schema>
106
+ export type KnowledgeEntry = z.infer<typeof KnowledgeEntrySchema>
@@ -0,0 +1,156 @@
1
+ type JsonSchema = {
2
+ readonly [key: string]: unknown
3
+ }
4
+
5
+ const stringArray = (maxItems: number): JsonSchema => ({
6
+ type: 'array',
7
+ items: { type: 'string', minLength: 1 },
8
+ maxItems,
9
+ })
10
+
11
+ export const AgentHandoffV1JsonSchema = {
12
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
13
+ $id: 'https://agentskit.io/schemas/doc-bridge/agent-handoff-v1.schema.json',
14
+ title: 'AgentHandoff v1',
15
+ type: 'object',
16
+ additionalProperties: false,
17
+ required: [
18
+ 'type',
19
+ 'schemaVersion',
20
+ 'source',
21
+ 'target',
22
+ 'startHere',
23
+ 'readBeforeEditing',
24
+ 'editRoots',
25
+ 'checks',
26
+ 'notes',
27
+ ],
28
+ properties: {
29
+ type: { const: 'agent-handoff' },
30
+ schemaVersion: { const: 1 },
31
+ source: { type: 'string', minLength: 1, maxLength: 512 },
32
+ target: {
33
+ type: 'object',
34
+ additionalProperties: false,
35
+ required: ['type', 'id'],
36
+ properties: {
37
+ type: {
38
+ enum: ['package', 'module', 'app', 'screen', 'flow', 'component', 'intent', 'change', 'search'],
39
+ },
40
+ id: { type: 'string', minLength: 1, maxLength: 256 },
41
+ path: { type: 'string', minLength: 1, maxLength: 512 },
42
+ group: { type: 'string', minLength: 1, maxLength: 128 },
43
+ layer: { type: 'string', minLength: 1, maxLength: 32 },
44
+ },
45
+ },
46
+ startHere: { type: 'string', minLength: 1, maxLength: 512 },
47
+ readBeforeEditing: stringArray(64),
48
+ editRoots: stringArray(32),
49
+ checks: stringArray(32),
50
+ humanDoc: { anyOf: [{ type: 'string', minLength: 1, maxLength: 512 }, { type: 'null' }] },
51
+ playbookPatterns: { type: 'array', items: { type: 'string', format: 'uri' }, maxItems: 16 },
52
+ notes: stringArray(16),
53
+ },
54
+ } as const satisfies JsonSchema
55
+
56
+ export const MemoryCandidateV1JsonSchema = {
57
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
58
+ $id: 'https://agentskit.io/schemas/doc-bridge/memory-candidate-v1.schema.json',
59
+ title: 'MemoryCandidate v1',
60
+ type: 'object',
61
+ additionalProperties: false,
62
+ required: ['schemaVersion', 'id', 'source', 'fact', 'suggestedType', 'confidence', 'references'],
63
+ properties: {
64
+ schemaVersion: { const: 1 },
65
+ id: { type: 'string', minLength: 1, maxLength: 256 },
66
+ source: { enum: ['cursor', 'claude', 'codex', 'copilot', 'agent-memory', 'manual'] },
67
+ rawPath: { type: 'string', minLength: 1, maxLength: 512 },
68
+ fact: { type: 'string', minLength: 1, maxLength: 8000 },
69
+ why: { type: 'string', maxLength: 4000 },
70
+ howToApply: { type: 'string', maxLength: 4000 },
71
+ suggestedType: { enum: ['user', 'feedback', 'project', 'reference', 'unknown'] },
72
+ confidence: { type: 'number', minimum: 0, maximum: 1 },
73
+ references: stringArray(64),
74
+ },
75
+ } as const satisfies JsonSchema
76
+
77
+ export const DocBridgeIndexV1JsonSchema = {
78
+ $schema: 'https://json-schema.org/draft/2020-12/schema',
79
+ $id: 'https://agentskit.io/schemas/doc-bridge/doc-bridge-index-v1.schema.json',
80
+ title: 'DocBridgeIndex v1',
81
+ type: 'object',
82
+ additionalProperties: false,
83
+ required: ['schemaVersion', 'contentHash', 'contentHashAlgo', 'knowledge'],
84
+ properties: {
85
+ schemaVersion: { const: 1 },
86
+ contentHash: { type: 'string', pattern: '^[a-f0-9]{64}$' },
87
+ contentHashAlgo: { const: 'sha256-normalized-v1' },
88
+ generatedAt: { type: 'string', format: 'date-time' },
89
+ project: {
90
+ type: 'object',
91
+ additionalProperties: false,
92
+ properties: {
93
+ name: { type: 'string', minLength: 1, maxLength: 128 },
94
+ root: { type: 'string', minLength: 1, maxLength: 512 },
95
+ },
96
+ },
97
+ properties: {
98
+ type: 'array',
99
+ maxItems: 16,
100
+ items: {
101
+ type: 'object',
102
+ additionalProperties: false,
103
+ required: ['id', 'name'],
104
+ properties: {
105
+ id: { type: 'string', minLength: 1, maxLength: 64 },
106
+ name: { type: 'string', minLength: 1, maxLength: 128 },
107
+ url: { type: 'string', format: 'uri' },
108
+ llms: { type: 'string', format: 'uri' },
109
+ },
110
+ },
111
+ },
112
+ knowledge: {
113
+ type: 'array',
114
+ maxItems: 10000,
115
+ items: {
116
+ type: 'object',
117
+ additionalProperties: false,
118
+ required: ['id', 'type', 'title', 'path'],
119
+ properties: {
120
+ id: { type: 'string', minLength: 1, maxLength: 256 },
121
+ type: { type: 'string', minLength: 1, maxLength: 128 },
122
+ title: { type: 'string', minLength: 1, maxLength: 256 },
123
+ path: { type: 'string', minLength: 1, maxLength: 512 },
124
+ description: { type: 'string', maxLength: 1024 },
125
+ links: stringArray(64),
126
+ tags: stringArray(32),
127
+ },
128
+ },
129
+ },
130
+ capabilities: {
131
+ type: 'array',
132
+ maxItems: 5000,
133
+ items: {
134
+ type: 'object',
135
+ additionalProperties: false,
136
+ required: ['id', 'kind'],
137
+ properties: {
138
+ id: { type: 'string', minLength: 1, maxLength: 256 },
139
+ kind: { type: 'string', minLength: 1, maxLength: 64 },
140
+ description: { type: 'string', maxLength: 512 },
141
+ },
142
+ },
143
+ },
144
+ handoffs: {
145
+ type: 'object',
146
+ additionalProperties: { type: 'object' },
147
+ },
148
+ lookup: { type: 'object' },
149
+ },
150
+ } as const satisfies JsonSchema
151
+
152
+ export const DocBridgeJsonSchemas = {
153
+ agentHandoffV1: AgentHandoffV1JsonSchema,
154
+ docBridgeIndexV1: DocBridgeIndexV1JsonSchema,
155
+ memoryCandidateV1: MemoryCandidateV1JsonSchema,
156
+ } as const
@@ -0,0 +1,37 @@
1
+ import { z } from 'zod'
2
+
3
+ export const MEMORY_CANDIDATE_SCHEMA_VERSION = 1 as const
4
+
5
+ export const MemorySourceSchema = z.enum([
6
+ 'cursor',
7
+ 'claude',
8
+ 'codex',
9
+ 'copilot',
10
+ 'agent-memory',
11
+ 'manual',
12
+ ])
13
+
14
+ export const MemorySuggestedTypeSchema = z.enum([
15
+ 'user',
16
+ 'feedback',
17
+ 'project',
18
+ 'reference',
19
+ 'unknown',
20
+ ])
21
+
22
+ export const MemoryCandidateV1Schema = z
23
+ .object({
24
+ schemaVersion: z.literal(MEMORY_CANDIDATE_SCHEMA_VERSION),
25
+ id: z.string().min(1).max(256),
26
+ source: MemorySourceSchema,
27
+ rawPath: z.string().min(1).max(512).optional(),
28
+ fact: z.string().min(1).max(8_000),
29
+ why: z.string().max(4_000).optional(),
30
+ howToApply: z.string().max(4_000).optional(),
31
+ suggestedType: MemorySuggestedTypeSchema,
32
+ confidence: z.number().min(0).max(1),
33
+ references: z.array(z.string().min(1).max(512)).max(64),
34
+ })
35
+ .strict()
36
+
37
+ export type MemoryCandidateV1 = z.infer<typeof MemoryCandidateV1Schema>