@a5c-ai/krate 5.0.1-staging.660d2b90f → 5.0.1-staging.69cb593ea

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 (118) hide show
  1. package/Dockerfile +31 -29
  2. package/bin/krate-demo.mjs +0 -0
  3. package/bin/krate-server.mjs +0 -0
  4. package/dist/krate-controller-ui.json +808 -10
  5. package/dist/krate-lifecycle.json +1 -1
  6. package/dist/krate-runtime-snapshot.json +223 -53
  7. package/dist/krate-summary.json +40 -3
  8. package/docs/agents/gaps-agent-mux-to-krate-crds.md +298 -0
  9. package/docs/architecture-v2.md +431 -0
  10. package/docs/openapi.yaml +1275 -0
  11. package/docs/requirements-v2.md +238 -0
  12. package/docs/sdk-api-reference.md +782 -0
  13. package/docs/system-spec-v2.md +352 -0
  14. package/docs/todos.md +4 -0
  15. package/docs/web-console-spec.md +433 -0
  16. package/package.json +1 -1
  17. package/scripts/validate-ui.mjs +305 -207
  18. package/src/agent-adapter-controller.js +169 -0
  19. package/src/agent-approval-controller.js +47 -0
  20. package/src/agent-dispatch-controller.js +130 -7
  21. package/src/agent-gateway-config-controller.js +147 -0
  22. package/src/agent-memory-controller.js +357 -0
  23. package/src/agent-memory-import.js +327 -0
  24. package/src/agent-memory-query.js +292 -0
  25. package/src/agent-memory-repository-source-controller.js +255 -0
  26. package/src/agent-mux-client.js +1 -1
  27. package/src/agent-permission-review.js +102 -14
  28. package/src/agent-project-controller.js +117 -0
  29. package/src/agent-provider-config-controller.js +150 -0
  30. package/src/agent-secret-config-grant-controller.js +282 -0
  31. package/src/agent-session-transcript-controller.js +189 -0
  32. package/src/agent-stack-controller.js +52 -1
  33. package/src/agent-subagent-controller.js +160 -0
  34. package/src/agent-transport-binding-controller.js +121 -0
  35. package/src/agent-trigger-controller.js +273 -0
  36. package/src/agent-workspace-controller.js +702 -0
  37. package/src/agent-writeback-controller.js +302 -0
  38. package/src/api-controller.js +338 -3
  39. package/src/async-controller.js +207 -0
  40. package/src/audit-controller.js +191 -0
  41. package/src/auth.js +48 -6
  42. package/src/controller-client.js +112 -38
  43. package/src/controller-ui.js +96 -16
  44. package/src/data-plane.js +3 -2
  45. package/src/event-bus.js +61 -0
  46. package/src/external/conflict-controller.js +225 -0
  47. package/src/external/github/auth.js +96 -0
  48. package/src/external/github/cicd.js +180 -0
  49. package/src/external/github/git-forge.js +240 -0
  50. package/src/external/github/index.js +144 -0
  51. package/src/external/github/issue-tracking.js +163 -0
  52. package/src/external/provider-adapter.js +161 -0
  53. package/src/external/provider-resource-factory.js +161 -0
  54. package/src/external/sync-controller.js +235 -0
  55. package/src/external/webhook-controller.js +144 -0
  56. package/src/external/write-controller.js +283 -0
  57. package/src/gitea-backend.js +36 -0
  58. package/src/gitea-service.js +173 -0
  59. package/src/http-server.js +226 -0
  60. package/src/index.js +27 -0
  61. package/src/kubernetes-controller-async.js +531 -0
  62. package/src/kubernetes-controller.js +156 -84
  63. package/src/notification-controller.js +178 -0
  64. package/src/org-scoping.js +5 -0
  65. package/src/resource-model.js +26 -8
  66. package/src/runner-controller.js +272 -0
  67. package/src/snapshot-cache.js +157 -0
  68. package/tests/agent-adapter-controller.test.js +361 -0
  69. package/tests/agent-dispatch-controller.test.js +139 -0
  70. package/tests/agent-gateway-config-controller.test.js +386 -0
  71. package/tests/agent-memory-controller.test.js +308 -0
  72. package/tests/agent-memory-import-snapshot.test.js +477 -0
  73. package/tests/agent-memory-query.test.js +404 -0
  74. package/tests/agent-memory-repository-source.test.js +514 -0
  75. package/tests/agent-permission-review-v2.test.js +317 -0
  76. package/tests/agent-project-controller.test.js +302 -0
  77. package/tests/agent-provider-config-controller.test.js +376 -0
  78. package/tests/agent-resources.test.js +35 -19
  79. package/tests/agent-secret-config-grant.test.js +231 -0
  80. package/tests/agent-session-transcript-controller.test.js +499 -0
  81. package/tests/agent-subagent-controller.test.js +201 -0
  82. package/tests/agent-transport-binding-controller.test.js +294 -0
  83. package/tests/agent-trigger-routes.test.js +190 -0
  84. package/tests/agent-trigger-sources.test.js +245 -0
  85. package/tests/agent-workspace-controller.test.js +181 -0
  86. package/tests/agent-writeback.test.js +292 -0
  87. package/tests/approval-persistence.test.js +171 -0
  88. package/tests/async-controller.test.js +252 -0
  89. package/tests/audit-controller.test.js +227 -0
  90. package/tests/codespace-controller.test.js +318 -0
  91. package/tests/controller-client.test.js +133 -0
  92. package/tests/deployment.test.js +43 -29
  93. package/tests/e2e/lifecycle.test.js +5 -2
  94. package/tests/event-bus-integration.test.js +190 -0
  95. package/tests/external-github-forge.test.js +560 -0
  96. package/tests/external-github-issues-cicd.test.js +520 -0
  97. package/tests/external-integration.test.js +470 -0
  98. package/tests/external-persistence.test.js +340 -0
  99. package/tests/external-provider-adapter.test.js +365 -0
  100. package/tests/external-resource-model.test.js +215 -0
  101. package/tests/external-webhook-sync.test.js +287 -0
  102. package/tests/external-write-conflict.test.js +353 -0
  103. package/tests/gitea-service.test.js +253 -0
  104. package/tests/health-check-real.test.js +165 -0
  105. package/tests/integration/full-flow.test.js +266 -0
  106. package/tests/krate.test.js +58 -6
  107. package/tests/memory-search-wiring.test.js +270 -0
  108. package/tests/notification-controller.test.js +196 -0
  109. package/tests/notification-integration.test.js +179 -0
  110. package/tests/org-scoping.test.js +687 -0
  111. package/tests/runner-controller.test.js +327 -0
  112. package/tests/runner-integration.test.js +231 -0
  113. package/tests/session-cookie-hmac.test.js +151 -0
  114. package/tests/snapshot-performance.test.js +315 -0
  115. package/tests/sse-events.test.js +107 -0
  116. package/tests/webhook-trigger.test.js +198 -0
  117. package/tests/workspace-volumes.test.js +312 -0
  118. package/tests/writeback-persistence.test.js +207 -0
