@a5c-ai/krate 5.0.1-staging.69cb593ea → 5.0.1-staging.6be34ee2a

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.
@@ -1,10 +1,8 @@
1
1
  # Krate SDK API Reference
2
2
 
3
- > Derived from implementation. Source: `packages/krate/sdk/src/index.js`
4
-
5
- Package: `@a5c-ai/krate-sdk`
6
-
7
- The SDK re-exports core helpers for web and CLI consumers. All functions are pure ESM exports with zero external dependencies.
3
+ > Exhaustive API reference for `@a5c-ai/krate-sdk`.
4
+ > Source: `packages/krate/sdk/src/index.js` — 65+ re-exports from core.
5
+ > All functions are pure ESM exports with zero external dependencies.
8
6
 
9
7
  ---
10
8
 
@@ -12,61 +10,102 @@ The SDK re-exports core helpers for web and CLI consumers. All functions are pur
12
10
 
13
11
  Source: `packages/krate/core/src/resource-model.js`
14
12
 
15
- ### Constants
13
+ ### CONFIG_KINDS
16
14
 
17
15
  ```javascript
18
- import { CONFIG_KINDS, AGGREGATED_KINDS, ALL_KINDS, RESOURCE_DEFINITIONS } from '@a5c-ai/krate-sdk';
16
+ import { CONFIG_KINDS } from '@a5c-ai/krate-sdk';
17
+ // Type: Set<string>
18
+ // Size: 44 kind names stored in etcd via Kubernetes CRDs
19
+ // Includes: Organization, User, Team, Repository, AgentStack, KrateWorkspace, etc.
19
20
  ```
20
21
 
21
- | Export | Type | Description |
22
- |--------|------|-------------|
23
- | `CONFIG_KINDS` | `Set<string>` | Set of 44 kind names stored in etcd |
24
- | `AGGREGATED_KINDS` | `Set<string>` | Set of 32 kind names stored in postgres |
25
- | `ALL_KINDS` | `Set<string>` | Union of CONFIG_KINDS and AGGREGATED_KINDS (76 total) |
26
- | `RESOURCE_DEFINITIONS` | `Object` | Frozen map of kind → `{ storage, context, plural, purpose, requiredSpec }` |
22
+ ### AGGREGATED_KINDS
27
23
 
28
- ### createResource(kind, metadata, spec)
24
+ ```javascript
25
+ import { AGGREGATED_KINDS } from '@a5c-ai/krate-sdk';
26
+ // Type: Set<string>
27
+ // Size: 32 kind names stored in PostgreSQL
28
+ // Includes: PullRequest, Issue, AgentDispatchRun, AgentSession, etc.
29
+ ```
29
30
 
30
- Creates a well-formed Krate resource object.
31
+ ### createResource(kind, metadata, spec, status)
32
+
33
+ Creates a well-formed Krate resource object with validation.
31
34
 
32
35
  ```javascript
33
36
  import { createResource } from '@a5c-ai/krate-sdk';
34
37
 
35
- const repo = createResource('Repository', { name: 'my-repo', namespace: 'krate-org-acme' }, {
36
- organizationRef: 'acme',
37
- visibility: 'private'
38
- });
39
- // Returns: { apiVersion: 'krate.a5c.ai/v1alpha1', kind: 'Repository', metadata: {...}, spec: {...} }
38
+ const repo = createResource('Repository',
39
+ { name: 'my-repo', namespace: 'krate-org-acme' },
40
+ { organizationRef: 'acme', visibility: 'private' },
41
+ { phase: 'Ready' }
42
+ );
40
43
  ```
41
44
 
42
- ### clone(obj)
45
+ **Parameters:**
46
+ | Parameter | Type | Required | Default | Constraints |
47
+ |-----------|------|----------|---------|-------------|
48
+ | `kind` | `string` | Yes | — | Must be a key in ALL_KINDS (76 valid values) |
49
+ | `metadata` | `object` | Yes | — | Must contain `name` (non-empty string) |
50
+ | `spec` | `object` | No | `{}` | Deep-cloned via JSON.parse(JSON.stringify) |
51
+ | `status` | `object` | No | `{}` | Deep-cloned |
52
+
53
+ **Returns:** `{ apiVersion: 'krate.a5c.ai/v1alpha1', kind, metadata: { namespace, labels: {}, annotations: {}, ...metadata }, spec, status }`
54
+
55
+ **Throws:**
56
+ - `Error('Unknown Krate resource kind: X')` if kind not in ALL_KINDS
57
+ - `Error('X requires metadata.name')` if metadata.name is falsy
58
+
59
+ **Side Effects:** None (pure function)
60
+
61
+ ### clone(value)
43
62
 
44
- Deep clone utility for resource objects.
63
+ Deep clone via `JSON.parse(JSON.stringify(value))`. Returns `undefined` for `undefined` input.
45
64
 
46
65
  ```javascript
47
66
  import { clone } from '@a5c-ai/krate-sdk';
48
- const copy = clone(resource);
67
+ const copy = clone(resource); // Independent deep copy
68
+ clone(undefined); // Returns undefined
49
69
  ```
50
70
 
51
71
  ### resourceToYaml(resource)
52
72
 
53
- Serialize a resource object to YAML string format.
73
+ Serialize a resource object to YAML string format. Custom implementation (no dependencies).
54
74
 