@@ -0,0 +1,431 @@
1
+ # Krate Architecture Specification v2
2
+
3
+ > Derived from implementation. Last updated from source analysis.
4
+
5
+ ## 1. System Overview
6
+
7
+ Krate is a Kubernetes-native Git forge runtime built as a monorepo with four packages:
8
+
9
+ | Package | NPM Name | Role | Path |
10
+ |---------|-----------|------|------|
11
+ | **core** | `@a5c-ai/krate` | Resource model, controllers, HTTP API server | `packages/krate/core/` |
12
+ | **sdk** | `@a5c-ai/krate-sdk` | Client SDK re-exporting core helpers for web/CLI consumers | `packages/krate/sdk/` |
13
+ | **cli** | `@a5c-ai/krate-cli` | CLI entrypoint and MCP server mode | `packages/krate/cli/` |
14
+ | **web** | `@a5c-ai/krate-web` | Next.js 16 + React 19 web console | `packages/krate/web/` |
15
+
16
+ **Design principles:**
17
+ - Pure ESM JavaScript (Node 20+), zero external runtime dependencies in core
18
+ - Kubernetes-first: all resources are K8s API objects (CRDs or aggregated)
19
+ - CRD-driven: 75 CustomResourceDefinitions under `krate.a5c.ai/v1alpha1`
20
+ - Controller pattern: each domain has a controller with explicit boundary declarations
21
+
22
+ ```mermaid
23
+ graph TB
24
+ subgraph "Krate Platform"
25
+ WEB[Web Console<br/>Next.js 16 + React 19]
26
+ CLI[CLI + MCP Server]
27
+ SDK[SDK Layer]
28
+ CORE[Core Controllers]
29
+ end
30
+
31
+ subgraph "Infrastructure"
32
+ K8S[Kubernetes API<br/>etcd storage]
33
+ PG[PostgreSQL<br/>Aggregated storage]
34
+ GITEA[Gitea<br/>Git hosting]
35
+ end
36
+
37
+ WEB --> SDK
38
+ CLI --> SDK
39
+ SDK --> CORE
40
+ CORE --> K8S
41
+ CORE --> PG
42
+ CORE --> GITEA
43
+ ```
44
+
45
+ ---
46
+
47
+ ## 2. Data Model
48
+
49
+ ### 2.1 Storage Split
50
+
51
+ Krate manages **76 resource kinds** across two storage backends:
52
+
53
+ - **CONFIG storage (etcd)**: 44 kinds — organizational configuration, policies, agent definitions. Stored as Kubernetes CRDs.
54
+ - **AGGREGATED storage (postgres)**: 32 kinds — operational data, event records, runtime state. Stored in PostgreSQL.
55
+
56
+ Source: `packages/krate/core/src/resource-model.js`
57
+
58
+ ### 2.2 Resource Schema
59
+
60
+ Every resource follows the Kubernetes object model:
61
+
62
+ ```javascript
63
+ {
64
+ apiVersion: 'krate.a5c.ai/v1alpha1',
65
+ kind: '<ResourceKind>',
66
+ metadata: {
67
+ name: '<unique-name>',
68
+ namespace: 'krate-org-<org>',
69
+ labels: { 'krate.a5c.ai/org': '<org>' },
70
+ annotations: {}
71
+ },
72
+ spec: { /* kind-specific specification */ },
73
+ status: { /* reconciled status */ }
74
+ }
75
+ ```
76
+
77
+ ### 2.3 Domain Organization
78
+
79
+ | Domain Context | CONFIG Kinds | AGGREGATED Kinds | Purpose |
80
+ |----------------|-------------|------------------|---------|
81
+ | **identity** | Organization, OrgNamespaceBinding, User, Team, Invite, IdentityMapping, AuthProvider, AgentServiceAccount, AgentRoleBinding, AgentSecretGrant, AgentConfigGrant | — | Users, teams, identity, RBAC |
82
+ | **data-plane** | Repository, SSHKey, RepositoryPermission, RefPolicy | — | Repository management |
83
+ | **control-plane** | BranchProtection | PullRequest, Issue, Review | Code review lifecycle |
84
+ | **policy** | PolicyProfile, PolicyTemplate, PolicyBinding, PolicyExceptionRequest | — | Kyverno policy management |
85
+ | **agents** | AgentStack, AgentSubagent, AgentToolProfile, AgentMcpServer, AgentSkill, AgentTriggerRule, AgentContextLabel, KrateWorkspacePolicy, AgentAdapter, AgentTransportBinding, AgentProviderConfig, KrateProject, AgentGatewayConfig, AgentMemoryRepository, AgentMemorySource, AgentMemoryOntology, AgentMemoryAssociation | AgentDispatchRun, AgentDispatchAttempt, AgentSession, AgentContextBundle, KrateArtifact, AgentApproval, AgentTriggerExecution, AgentCapabilityRequirement, WorkItemSessionLink, WorkItemWorkspaceLink, AgentSessionTranscript, AgentSessionAttachment, KrateWorkspaceRuntime, AgentMemorySnapshot, AgentMemoryQuery, AgentMemoryUpdate, AgentRunMemoryImport | Agent orchestration |
86
+ | **workspaces** | KrateWorkspace | — | Git workspace management |
87
+ | **external-backends** | ExternalBackendProvider, ExternalBackendBinding, ExternalBackendSyncPolicy, ExternalProviderCapabilityManifest | ExternalWebhookDelivery, ExternalSyncEvent, ExternalSyncState, ExternalWriteIntent, ExternalSyncConflict, ExternalObjectLink | External system integration |
88
+ | **runners-ci** | RunnerPool | Pipeline, Job | CI/CD execution |
89
+ | **hooks-events** | WebhookSubscription | WebhookDelivery | Webhook management |
90
+ | **web-ui** | View, Selector | — | Saved views and selectors |
91
+
92
+ ---
93
+
94
+ ## 3. Control Plane
95
+
96
+ Source: `packages/krate/core/src/kubernetes-controller.js`, `kubernetes-controller-async.js`, `kubernetes-resource-gateway.js`
97
+
98
+ ### 3.1 Resource Reconciliation
99
+
100
+ The control plane uses kubectl to interact with the Kubernetes API server. Resources are reconciled through:
101
+
102
+ 1. **kubectl get** — list/get resources by kind and namespace
103
+ 2. **kubectl apply** — create/update resources declaratively
104
+ 3. **kubectl delete** — remove resources
105
+
106
+ The `createKubernetesResourceGateway()` provides an async wrapper over kubectl operations.
107
+
108
+ ### 3.2 Namespace Scoping
109
+
110
+ ```
111
+ Namespace pattern: krate-org-{orgSlug}
112
+ ```
113
+
114
+ Each organization gets an isolated Kubernetes namespace (`krate-org-<org>`). The `orgNamespaceName(org)` helper (from `org-scoping.js`) computes the namespace name.
115
+
116
+ Platform-scoped resources (Organization, OrgNamespaceBinding) live in `krate-system` namespace.
117
+
118
+ ### 3.3 Org Isolation
119
+
120
+ - `OrgNamespaceBinding` maps one organization to exactly one tenant namespace
121
+ - All org-scoped resources carry `metadata.labels['krate.a5c.ai/org']`
122
+ - API routes extract org from URL path and scope controllers to that namespace
123
+
124
+ ### 3.4 Stale-While-Revalidate Cache
125
+
126
+ Source: `packages/krate/core/src/snapshot-cache.js`
127
+
128
+ ```javascript
129
+ CACHE_TTL_MS = 30_000 // 30 seconds, configurable via KRATE_SNAPSHOT_CACHE_TTL_MS
130
+ ```
131
+
132
+ - Per-org cache map stores `{ data, timestamp, revalidating }`
133
+ - Returns stale data immediately while refreshing in background
134
+ - Prevents kubectl overhead on repeated snapshot requests
135
+
136
+ ---
137
+
138
+ ## 4. Data Plane
139
+
140
+ ### 4.1 Aggregated Resources
141
+
142
+ Stored in PostgreSQL (in-memory for development):
143
+
144
+ | Kind | Purpose |
145
+ |------|---------|
146
+ | PullRequest | Review unit with source/target refs, checks, merge lifecycle |
147
+ | Issue | Project-scoped work item with labels, comments, backend sync |
148
+ | Review | Approval/comment/change-request for a pull request |
149
+ | Pipeline | CI pipeline run state, trust tier, steps, resume point |
150
+ | Job | Executable CI step with service-account scope |
151
+
152
+ ### 4.2 Git Layer (Gitea)
153
+
154
+ Source: `packages/krate/core/src/gitea-service.js`, `gitea-backend.js`
155
+
156
+ - Repository storage and hosting
157
+ - Branch management (create, list, delete)
158
+ - Tree/blob API for code browsing
159
+ - SSH key reconciliation with repository access
160
+
161
+ ### 4.3 Search Index
162
+
163
+ The HTTP API exposes `POST /api/orgs/:org/repositories/:repo/search-index` to enqueue search indexing for a repository.
164
+
165
+ ---
166
+
167
+ ## 5. Agent Orchestration
168
+
169
+ Source: `packages/krate/core/src/agent-stack-controller.js`, `agent-dispatch-controller.js`, `agent-workspace-controller.js`, `agent-trigger-controller.js`, `agent-approval-controller.js`
170
+
171
+ ### 5.1 Lifecycle Flow
172
+
173
+ ```mermaid
174
+ sequenceDiagram
175
+ participant Trigger as AgentTriggerRule
176
+ participant Stack as AgentStack
177
+ participant Dispatch as AgentDispatchRun
178
+ participant Attempt as AgentDispatchAttempt
179
+ participant Session as AgentSession
180
+ participant Workspace as KrateWorkspace
181
+
182
+ Trigger->>Dispatch: Event matches rule → create run
183
+ Dispatch->>Stack: Resolve stack definition
184
+ Stack->>Dispatch: Capabilities, approval mode
185
+ Dispatch->>Attempt: Create execution attempt
186
+ Attempt->>Session: Bind Agent Mux session
187
+ Attempt->>Workspace: Provision workspace (PVC)
188
+ Session->>Workspace: Mount and execute
189
+ ```
190
+
191
+ ### 5.2 Stack Definition
192
+
193
+ `AgentStack` defines a reusable agent with:
194
+ - Base agent and adapter selection
195
+ - Model and prompt configuration
196
+ - MCP servers, skills, subagents
197
+ - Tool profiles and approval mode
198
+ - Runner policy and runtime identity
199
+
200
+ ### 5.3 Trigger System
201
+
202
+ `AgentTriggerRule` routes events to stacks based on:
203
+ - CI failures (`pipeline-failure`)
204
+ - Webhook events
205
+ - Comments on issues/PRs
206
+ - Label additions
207
+ - Cron schedules
208
+ - Manual dispatch
209
+
210
+ ### 5.4 Supporting Resources
211
+
212
+ | Resource | Role |
213
+ |----------|------|
214
+ | AgentAdapter | Transport type, capabilities matrix, auth requirements |
215
+ | AgentTransportBinding | Endpoint, protocol, auth, health, reconnect policy |
216
+ | AgentProviderConfig | Model provider with API base, auth, rate limits |
217
+ | AgentGatewayConfig | Agent Mux gateway connection settings |
218
+ | AgentContextBundle | Immutable prompt/context snapshot |
219
+ | AgentApproval | Human approval gate for tools, secrets, write-back |
220
+ | AgentSessionTranscript | Chat transcript with message nodes and cost |
221
+
222
+ ---
223
+
224
+ ## 6. External Backend Pipeline
225
+
226
+ Source: `packages/krate/core/src/external/`
227
+
228
+ ### 6.1 Pipeline Architecture
229
+
230
+ ```mermaid
231
+ graph LR
232
+ A[ExternalBackendProvider] --> B[ExternalBackendBinding]
233
+ B --> C[ExternalWebhookDelivery]
234
+ C --> D[ExternalSyncEvent]
235
+ D --> E{Conflict?}
236
+ E -->|Yes| F[ExternalSyncConflict]
237
+ E -->|No| G[ExternalSyncState]
238
+ F --> H[Resolution]
239
+ H --> G
240
+ G --> I[ExternalWriteIntent]
241
+ I --> J[ExternalObjectLink]
242
+ ```
243
+
244
+ ### 6.2 Controllers
245
+
246
+ | Controller | File | Responsibility |
247
+ |-----------|------|----------------|
248
+ | WebhookController | `external/webhook-controller.js` | HMAC-SHA256 verification, dedup, async event queue |
249
+ | SyncController | `external/sync-controller.js` | Sync event processing, state management, watermarks |
250
+ | ConflictController | `external/conflict-controller.js` | Conflict detection, resolution strategies |
251
+ | WriteController | `external/write-controller.js` | Write intent queuing, approval, execution |
252
+ | ProviderAdapter | `external/provider-adapter.js` | Provider-specific translation |
253
+
254
+ ### 6.3 GitHub Adapter
255
+
256
+ Source: `packages/krate/core/src/external/github/`
257
+
258
+ - `auth.js` — GitHub App authentication, installation tokens
259
+ - `git-forge.js` — Repository, branch, PR operations
260
+ - `issue-tracking.js` — Issues, labels, comments
261
+ - `cicd.js` — Actions, workflows, check runs
262
+ - `index.js` — Unified GitHub adapter facade
263
+
264
+ ---
265
+
266
+ ## 7. Memory System
267
+
268
+ Source: `packages/krate/core/src/agent-memory-controller.js`, `agent-memory-query.js`, `agent-memory-import.js`, `agent-memory-repository-source-controller.js`
269
+
270
+ ### 7.1 Pipeline
271
+
272
+ ```mermaid
273
+ graph LR
274
+ A[AgentMemoryRepository] --> B[AgentMemorySource]
275
+ B --> C[AgentMemoryOntology]
276
+ C --> D[AgentMemorySnapshot]
277
+ D --> E[AgentMemoryQuery]
278
+ F[AgentRunMemoryImport] --> A
279
+ G[AgentMemoryAssociation] --> A
280
+ H[AgentMemoryUpdate] --> A
281
+ ```
282
+
283
+ ### 7.2 Query Engine
284
+
285
+ Source: `packages/krate/core/src/agent-memory-query.js`
286
+
287
+ Three query modes:
288
+ - **graph-only** — Graph traversal with adjacency, depth, nodeKind filtering, relevance scoring
289
+ - **grep-only** — Full-text grep with context extraction
290
+ - **graph-and-grep** — Combined query execution
291
+
292
+ ```javascript
293
+ queryGraph({ records, edges, query, kinds, depth })
294
+ queryGrep({ documents, query, contextLines })
295
+ queryMemory({ records, documents, edges, query, mode, kinds, depth, contextLines })
296
+ ```
297
+
298
+ ### 7.3 Memory Import
299
+
300
+ `AgentRunMemoryImport` imports curated babysitter run metadata into org memory with redaction and review controls.
301
+
302
+ ---
303
+
304
+ ## 8. Authentication Model
305
+
306
+ Source: `packages/krate/core/src/auth.js`
307
+
308
+ ### 8.1 Providers
309
+
310
+ | Provider | Type | Configuration |
311
+ |----------|------|---------------|
312
+ | GitHub | OAuth 2.0 | `KRATE_AUTH_GITHUB_*` env vars |
313
+ | SSO | OIDC | `KRATE_AUTH_SSO_*` env vars |
314
+ | Delegated | Header-based | `KRATE_AUTH_DELEGATED_*` env vars |
315
+
316
+ ### 8.2 Session Management
317
+
318
+ - Cookie name: `krate_session` (configurable via `KRATE_AUTH_COOKIE_NAME`)
319
+ - Format: `base64url(payload).hmac_sha256_signature`
320
+ - HMAC secret: `KRATE_SESSION_SECRET`
321
+ - Timing-safe comparison for signature verification
322
+ - `HttpOnly; SameSite=Lax` cookie attributes
323
+
324
+ ### 8.3 Delegated Identity
325
+
326
+ For environments with upstream proxy authentication:
327
+ - `x-forwarded-user` header (user identity)
328
+ - `x-forwarded-groups` header (group memberships)
329
+ - `x-forwarded-email` header (email address)
330
+ - Local development fallback with configurable defaults
331
+
332
+ ### 8.4 Auth Middleware
333
+
334
+ All mutating API routes require authentication. The session cookie is parsed and verified on each request. Admin detection uses group membership (`krate:platform-engineers`, `krate:repo-admins`).
335
+
336
+ ---
337
+
338
+ ## 9. Deployment Architecture
339
+
340
+ ### 9.1 Helm Chart
341
+
342
+ The Krate Helm chart deploys multi-container pods:
343
+
344
+ | Container | Role |
345
+ |-----------|------|
346
+ | api | HTTP API server (port 3080) |
347
+ | controllers | Background reconciliation controllers |
348
+ | web | Next.js web console |
349
+ | webhook-worker | Inbound webhook processing |
350
+
351
+ ### 9.2 Infrastructure Requirements
352
+
353
+ - **AKS** (Azure Kubernetes Service) or compatible K8s cluster
354
+ - **ACR** (Azure Container Registry) for image storage
355
+ - **cert-manager** for TLS certificate provisioning
356
+ - **nginx ingress** controller for HTTP routing
357
+ - **PostgreSQL** for aggregated resource storage
358
+ - **Gitea** for Git hosting backend
359
+
360
+ ### 9.3 CRD Management
361
+
362
+ 75 CRDs are defined under `krate.a5c.ai/v1alpha1`. All use:
363
+ - `x-kubernetes-preserve-unknown-fields: true` for spec extensibility
364
+ - Namespaced scope (platform resources in `krate-system`)
365
+ - Labels for org association
366
+
367
+ ---
368
+
369
+ ## 10. Performance Architecture
370
+
371
+ ### 10.1 Caching Strategy
372
+
373
+ | Layer | Mechanism | TTL |
374
+ |-------|-----------|-----|
375
+ | Snapshot cache | Stale-while-revalidate | 30s (configurable) |
376
+ | Per-org cache | Map-based, independent revalidation | 30s |
377
+ | kubectl | Async spawn with output buffering | Per-request |
378
+
379
+ ### 10.2 Async Patterns
380
+
381
+ Source: `packages/krate/core/src/async-controller.js`
382
+
383
+ | Utility | Purpose |
384
+ |---------|---------|
385
+ | `createEventBatcher` | Accumulates events, flushes by size or interval |
386
+ | `createRetryPolicy` | Exponential backoff with jitter |
387
+ | `createDeliveryQueue` | Ordered async delivery with error isolation |
388
+ | `createCheckpointer` | Progress checkpoints for long-running operations |
389
+
390
+ ### 10.3 Event Bus
391
+
392
+ Source: `packages/krate/core/src/event-bus.js`
393
+
394
+ - Global singleton (`globalEventBus`)
395
+ - Pub/sub pattern: `subscribe(fn)`, `unsubscribe(fn)`, `emit(event)`
396
+ - SSE streaming via `/api/orgs/:org/agents/events/stream`
397
+ - 30s heartbeat for connection keepalive
398
+
399
+ ---
400
+
401
+ ## 11. Security Model
402
+
403
+ ### 11.1 Session Security
404
+
405
+ - HMAC-SHA256 signing of session cookies
406
+ - `timingSafeEqual` for signature comparison (prevents timing attacks)
407
+ - Signed cookies rejected when no secret configured
408
+ - Unsigned cookies rejected when secret is configured
409
+
410
+ ### 11.2 API Security
411
+
412
+ - Auth middleware on all mutating routes
413
+ - Org scoping prevents cross-tenant access
414
+ - Namespace isolation in Kubernetes
415
+
416
+ ### 11.3 Webhook Security
417
+
418
+ - HMAC-SHA256 verification for inbound webhooks
419
+ - Timing-safe signature comparison
420
+ - Deduplication by delivery ID
421
+
422
+ ### 11.4 Kubernetes RBAC
423
+
424
+ - ClusterRole for Krate CRD access
425
+ - ServiceAccount binding per agent (`AgentServiceAccount`)
426
+ - `AgentRoleBinding` for managed RBAC projection
427
+ - `AgentSecretGrant` / `AgentConfigGrant` for explicit secret access
428
+
429
+ ### 11.5 CRD Extensibility
430
+
431
+ All CRDs use `x-kubernetes-preserve-unknown-fields: true` allowing spec evolution without CRD version bumps.