55
75
  ```javascript
56
76
  import { resourceToYaml } from '@a5c-ai/krate-sdk';
57
77
  const yaml = resourceToYaml(repo);
58
- ```
78
+ // apiVersion: krate.a5c.ai/v1alpha1
79
+ // kind: Repository
80
+ // metadata:
81
+ // name: my-repo
82
+ // namespace: krate-org-acme
83
+ // spec:
84
+ // organizationRef: acme
85
+ // visibility: private
86
+ ```
87
+
88
+ **Behavior:**
89
+ - Scalars: direct value (quotes added for `: ` or `{`/`[` prefixed strings)
90
+ - Objects: nested with 2-space indent
91
+ - Arrays: `- item` format; first key of object items on same line as `-`
92
+ - Returns string with trailing newline
59
93
 
60
94
  ### findResourceDefinition(kind)
61
95
 
62
- Look up the resource definition (plural, storage, namespace) for a given kind.
96
+ Look up the full resource definition from `KRATE_RESOURCES` array.
63
97
 
64
98
  ```javascript
65
99
  import { findResourceDefinition } from '@a5c-ai/krate-sdk';
66
100
  const def = findResourceDefinition('Repository');
67
101
  // { kind: 'Repository', plural: 'repositories', namespaced: true, storage: 'etcd' }
102
+ findResourceDefinition('repositories'); // Also works (matches on plural)
68
103
  ```
69
104
 
105
+ **Throws:** `Error('Unsupported Krate resource X')` if not found.
106
+
107
+ **Note:** This function searches the 75+ KRATE_RESOURCES array (which includes KubeVela, Kyverno, and core K8s resources beyond the 76 Krate-native kinds).
108
+
70
109
  ---
71
110
 
72
111
  ## 2. API Controller
@@ -75,45 +114,62 @@ Source: `packages/krate/core/src/api-controller.js`
75
114
 
76
115
  ### createKrateApiController(options?)
77
116
 
78
- Creates the main API controller for resource operations.
117
+ Creates the main API controller facade for resource operations.
79
118
 
80
119
  ```javascript
81
120
  import { createKrateApiController } from '@a5c-ai/krate-sdk';
82
121
 
83
122
  const controller = createKrateApiController({
84
123
  namespace: 'krate-org-acme',
85
- resourceGateway: createKubernetesResourceGateway() // optional
124
+ resourceGateway: customGateway, // optional
125
+ onAuditEvent: (event) => {} // optional callback
86
126
  });
87
127
  ```
88
128
 
89
129
  **Options:**
90
- | Option | Type | Description |
91
- |--------|------|-------------|
92
- | `namespace` | `string` | Target K8s namespace |
93
- | `resourceGateway` | `object` | Custom resource gateway (default: kubectl) |
130
+ | Option | Type | Default | Description |
131
+ |--------|------|---------|-------------|
132
+ | `namespace` | `string` | `process.env.KRATE_NAMESPACE` or `'krate-system'` | Target K8s namespace |
133
+ | `resourceGateway` | `object` | `createKubernetesResourceGateway(options)` | Custom gateway |
134
+ | `onAuditEvent` | `function` | `null` | Callback for audit events |
94
135
 
95
136
  **Methods:**
96
137
 
97
- | Method | Signature | Returns |
98
- |--------|-----------|---------|
99
- | `snapshot()` | `() => Promise<object>` | Full namespace resource snapshot |
100
- | `listResource(kind)` | `(kind: string) => Promise<{ items: object[] }>` | List resources by kind |
101
- | `getResource(kind, name)` | `(kind: string, name: string) => Promise<object>` | Get single resource |
102
- | `applyResource(resource)` | `(resource: object) => Promise<object>` | Create or update resource |
103
- | `deleteResource(kind, name)` | `(kind: string, name: string) => Promise<object>` | Delete resource |
104
- | `createOrganization(spec)` | `(spec: object) => Promise<object>` | Create org with namespace |
105
- | `createRepository(spec)` | `(spec: object) => Promise<object>` | Create repository |
106
- | `listResourceForOrg(org, kind)` | `(org: string, kind: string) => Promise<object>` | List resources scoped to org |
107
- | `applyResourceForOrg(org, resource)` | `(org: string, resource: object) => Promise<object>` | Apply resource scoped to org |
108
- | `deleteResourceForOrg(org, kind, name)` | `(org: string, kind: string, name: string) => Promise<object>` | Delete scoped resource |
109
- | `syncExternalBinding(name, data)` | `(name: string, data: object) => Promise<object>` | Trigger external sync |
110
- | `resolveExternalConflict(options)` | `(options: object) => Promise<object>` | Resolve sync conflict |
111
- | `approveExternalWriteIntent(options)` | `(options: object) => Promise<object>` | Approve write intent |
112
- | `cancelExternalWriteIntent(options)` | `(options: object) => Promise<object>` | Cancel write intent |
113
- | `processWebhookEvent(event)` | `(event: object) => Promise<object>` | Process webhook/trigger event |
114
- | `queryAgentMemory(options)` | `(options: object) => Promise<object>` | Query agent memory |
115
- | `approveAgentAction(input)` | `(input: object) => Promise<object>` | Approve agent action |
116
- | `denyAgentAction(input)` | `(input: object) => Promise<object>` | Deny agent action |
138
+ | Method | Signature | Returns | Side Effects |
139
+ |--------|-----------|---------|--------------|
140
+ | `snapshot()` | `() Promise<object>` | Full snapshot with architecture | kubectl calls |
141
+ | `listResource(kind)` | `(string) Promise<{items}>` | Resource list | kubectl get |
142
+ | `listResourceForOrg(org, kind)` | `(string, string) Promise<{items}>` | Org-filtered list | kubectl get + filter |
143
+ | `getResource(kind, name)` | `(string, string) Promise<object>` | Single resource | kubectl get |
144
+ | `applyResource(resource)` | `(object) Promise<{operation, resource}>` | Apply result | kubectl apply, cache clear, event emit |
145
+ | `applyResourceForOrg(org, resource)` | `(string, object) Promise<object>` | Scoped apply | kubectl apply, cross-org validation |
146
+ | `deleteResource(kind, name)` | `(string, string) Promise<object>` | Delete result | kubectl delete, cache clear, event emit |
147
+ | `deleteResourceForOrg(org, kind, name)` | `(string, string, string) Promise<object>` | Scoped delete | Cross-org validation, kubectl delete |
148
+ | `getResourceForOrg(org, kind, name)` | `(string, string, string) Promise<object>` | Scoped get | Cross-org validation |
149
+ | `createRepository(input)` | `(object) Promise<{repository, resource}>` | Repository summary | kubectl apply |
150
+ | `createOrganization(input)` | `(object) Promise<{organization, namespace, binding}>` | Org + namespace + binding | kubectl apply x3 |
151
+ | `watchResource(path, handlers)` | `(string, object) {child, command}` | Watch handle | kubectl spawn |
152
+ | `reviewAgentPermissions(input)` | `(object) Promise<review>` | Permission review | snapshot + review |
153
+ | `dispatchAgent(input)` | `(object) Promise<dispatch result>` | Dispatch run | Full dispatch flow |
154
+ | `approveAgentAction(input)` | `(object) Promise<result>` | Approval decision | Snapshot + approve |
155
+ | `denyAgentAction(input)` | `(object) Promise<result>` | Deny decision | Snapshot + deny |
156
+ | `processWebhookEvent(input)` | `(object) Promise<{processed, dispatched}>` | Trigger results | Snapshot + trigger eval |
157
+ | `provisionAgentWorkspace(input)` | `(object) Promise<workspace>` | Workspace | Workspace creation |
158
+ | `archiveAgentWorkspace(input)` | `(object) → Promise<result>` | Archived workspace | Snapshot + archive |
159
+ | `linkWorkItem(input)` | `(object) → Promise<link>` | Link resource | Link creation |
160
+ | `queryAgentMemory(input)` | `(object) → Promise<results>` | Query results | Memory query |
161
+ | `syncExternalBinding(name, opts)` | `(string, object) → Promise<{resource, bindingName}>` | Sync result | Upsert + watermark |
162
+ | `resolveExternalConflict(opts)` | `(object) → Promise<result>` | Resolution | Conflict resolve |
163
+ | `approveExternalWriteIntent(opts)` | `(object) → Promise<result>` | Approval | Intent approve |
164
+ | `cancelExternalWriteIntent(opts)` | `(object) → Promise<result>` | Cancellation | Intent reject |
165
+ | `processExternalWebhook(params)` | `(object) → Promise<result>` | Delivery result | HMAC verify + process |
166
+
167
+ **Cross-org admission (in `applyResource`):**
168
+ ```javascript
169
+ // If resource.spec.organizationRef is set and metadata.namespace doesn't match
170
+ // orgNamespaceName(organizationRef), throws:
171
+ // Error('Cross-org namespace mismatch: resource organizationRef "X" expects namespace "Y" but got "Z"')
172
+ ```
117
173
 
118
174
  ---
119
175
 
@@ -123,32 +179,38 @@ Source: `packages/krate/core/src/controller-ui.js`
123
179
 
124
180
  ### createControllerUiModel(snapshot, options?)
125
181
 
126
- Transforms a raw controller snapshot into a structured UI model.
182
+ Transforms a raw snapshot into the structured UI model consumed by all web pages.
127
183
 
128
184
  ```javascript
129
185
  import { createControllerUiModel } from '@a5c-ai/krate-sdk';
130
-
131
- const uiModel = createControllerUiModel(await controller.snapshot(), {
132
- organization: 'acme'
133
- });
186
+ const uiModel = createControllerUiModel(snapshot, { organization: 'acme' });
134
187
  ```
135
188
 
136
- **Returns:** Object with:
137
- - `orgs` Organization list with display names
138
- - `repositories` — Repository list with metadata
139
- - `pullRequests` Open pull requests
140
- - `pipelines` Recent pipeline runs
141
- - `issues` — Issue list
142
- - `agents` Agent stacks, runs, sessions
143
- - `memory` — Memory repositories
189
+ **Parameters:**
190
+ | Parameter | Type | Description |
191
+ |-----------|------|-------------|
192
+ | `snapshot` | `object` | Raw snapshot from `controller.snapshot()` or runtime |
193
+ | `options.organization` | `string` | Org slug to filter by (optional) |
194
+
195
+ **Returns:** Full UI model object (see web-console-spec.md Section 3.2 for full shape)
144
196
 
145
197
  ### issueProjectRefs(issue)
146
198
 
147
- Extract project references from an issue resource.
199
+ Extract all project references from an issue resource (checks spec, labels, annotations, status).
200
+
201
+ ```javascript
202
+ import { issueProjectRefs } from '@a5c-ai/krate-sdk';
203
+ const refs = issueProjectRefs(issue); // ['project-alpha', 'project-beta']
204
+ ```
148
205
 
149
206
  ### issueRepositoryRefs(issue)
150
207
 
151
- Extract repository references from an issue resource.
208
+ Extract all repository references from an issue resource.
209
+
210
+ ```javascript
211
+ import { issueRepositoryRefs } from '@a5c-ai/krate-sdk';
212
+ const refs = issueRepositoryRefs(issue); // ['my-repo', 'other-repo']
213
+ ```
152
214
 
153
215
  ---
154
216
 
@@ -158,40 +220,34 @@ Source: `packages/krate/core/src/auth.js`
158
220
 
159
221
  ### createAuthProviderConfig(env?)
160
222
 
161
- Build auth configuration from environment variables.
162
-
163
223
  ```javascript
164
224
  import { createAuthProviderConfig } from '@a5c-ai/krate-sdk';
165
225
  const config = createAuthProviderConfig(process.env);
226
+ // Returns: { session: { cookieName }, delegatedIdentity: {...}, providers: { github: {...}, sso: {...} } }
166
227
  ```
167
228
 
168
- **Returns:** `{ session, delegatedIdentity, providers: { github, sso } }`
169
-
170
229
  ### listEnabledAuthProviders(config?)
171
230
 
172
- Get array of enabled and configured providers.
173
-
174
231
  ```javascript
175
232
  import { listEnabledAuthProviders } from '@a5c-ai/krate-sdk';
176
233
  const providers = listEnabledAuthProviders(config);
177
- // [{ id: 'github', label: 'GitHub', type: 'github', ... }]
234
+ // Returns: Array of providers where enabled=true, clientId set, authorizationUrl set
178
235
  ```
179
236
 
180
237
  ### buildAuthorizationRedirect({ provider, requestUrl, state? })
181
238
 
182
- Build OAuth authorization redirect URL.
183
-
184
239
  ```javascript
185
240
  import { buildAuthorizationRedirect } from '@a5c-ai/krate-sdk';
186
241
  const { url, state, redirectUri } = buildAuthorizationRedirect({
187
242
  provider: config.providers.github,
188
243
  requestUrl: 'https://krate.example.com/login'
189
244
  });
245
+ // url: 'https://github.com/login/oauth/authorize?response_type=code&client_id=...&redirect_uri=...&scope=...&state=...'
190
246
  ```
191
247
 
192
- ### exchangeOAuthCodeForProfile({ provider, code, requestUrl, fetchImpl? })
248
+ **Throws:** Error if provider disabled, clientId missing, or authorizationUrl missing.
193
249
 
194
- Exchange OAuth authorization code for user profile.
250
+ ### exchangeOAuthCodeForProfile({ provider, code, requestUrl, fetchImpl? })
195
251
 
196
252
  ```javascript
197
253
  import { exchangeOAuthCodeForProfile } from '@a5c-ai/krate-sdk';
@@ -200,583 +256,524 @@ const profile = await exchangeOAuthCodeForProfile({
200
256
  code: 'abc123',
201
257
  requestUrl: 'https://krate.example.com/login'
202
258
  });
203
- // { provider, subject, email, displayName, username, groups, teams, admin }
259
+ // Returns: { provider, subject, email, displayName, username, groups, teams, admin }
204
260
  ```
205
261
 
206
- ### createSessionCookie(config, profile, options?)
262
+ **Side Effects:** Two HTTP requests (token exchange + profile fetch)
207
263
 
208
- Create an HMAC-signed session cookie.
264
+ ### createSessionCookie(config, profile, options?)
209
265
 
210
266
  ```javascript
211
267
  import { createSessionCookie } from '@a5c-ai/krate-sdk';
212
- const cookie = createSessionCookie(config, profile, { secret: process.env.KRATE_SESSION_SECRET });
213
- // "krate_session=base64url.signature; Path=/; HttpOnly; SameSite=Lax"
268
+ const cookie = createSessionCookie(config, profile, { secret: 'my-secret' });
269
+ // "krate_session=eyJ...base64url.hmac_signature; Path=/; HttpOnly; SameSite=Lax"
214
270
  ```
215
271
 
216
272
  ### parseSessionCookie(config, cookieValue, options?)
217
273
 
218
- Parse and verify a session cookie. Returns `null` if invalid.
219
-
220
274
  ```javascript
221
275
  import { parseSessionCookie } from '@a5c-ai/krate-sdk';
222
- const session = parseSessionCookie(config, cookieValue, { secret });
223
- // { provider, subject, user } or null
276
+ const session = parseSessionCookie(config, cookieValue, { secret: 'my-secret' });
277
+ // Returns: { cookieName, provider, subject, user } or null
224
278
  ```
225
279
 
226
- ### registerLoginProfile({ controller, namespace, profile })
227
-
228
- Register a login profile as a User and IdentityMapping.
229
-
230
- ### mapLoginProfileToKrateIdentity(profile)
231
-
232
- Map an OAuth profile to Krate User + IdentityMapping resources.
233
-
234
280
  ### profileFromDelegatedHeaders(headers, config?, options?)
235
281
 
236
- Extract user profile from proxy delegation headers.
237
-
238
- ### createInviteResource(spec)
239
-
240
- Create an Invite resource for user onboarding.
241
-
242
- ### createTeamResource(spec)
243
-
244
- Create a Team resource.
245
-
246
- ---
247
-
248
- ## 5. Agent Controllers
249
-
250
- ### createAgentStackController()
251
-
252
- Source: `packages/krate/core/src/agent-stack-controller.js`
253
-
254
- Stack readiness reconciliation with capability resolution and MCP health checks.
255
-
256
282
  ```javascript
257
- import { createAgentStackController } from '@a5c-ai/krate-sdk';
258
- const stackCtrl = createAgentStackController();
283
+ import { profileFromDelegatedHeaders } from '@a5c-ai/krate-sdk';
284
+ const profile = profileFromDelegatedHeaders(request.headers, config, { requestUrl });
259
285
  ```
260
286
 
261
- **Methods:**
262
- - `reconcileStack(stack, resources)` — Resolve capabilities, compute readiness
263
- - `performMcpHealthCheck(url)` — HTTP health check (3s timeout)
264
-
265
- ### createAgentDispatchController(options?)
266
-
267
- Source: `packages/krate/core/src/agent-dispatch-controller.js`
268
-
269
- Manual dispatch orchestration with permission gating.
270
-
271
- ```javascript
272
- import { createAgentDispatchController } from '@a5c-ai/krate-sdk';
273
- const dispatchCtrl = createAgentDispatchController();
274
- ```
275
-
276
- **Methods:**
277
- - `createManualDispatch({ repository, ref, agentStack, taskKind, actor, namespace, organizationRef, resources })` — Create dispatch run
278
-
279
- ### createAgentWorkspaceController()
280
-
281
- Source: `packages/krate/core/src/agent-workspace-controller.js`
287
+ ### registerLoginProfile({ controller, namespace, profile })
282
288
 
283
- Volume-backed git workspace provisioning.
289
+ Applies User + IdentityMapping resources via `controller.applyResource()`.
284
290
 
285
- **Methods:**
286
- - `createWorkspace({ name, organizationRef, repository, volumeSpec, branch, namespace })` — Create workspace with PVC
287
- - `generateCloneSpec(workspace)` — Git clone commands
288
- - `generateCheckoutSpec(workspace, ref)` — Checkout commands
289
- - `generateMountSpec(workspace)` — Volume mount configuration
290
- - `findReusableWorkspace(repository, branch, workspaces)` — Find existing workspace
291
- - `recordRunInHistory(workspace, runId)` — Track run association
291
+ ### mapLoginProfileToKrateIdentity(profile)
292
292
 
293
- ### createAgentApprovalController()
293
+ Pure function: maps OAuth profile to User + IdentityMapping resources.
294
294
 
295
- Source: `packages/krate/core/src/agent-approval-controller.js`
295
+ ### createInviteResource(spec) / createTeamResource(spec)
296
296
 
297
- Approval workflow management.
297
+ Factory functions for Invite and Team resources.
298
298
 
299
- **Methods:**
300
- - `createApproval(options)` — Create pending approval
301
- - `approveAction(approval, decidedBy, reason)` — Approve
302
- - `denyAction(approval, decidedBy, reason)` — Deny
299
+ ---
303
300
 
304
- ### createAgentTriggerController()
301
+ ## 5. Org Scoping
305
302
 
306
- Source: `packages/krate/core/src/agent-trigger-controller.js`
303
+ Source: `packages/krate/core/src/org-scoping.js`
307
304
 
308
- Event-to-stack routing.
305
+ ### orgNamespaceName(org)
309
306
 
310
307
  ```javascript
311
- import { createAgentTriggerController, validateTriggerRule } from '@a5c-ai/krate-sdk';
308
+ import { orgNamespaceName } from '@a5c-ai/krate-sdk';
309
+ orgNamespaceName('acme'); // 'krate-org-acme'
310
+ orgNamespaceName('Acme Inc'); // 'krate-org-acme-inc'
312
311
  ```
313
312
 
314
- **Methods:**
315
- - `evaluateTrigger(event, rules, resources)` — Match event to rules
316
- - `createExecutionRecord(rule, event, decision)` — Record evaluation
317
-
318
- **Exported utilities:**
319
- - `validateCronExpression(expr)` — Validate cron syntax
320
- - `calculateNextRun(expr, now)` — Next cron execution time
321
- - `validateWebhookTrigger(source)` — Validate webhook source config
322
- - `validateCommentTrigger(source)` — Validate comment trigger
323
- - `validateLabelTrigger(source)` — Validate label trigger
324
- - `getTriggerSourceType(source)` — Determine source type
325
- - `validateTriggerRule(rule)` — Full rule validation
326
-
327
- ### createAgentMemoryController()
328
-
329
- Source: `packages/krate/core/src/agent-memory-controller.js`
313
+ **Throws:** `Error('organization is required')` if empty after normalization.
330
314
 
331
- Memory CRUD and time travel.
332
-
333
- **Methods:**
334
- - `createMemorySnapshot(options)` — Create dispatch-time memory pin
335
- - `resolveTimeTravel(options)` — Resolve commit reference
336
-
337
- ### createAgentAdapterController()
338
-
339
- Source: `packages/krate/core/src/agent-adapter-controller.js`
315
+ ### normalizeOrgSlug(value)
340
316
 
341
317
  ```javascript
342
- import { createAgentAdapterController, validateAgentAdapter } from '@a5c-ai/krate-sdk';
318
+ import { normalizeOrgSlug } from '@a5c-ai/krate-sdk';
319
+ normalizeOrgSlug('Acme Inc'); // 'acme-inc'
320
+ normalizeOrgSlug(' HELLO '); // 'hello'
343
321
  ```
344
322
 
345
- ### createAgentTransportBindingController()
346
-
347
- Source: `packages/krate/core/src/agent-transport-binding-controller.js`
348
-
349
- ```javascript
350
- import { createAgentTransportBindingController, validateAgentTransportBinding } from '@a5c-ai/krate-sdk';
351
- ```
323
+ ---
352
324
 
353
- ### createAgentProviderConfigController()
325
+ ## 6. Agent Controllers
354
326
 
355
- Source: `packages/krate/core/src/agent-provider-config-controller.js`
327
+ ### createAgentStackController(options?)
356
328
 
357
329
  ```javascript
358
- import { createAgentProviderConfigController, validateAgentProviderConfig } from '@a5c-ai/krate-sdk';
330
+ import { createAgentStackController } from '@a5c-ai/krate-sdk';
331
+ const ctrl = createAgentStackController({ fetch: customFetch });
359
332
  ```
360
333
 
361
- ### createAgentProjectController()
334
+ **Methods:**
335
+ - `reconcileStack(stack, resources)` — Returns `{ conditions, capabilities, validation, permissionDecision }`
336
+ - `listStackCapabilities(stack, resources)` — Returns array of `{ kind, name, status, ref }`
337
+ - `checkMcpHealth(mcpServer)` — Returns `{ serverName, status, latencyMs, error? }`
362
338
 
363
- Source: `packages/krate/core/src/agent-project-controller.js`
339
+ ### createAgentDispatchController(options?)
364
340
 
365
341
  ```javascript
366
- import { createAgentProjectController, validateAgentProject } from '@a5c-ai/krate-sdk';
342
+ import { createAgentDispatchController } from '@a5c-ai/krate-sdk';
343
+ const ctrl = createAgentDispatchController({ permissionReviewer, stackController, ... });
367
344
  ```
368
345
 
369
- ### createAgentGatewayConfigController()
346
+ **Methods:**
347
+ - `createManualDispatch({ repository, ref, agentStack, taskKind, actor, namespace, organizationRef, resources })` — Full dispatch orchestration
370
348
 
371
- Source: `packages/krate/core/src/agent-gateway-config-controller.js`
349
+ ### createAgentWorkspaceController()
372
350
 
373
351
  ```javascript
374
- import { createAgentGatewayConfigController, validateAgentGatewayConfig } from '@a5c-ai/krate-sdk';
375
- ```
376
-
377
- ### createAgentSessionTranscriptController()
378
-
379
- Source: `packages/krate/core/src/agent-session-transcript-controller.js`
352
+ import { createAgentWorkspaceController } from '@a5c-ai/krate-sdk';
353
+ const ctrl = createAgentWorkspaceController();
354
+ ```
355
+
356
+ **Methods (25):**
357
+ - `createWorkspace(opts)` — Returns `{ workspace, pvcManifest }`
358
+ - `deleteWorkspace(opts)` — Returns `{ workspace, pvcDeleteManifest }`
359
+ - `getWorkspaceStatus(opts)` — Returns status object
360
+ - `initializeWorkspace(opts)` — Returns git clone commandSpec
361
+ - `checkoutBranch(opts)` — Returns git checkout commandSpec
362
+ - `syncWorkspace(opts)` — Returns fetch+reset commandSpecs
363
+ - `getMountSpec(opts)` — Returns `{ volume, volumeMount }`
364
+ - `findReusableWorkspace(opts)` — Returns matching workspace or null
365
+ - `claimWorkspace(opts)` — Marks workspace InUse
366
+ - `releaseWorkspace(opts)` — Returns workspace to Ready
367
+ - `provisionWorkspace(opts)` — Legacy: create + mark InUse + runtime
368
+ - `archiveWorkspace(opts)` — Sets phase=Archived
369
+ - `recoverWorkspace(opts)` — Recovers from Archived
370
+ - `bindSession(opts)` — Adds session to boundSessions[]
371
+ - `linkWorkItem(opts)` — Creates WorkItemWorkspaceLink
372
+ - `linkWorkItemToSession(opts)` — Creates WorkItemSessionLink
373
+ - `listWorkspacesForRepo(opts)` — Filter by repository
374
+ - `listWorkspacesForRun(opts)` — Filter by runRef
375
+ - `launchCodespace(workspace, opts)` — Returns podSpec, serviceSpec, codespaceUrl
376
+ - `stopCodespace(workspace)` — Returns delete manifests
377
+ - `getCodespaceStatus(workspace, podStatus)` — Returns running/url/uptime
378
+ - `addAssociation(workspace, ref)` — Adds to spec.associations[]
379
+ - `removeAssociation(workspace, ref)` — Removes from spec.associations[]
380
+ - `listAssociations(workspace)` — Returns associations array
381
+ - `getWorkspaceRuns(workspace, allRuns)` — Returns `{ active, history }`
382
+
383
+ ### createAgentTriggerController(options?)
380
384
 
381
385
  ```javascript
382
- import { createAgentSessionTranscriptController, validateAgentSessionTranscript } from '@a5c-ai/krate-sdk';
386
+ import { createAgentTriggerController, validateTriggerRule } from '@a5c-ai/krate-sdk';
383
387
  ```
384
388
 
385
- ### createAgentSubagentController()
386
-
387
- Source: `packages/krate/core/src/agent-subagent-controller.js`
389
+ **Methods:**
390
+ - `matchRule(rule, event)` — Returns `{ matches, reason }`
391
+ - `evaluateEvent({ event, resources })` — Returns array of `{ rule, matches, reason, isDuplicate }`
392
+ - `createTriggerExecution({ rule, event, decision, reason, namespace, organizationRef })` — Creates resource
393
+ - `evaluateWebhookEvent(event, rules)` — Returns `{ matchingRules, dispatchIntents }`
394
+ - `processEvent({ event, resources, namespace, organizationRef })` — Full evaluation + dispatch
395
+
396
+ **Utility exports:**
397
+ - `validateCronExpression(expr)` → `{ valid, error? }`
398
+ - `calculateNextRun(cronExpr, fromDate?)` → `Date | null`
399
+ - `validateWebhookTrigger(config)` → `{ valid, error? }`
400
+ - `validateCommentTrigger(config)` → `{ valid, error? }`
401
+ - `validateLabelTrigger(config)` → `{ valid, error? }`
402
+ - `getTriggerSourceType(rule)` → `'cron'|'webhook'|'comment'|'label'|'event'|'unknown'`
403
+ - `validateTriggerRule(rule)` → `{ valid, errors[] }`
388
404
 
389
- ```javascript
390
- import { createAgentSubagentController } from '@a5c-ai/krate-sdk';
391
- ```
405
+ ### createAgentApprovalController()
392
406
 
393
- ### createAgentWritebackController()
407
+ **Methods:**
408
+ - `createApprovalRequest({ dispatchRun, action, requestedBy, context, namespace, organizationRef, resources })` — Creates AgentApproval (dedup check)
409
+ - `recordDecision({ approvalName, decision, decidedBy, reason, namespace, organizationRef, resources })` — Approve or deny
410
+ - `isActionApproved({ dispatchRun, action, resources })` — Check approval status
411
+ - `listPendingApprovals({ organizationRef, resources })` — Filter pending
412
+ - `listApprovalsForRun({ dispatchRun, resources })` — Filter by run
413
+ - `persistApproval({ approval, applyResource })` — Persist to K8s
414
+ - `enforceApproval({ dispatchRun, action, resources })` — Gate check
394
415
 
395
- Source: `packages/krate/core/src/agent-writeback-controller.js`
416
+ ### createPermissionReviewer()
396
417
 
397
418
  ```javascript
398
- import { createAgentWritebackController } from '@a5c-ai/krate-sdk';
419
+ import { createPermissionReviewer } from '@a5c-ai/krate-sdk';
420
+ const reviewer = createPermissionReviewer();
421
+ const result = reviewer.reviewPermissions({
422
+ repository, ref, actor, agentStack, triggerSource, taskKind,
423
+ runnerPool, toolRefs, skillRefs, mcpServerRefs, contextLabelRefs,
424
+ workspacePolicyRef, isFork, resources
425
+ });
426
+ // Returns: { decision: 'allowed'|'requires-approval'|'denied', reasons[], grants[], capabilities, ... }
399
427
  ```
400
428
 
401
429
  ---
402
430
 
403
- ## 6. Memory System
404
-
405
- Source: `packages/krate/core/src/agent-memory-query.js`
431
+ ## 7. Memory System
406
432
 
407
433
  ### queryGraph({ records, edges, query, kinds?, depth? })
408
434
 
409
- Execute a graph query over memory records.
410
-
411
435
  ```javascript
412
436
  import { queryGraph } from '@a5c-ai/krate-sdk';
413
-
414
437
  const result = queryGraph({
415
- records: [{ id: 'n1', nodeKind: 'concept', attributes: { title: 'Agent Design' }, edges: [] }],
438
+ records: [{ id: 'n1', nodeKind: 'concept', attributes: { title: 'Design' }, edges: [] }],
416
439
  edges: [{ source: 'n1', target: 'n2', kind: 'related-to' }],
417
- query: 'agent',
440
+ query: 'design',
418
441
  kinds: ['concept'],
419
442
  depth: 2
420
443
  });
421
- // { matches: [...], totalMatches: number }
444
+ // Returns: { matches: [{ record, score, edges }], totalMatches: number }
422
445
  ```
423
446
 
424
- **Parameters:**
425
- | Param | Type | Required | Description |
426
- |-------|------|----------|-------------|
427
- | `records` | `Array<{ id, nodeKind, attributes, edges }>` | Yes | Graph records |
428
- | `edges` | `Array<{ source, target, kind }>` | No | Flat edges (supplements per-record edges) |
429
- | `query` | `string` | Yes | Search text (non-empty) |
430
- | `kinds` | `string[]` | No | nodeKind filter (empty = no filter) |
431
- | `depth` | `number` | No | Edge-follow depth (default: 1) |
432
-
433
- ### queryGrep({ documents, query, contextLines? })
447
+ **Scoring:** id match = 2, attribute match = 1, no match = 0
448
+ **Throws:** Error if query is null, undefined, or empty string
434
449
 
435
- Execute full-text grep over documents.
450
+ ### queryGrep({ documents, query, paths?, context?, maxMatches? })
436
451
 
437
452
  ```javascript
438
453
  import { queryGrep } from '@a5c-ai/krate-sdk';
439
-
440
454
  const result = queryGrep({
441
- documents: [{ id: 'doc1', content: 'Agent memory stores knowledge...' }],
442
- query: 'knowledge',
443
- contextLines: 2
455
+ documents: [{ path: 'docs/arch.md', content: '...' }],
456
+ query: 'controller',
457
+ paths: ['docs/*'],
458
+ context: 2,
459
+ maxMatches: 25
444
460
  });
445
- // { matches: [...], totalMatches: number }
461
+ // Returns: { excerpts: [{ path, lineNumber, line, highlighted, context, contextStart, contextEnd }], totalMatches }
446
462
  ```
447
463
 
448
- ### queryMemory({ records, documents, edges, query, mode, kinds?, depth?, contextLines? })
464
+ ### queryMemory({ query, mode, records, documents, edges, graphOptions, grepOptions })
449
465
 
450
- Combined graph + grep query.
466
+ Combined query supporting three modes: `'graph-only'`, `'grep-only'`, `'graph-and-grep'`.
451
467
 
452
468
  ```javascript
453
469
  import { queryMemory } from '@a5c-ai/krate-sdk';
454
-
455
470
  const result = queryMemory({
456
- records,
457
- documents,
458
- edges,
459
471
  query: 'agent design',
460
- mode: 'graph-and-grep', // 'graph-only' | 'grep-only' | 'graph-and-grep'
461
- kinds: [],
462
- depth: 1,
463
- contextLines: 3
472
+ mode: 'graph-and-grep',
473
+ records, documents, edges,
474
+ graphOptions: { kinds: ['concept'], depth: 2 },
475
+ grepOptions: { paths: ['docs/*'], context: 3, maxMatches: 25 }
464
476
  });
477
+ // Returns: { graph: { matches, totalMatches }, grep: { excerpts, totalMatches }, stats: { mode, totalMatches, graphCount, grepCount } }
465
478
  ```
466
479
 
467
480
  ### Memory Import Utilities
468
481
 
469
- Source: `packages/krate/core/src/agent-memory-import.js`
470
-
471
482
  ```javascript
472
483
  import {
473
- parseJournalForImport,
474
- createMemorySnapshot,
475
- validateMemoryImport,
476
- validateMemorySnapshot,
477
- validateOntology,
478
- getOntologyNodeKinds,
479
- getOntologyEdgeKinds
484
+ parseJournalForImport, // Parse babysitter run journal → importable data
485
+ createMemorySnapshot, // Create AgentMemorySnapshot resource
486
+ validateMemoryImport, // Validate AgentRunMemoryImport structure
487
+ validateMemorySnapshot, // Validate AgentMemorySnapshot structure
488
+ validateOntology, // Validate AgentMemoryOntology structure
489
+ getOntologyNodeKinds, // Extract valid node kinds
490
+ getOntologyEdgeKinds // Extract valid edge kinds
480
491
  } from '@a5c-ai/krate-sdk';
481
492
  ```
482
493
 
483
- | Function | Description |
484
- |----------|-------------|
485
- | `parseJournalForImport(journal)` | Parse babysitter run journal for importable data |
486
- | `createMemorySnapshot(options)` | Create an AgentMemorySnapshot resource |
487
- | `validateMemoryImport(importResource)` | Validate an AgentRunMemoryImport |
488
- | `validateMemorySnapshot(snapshot)` | Validate an AgentMemorySnapshot |
489
- | `validateOntology(ontology)` | Validate an AgentMemoryOntology |
490
- | `getOntologyNodeKinds(ontology)` | Extract valid node kinds from ontology |
491
- | `getOntologyEdgeKinds(ontology)` | Extract valid edge kinds from ontology |
492
-
493
494
  ---
494
495
 
495
- ## 7. External Backend Controllers
496
+ ## 8. External Backend Controllers
496
497
 
497
498
  ### createWebhookController(options?)
498
499
 
499
- Source: `packages/krate/core/src/external/webhook-controller.js`
500
-
501
500
  ```javascript
502
501
  import { createWebhookController } from '@a5c-ai/krate-sdk';
503
- const webhookCtrl = createWebhookController({ secret: 'webhook-secret' });
502
+ const ctrl = createWebhookController({ secret: 'webhook-signing-secret' });
504
503
  ```
505
504
 
506
- **Methods:**
507
- - `verifySignature(body, signature)` HMAC-SHA256 verification`{ valid, reason }`
508
- - `createDelivery(event)` — Create delivery record with dedup
509
- - `subscribe(handler)` Subscribe to delivery events
510
- - `getDelivery(id)` — Get delivery by ID
511
- - `listDeliveries()` List all deliveries
512
-
513
- ### createSyncController()
505
+ - `verifyHmacSignature(body, signature)` → `{ valid, reason }`
506
+ - `createDeliveryRecord({ deliveryId, eventType, payload, rawBody })`record
507
+ - `recordDelivery(record)` — Store in dedup Map
508
+ - `isDuplicate(deliveryId)` boolean
509
+ - `onEvent(handler)` — Subscribe to events
510
+ - `processDelivery(params)` `{ queued, duplicate, deliveryId }`
514
511
 
515
- Source: `packages/krate/core/src/external/sync-controller.js`
512
+ ### createSyncController(opts?)
516
513
 
517
514
  ```javascript
518
515
  import { createSyncController } from '@a5c-ai/krate-sdk';
519
- const syncCtrl = createSyncController();
516
+ const ctrl = createSyncController({ persistFn: async (resource) => {} });
520
517
  ```
521
518
 
522
- **Methods:**
523
- - `processSync(event)` Process sync event, update state
524
- - `getSyncState(provider, resource)` — Get current sync state
525
- - `listSyncEvents(options)` List events with filtering
526
-
527
- ### createWriteController()
519
+ - `normalizeEvent(rawEvent)` → canonical event
520
+ - `upsertResource({ kind, localName, namespace, spec, externalEnvelope })` → resource
521
+ - `updateWatermark(bindingRef, timestamp)` — Advance watermark
522
+ - `getWatermark(bindingRef)` string | null
523
+ - `applyOwnershipMode({ ownershipMode, operation, origin })` → `{ allowed, reason }`
524
+ - `createTombstone(params)` → tombstone record
525
+ - `getTombstone(nativeId)` → record | null
528
526
 
529
- Source: `packages/krate/core/src/external/write-controller.js`
530
-
531
- ```javascript
532
- import { createWriteController } from '@a5c-ai/krate-sdk';
533
- const writeCtrl = createWriteController();
534
- ```
535
-
536
- **Methods:**
537
- - `createWriteIntent(options)` — Queue write-back intent
538
- - `approveIntent(name, approvedBy)` — Approve for execution
539
- - `cancelIntent(name, cancelledBy)` — Cancel intent
540
- - `listIntents(options)` — List pending intents
541
-
542
- ### createConflictController()
543
-
544
- Source: `packages/krate/core/src/external/conflict-controller.js`
527
+ ### createConflictController(opts?)
545
528
 
546
529
  ```javascript
547
530
  import { createConflictController } from '@a5c-ai/krate-sdk';
548
- const conflictCtrl = createConflictController();
531
+ const ctrl = createConflictController({ persistFn });
549
532
  ```
550
533
 
551
- **Methods:**
552
- - `detectConflict(local, external)` Compare and detect conflicts
553
- - `resolveConflict(name, strategy, resolvedValue)` Resolve with strategy
554
- - `listConflicts(options)` List unresolved conflicts
555
-
556
- ### createDefaultProviderRegistry()
534
+ - `detectConflict({ resourceRef, fieldPath, localValue, externalValue, namespace?, organizationRef? })` → `{ conflict: resource | null }`
535
+ - `resolveConflict({ conflictName, strategy, resolvedValue?, resources? })` resolved conflict
536
+ - `listOpenConflicts(options)` conflict array
537
+ - `supersede(conflictName, resources)` superseded conflict
557
538
 
558
- Source: `packages/krate/core/src/external/provider-resource-factory.js`
539
+ ### createWriteController(opts?)
559
540
 
560
541
  ```javascript
561
- import { createDefaultProviderRegistry, createExternalBackendProvider } from '@a5c-ai/krate-sdk';
562
- const registry = createDefaultProviderRegistry();
542
+ import { createWriteController } from '@a5c-ai/krate-sdk';
543
+ const ctrl = createWriteController({ persistFn });
563
544
  ```
564
545
 
565
- ---
546
+ - `createWriteIntent({ interfaceKey, operation, payload?, resourceRef, requiresApproval?, maxRetries?, namespace?, organizationRef? })` → intent
547
+ - `approveWriteIntent({ intentName, approvedBy, resources? })` → approved intent
548
+ - `rejectWriteIntent({ intentName, rejectedBy, reason?, resources? })` → rejected intent
549
+ - `markSending(intentName, resources)` → sending intent
550
+ - `confirmSuccess(intentName, response, resources)` → succeeded intent
551
+ - `confirmFailure(intentName, error, resources)` → failed/retrying intent
552
+ - `listIntents(options)` → intent array
566
553
 
567
- ## 8. Event System
554
+ ---
568
555
 
569
- Source: `packages/krate/core/src/event-bus.js`
556
+ ## 9. Event System
570
557
 
571
558
  ### globalEventBus
572
559
 
573
- Singleton event bus instance.
560
+ Singleton event bus shared across the process.
574
561
 
575
562
  ```javascript
576
563
  import { globalEventBus } from '@a5c-ai/krate-sdk';
577
-
578
- globalEventBus.subscribe((event) => {
579
- console.log('Event:', event.type, event.kind, event.name);
580
- });
581
-
582
- globalEventBus.emit({ type: 'resource-change', kind: 'Repository', name: 'my-repo', operation: 'apply' });
564
+ globalEventBus.subscribe((event) => console.log(event));
565
+ globalEventBus.emit({ type: 'custom', data: {} });
566
+ globalEventBus.emitResourceChange('Repository', 'my-repo', 'apply');
583
567
  ```
584
568
 
585
569
  ### createEventBus()
586
570
 
587
- Create a new isolated event bus.
571
+ Create an isolated event bus instance.
588
572
 
589
573
  ```javascript
590
574
  import { createEventBus } from '@a5c-ai/krate-sdk';
591
575
  const bus = createEventBus();
576
+ bus.subscribe(fn);
577
+ bus.unsubscribe(fn);
578
+ bus.emit(event);
579
+ bus.emitResourceChange(kind, name, operation);
592
580
  ```
593
581
 
594
- **Methods:**
595
- | Method | Signature | Description |
596
- |--------|-----------|-------------|
597
- | `subscribe(fn)` | `(fn: (event) => void) => void` | Add listener |
598
- | `unsubscribe(fn)` | `(fn: Function) => void` | Remove listener |
599
- | `emit(event)` | `(event: object) => void` | Broadcast to all |
600
- | `emitResourceChange(kind, name, operation)` | `(kind, name, op) => void` | Emit resource-change event |
601
-
602
- ---
603
-
604
- ## 9. Audit
605
-
606
- Source: `packages/krate/core/src/audit-controller.js`
607
-
608
- ### createAuditController()
609
-
610
- ```javascript
611
- import { createAuditController } from '@a5c-ai/krate-sdk';
612
- const audit = createAuditController();
613
- ```
614
-
615
- **Methods:**
616
- - `record(event)` — Record an audit event
617
- - `query(options)` — Query events by org, action, time range, pagination
618
-
619
- ### createEventPoller(options)
620
-
621
- Polling mechanism for audit event consumption.
622
-
623
582
  ---
624
583
 
625
584
  ## 10. Async Utilities
626
585
 
627
- Source: `packages/krate/core/src/async-controller.js`
628
-
629
586
  ### createEventBatcher(handler, options?)
630
587
 
631
- Batch events with size and time-based flushing.
632
-
633
588
  ```javascript
634
589
  import { createEventBatcher } from '@a5c-ai/krate-sdk';
635
-
636
- const batcher = createEventBatcher(async (events) => {
637
- await saveAll(events);
638
- }, { maxBatchSize: 50, flushIntervalMs: 1000 });
639
-
640
- batcher.push(event);
641
- await batcher.flush();
642
- batcher.stop();
590
+ const batcher = createEventBatcher(async (events) => { await saveAll(events); }, { maxBatchSize: 50, flushIntervalMs: 1000 });
591
+ batcher.push(event); // Add event to batch
592
+ await batcher.flush(); // Force immediate flush
593
+ batcher.stop(); // Clear timer and buffer
643
594
  ```
644
595
 
645
- **Options:** `{ maxBatchSize: 50, flushIntervalMs: 1000 }`
646
- **Returns:** `{ push(event), flush(), stop() }`
647
-
648
596
  ### createRetryPolicy(options?)
649
597
 
650
- Retry operations with exponential backoff and jitter.
651
-
652
598
  ```javascript
653
599
  import { createRetryPolicy } from '@a5c-ai/krate-sdk';
654
- const retry = createRetryPolicy({ maxRetries: 3, baseDelayMs: 100 });
600
+ const policy = createRetryPolicy({ maxRetries: 3, baseDelayMs: 1000, maxDelayMs: 30000, jitter: true });
601
+ policy.shouldRetry(attempt, error); // boolean
602
+ policy.getDelay(attempt); // milliseconds
655
603
  ```
656
604
 
657
- ### createDeliveryQueue(options?)
658
-
659
- Ordered async delivery queue with error isolation.
605
+ ### createDeliveryQueue(processor, options?)
660
606
 
661
607
  ```javascript
662
608
  import { createDeliveryQueue } from '@a5c-ai/krate-sdk';
663
- const queue = createDeliveryQueue({ concurrency: 5 });
609
+ const queue = createDeliveryQueue(async (item) => { await deliver(item); }, { concurrency: 5, retryPolicy });
610
+ queue.enqueue(item); // Add to queue
611
+ await queue.drain(); // Wait for empty
612
+ queue.size(); // Current queue + active
613
+ queue.stop(); // Clear and resolve waiters
664
614
  ```
665
615
 
666
- ### createCheckpointer(options?)
667
-
668
- Checkpoint and resume for long-running operations.
616
+ ### createCheckpointer(storage?)
669
617
 
670
618
  ```javascript
671
619
  import { createCheckpointer } from '@a5c-ai/krate-sdk';
672
- const cp = createCheckpointer({ storageKey: 'sync-progress' });
620
+ const cp = createCheckpointer(new Map());
621
+ cp.save('progress', { page: 5 });
622
+ cp.load('progress'); // { page: 5 }
623
+ cp.clear('progress');
624
+ cp.listKeys(); // []
673
625
  ```
674
626
 
675
627
  ---
676
628
 
677
- ## 11. Other Utilities
629
+ ## 11. Audit
630
+
631
+ ### createAuditController()
632
+
633
+ ```javascript
634
+ import { createAuditController } from '@a5c-ai/krate-sdk';
635
+ const audit = createAuditController();
636
+ audit.log({ org: 'acme', actor: 'user1', action: 'apply', resource: { kind: 'Repository', name: 'x' } });
637
+ const { events, total } = audit.query({ org: 'acme', action: 'apply', limit: 10, offset: 0 });
638
+ ```
639
+
640
+ ### createEventPoller(options)
641
+
642
+ Polling mechanism for audit event consumption with exponential backoff.
678
643
 
679
- ### Runner Controller
644
+ ---
680
645
 
681
- Source: `packages/krate/core/src/runner-controller.js`
646
+ ## 12. Other Utilities
647
+
648
+ ### createRunnerController()
682
649
 
683
650
  ```javascript
684
651
  import { createRunnerController } from '@a5c-ai/krate-sdk';
685
652
  const runners = createRunnerController();
653
+ runners.validateRunnerPool(resource); // { valid, reason?, name?, ... }
654
+ runners.getPoolStatus(pool); // { idle, active, total, phase, scaling }
655
+ runners.getCapacity(pool); // { maxReplicas, used, available, utilizationPct }
656
+ runners.createRunner(pool, runRef); // Runner record
657
+ runners.assignJob(runnerId, jobRef); // Assignment
658
+ runners.releaseRunner(runnerId); // Release
686
659
  ```
687
660
 
688
- ### Notification Controller
689
-
690
- Source: `packages/krate/core/src/notification-controller.js`
661
+ ### createNotificationController()
691
662
 
692
663
  ```javascript
693
664
  import { createNotificationController } from '@a5c-ai/krate-sdk';
694
- const notifications = createNotificationController();
665
+ const notif = createNotificationController();
666
+ notif.createNotification(event); // Create from event
667
+ notif.listNotifications(org, { unreadOnly, limit, since });
668
+ notif.markAsRead(id); // Mark single
669
+ notif.markAllAsRead(org); // Mark all for org
670
+ notif.getUnreadCount(org); // Count
671
+ notif.getPreferences(userId); // Get prefs
672
+ notif.updatePreferences(userId, { sound: true }); // Update
695
673
  ```
696
674
 
697
- ### Org Scoping
698
-
699
- Source: `packages/krate/core/src/org-scoping.js`
675
+ ### createGiteaService(options)
700
676
 
701
677
  ```javascript
702
- import { orgNamespaceName, normalizeOrgSlug } from '@a5c-ai/krate-sdk';
703
-
704
- orgNamespaceName('acme'); // 'krate-org-acme'
705
- normalizeOrgSlug('Acme Inc'); // 'acme-inc'
678
+ import { createGiteaService } from '@a5c-ai/krate-sdk';
679
+ const gitea = createGiteaService({ baseUrl: 'http://gitea:3000', token: 'admin-token' });
706
680
  ```
707
681
 
708
- ### Permission Review
709
-
710
- Source: `packages/krate/core/src/agent-permission-review.js`
682
+ ### fetchControllerUiModel({ baseUrl, org })
711
683
 
712
684
  ```javascript
713
- import { createPermissionReviewer } from '@a5c-ai/krate-sdk';
714
- const reviewer = createPermissionReviewer();
715
- const result = reviewer.reviewPermissions({ repository, ref, actor, agentStack, resources });
685
+ import { fetchControllerUiModel } from '@a5c-ai/krate-sdk';
686
+ const uiModel = await fetchControllerUiModel({ baseUrl: 'http://localhost:3080', org: 'acme' });
716
687
  ```
717
688
 
718
- ### Secret/Config Grant Management
719
-
720
- Source: `packages/krate/core/src/agent-secret-config-grant-controller.js`
689
+ ### clearSnapshotCache()
721
690
 
722
691
  ```javascript
723
- import {
724
- createAgentSecretGrantController,
725
- createAgentConfigGrantController,
726
- validateAgentSecretGrant,
727
- validateAgentConfigGrant,
728
- listGrantsForAgent,
729
- revokeGrant
730
- } from '@a5c-ai/krate-sdk';
692
+ import { clearSnapshotCache } from '@a5c-ai/krate-sdk';
693
+ clearSnapshotCache(); // Invalidates all per-org cache entries + legacy cache
731
694
  ```
732
695
 
733
- ### Gitea Service
734
-
735
- Source: `packages/krate/core/src/gitea-service.js`
696
+ ### mapOidcIdentity(profile)
736
697
 
737
698
  ```javascript
738
- import { createGiteaService } from '@a5c-ai/krate-sdk';
739
- const gitea = createGiteaService({ baseUrl: 'http://gitea:3000', token: '...' });
699
+ import { mapOidcIdentity } from '@a5c-ai/krate-sdk';
700
+ const identity = mapOidcIdentity({ subject, email, groups });
740
701
  ```
741
702
 
742
- ### Atlas Graph Client
703
+ ---
704
+
705
+ ## 13. Atlas Graph Client
743
706
 
744
707
  Source: `packages/krate/sdk/src/atlas-graph-client.js`
745
708
 
709
+ ### STACK_LAYERS
710
+
711
+ Array of 11 stack layer definitions for the agent stack builder. Each has:
746
712
  ```javascript
747
- import { fetchAtlasRecordsByKinds, searchAtlasGraph, STACK_LAYERS, COMPOSITION_FACETS, ALL_LAYER_DEFS } from '@a5c-ai/krate-sdk';
713
+ { key: 'layer:N-name', label: string, kind: 'stack-layer', position: number, atlasKinds: string[] }
748
714
  ```
749
715
 
750
- | Export | Description |
751
- |--------|-------------|
752
- | `fetchAtlasRecordsByKinds(kinds, options)` | Fetch graph records by node kinds |
753
- | `searchAtlasGraph(query, options)` | Full-text search across Atlas graph |
754
- | `STACK_LAYERS` | Stack layer definitions |
755
- | `COMPOSITION_FACETS` | Composition facet catalog |
756
- | `ALL_LAYER_DEFS` | All layer definition objects |
716
+ Layers: Model, Provider, Transport, Agent Core, Agent Runtime, Agent Platform, Workspace, Execution, Sandbox, Interaction, Presentation.
757
717
 
758
- ### Controller Client
718
+ ### COMPOSITION_FACETS
759
719
 
760
- Source: `packages/krate/core/src/controller-client.js`
720
+ Array of 4 composition facet definitions:
721
+ - Roles and Teams
722
+ - Skills and Capabilities
723
+ - Evaluation and Governance
724
+ - Environment and Data
725
+
726
+ ### ALL_LAYER_DEFS
727
+
728
+ Combined `[...STACK_LAYERS, ...COMPOSITION_FACETS]` — 15 definitions.
729
+
730
+ ### fetchAtlasRecordsByKinds(atlasBaseUrl, kinds, options?)
761
731
 
762
732
  ```javascript
763
- import { fetchControllerUiModel } from '@a5c-ai/krate-sdk';
764
- const uiModel = await fetchControllerUiModel({ baseUrl: 'http://localhost:3080', org: 'acme' });
733
+ import { fetchAtlasRecordsByKinds } from '@a5c-ai/krate-sdk';
734
+ const records = await fetchAtlasRecordsByKinds('https://atlas.example.com', ['ModelFamily', 'ModelVersion'], { limit: 100 });
735
+ // Returns: Array<{ id, nodeKind, displayName, description, cluster }>
765
736
  ```
766
737
 
767
- ### Snapshot Cache
768
-
769
- Source: `packages/krate/core/src/snapshot-cache.js`
738
+ ### searchAtlasGraph(atlasBaseUrl, query, options?)
770
739
 
771
740
  ```javascript
772
- import { clearSnapshotCache } from '@a5c-ai/krate-sdk';
773
- clearSnapshotCache(); // Invalidate all cached data
741
+ import { searchAtlasGraph } from '@a5c-ai/krate-sdk';
742
+ const result = await searchAtlasGraph('https://atlas.example.com', 'claude', { kinds: ['ModelFamily'], limit: 25 });
743
+ // Returns: { total, hits: Array<{ id, nodeKind, displayName, cluster, score, snippet }> }
774
744
  ```
775
745
 
776
- ### Identity Policy
746
+ ---
747
+
748
+ ## 14. Boundary Constants
777
749
 
778
- Source: `packages/krate/core/src/identity-policy.js`
750
+ All boundary declarations are also exported for runtime introspection:
779
751
 
780
752
  ```javascript
781
- import { mapOidcIdentity } from '@a5c-ai/krate-sdk';
753
+ import {
754
+ KRATE_API_CONTROLLER_BOUNDARY,
755
+ AGENT_STACK_CONTROLLER_BOUNDARY,
756
+ AGENT_DISPATCH_CONTROLLER_BOUNDARY,
757
+ AGENT_WORKSPACE_CONTROLLER_BOUNDARY,
758
+ AGENT_TRIGGER_CONTROLLER_BOUNDARY,
759
+ AGENT_APPROVAL_CONTROLLER_BOUNDARY,
760
+ AGENT_MEMORY_QUERY_BOUNDARY,
761
+ AGENT_PERMISSION_REVIEW_BOUNDARY,
762
+ AGENT_SECRET_GRANT_CONTROLLER_BOUNDARY,
763
+ AGENT_CONFIG_GRANT_CONTROLLER_BOUNDARY,
764
+ AGENT_ADAPTER_CONTROLLER_BOUNDARY,
765
+ AGENT_TRANSPORT_BINDING_CONTROLLER_BOUNDARY,
766
+ AGENT_PROVIDER_CONFIG_CONTROLLER_BOUNDARY,
767
+ AGENT_PROJECT_CONTROLLER_BOUNDARY,
768
+ AGENT_GATEWAY_CONFIG_CONTROLLER_BOUNDARY,
769
+ AGENT_SESSION_TRANSCRIPT_CONTROLLER_BOUNDARY,
770
+ AGENT_SUBAGENT_CONTROLLER_BOUNDARY,
771
+ AGENT_WRITEBACK_CONTROLLER_BOUNDARY,
772
+ AUDIT_CONTROLLER_BOUNDARY,
773
+ RUNNER_CONTROLLER_BOUNDARY,
774
+ NOTIFICATION_CONTROLLER_BOUNDARY,
775
+ AGENT_MEMORY_CONTROLLER_BOUNDARY
776
+ } from '@a5c-ai/krate-sdk';
782
777
  ```
778
+
779
+ Each exports `{ role, scope, owns, delegatesTo, mustNotOwn }`.