@escalay/kit 0.0.0-stage → 1.8.0

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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -2
  3. package/cli.mjs +438 -0
  4. package/docs/STANDARD.md +342 -0
  5. package/docs/decisions/0001-features-drizzle-scaffold.md +35 -0
  6. package/docs/decisions/0002-node-and-workers.md +45 -0
  7. package/docs/releasing.md +97 -0
  8. package/package.json +59 -3
  9. package/registry.json +548 -0
  10. package/src/a2a/README.md +25 -0
  11. package/src/a2a/index.ts +262 -0
  12. package/src/boards/README.md +35 -0
  13. package/src/boards/handlers.ts +87 -0
  14. package/src/boards/index.ts +64 -0
  15. package/src/boards/refs.ts +23 -0
  16. package/src/boards/repo.ts +50 -0
  17. package/src/boards/routes.ts +83 -0
  18. package/src/boards/schema.ts +28 -0
  19. package/src/boards/tools.ts +76 -0
  20. package/src/browser/README.md +31 -0
  21. package/src/browser/boards-client.ts +74 -0
  22. package/src/browser/boards-react.ts +73 -0
  23. package/src/browser/search-client.ts +258 -0
  24. package/src/browser/search-react.ts +116 -0
  25. package/src/browser/vector-search-block.tsx +94 -0
  26. package/src/core/README.md +37 -0
  27. package/src/core/api.ts +239 -0
  28. package/src/core/auth.ts +147 -0
  29. package/src/core/cache.ts +53 -0
  30. package/src/core/discovery.ts +315 -0
  31. package/src/core/guards.ts +109 -0
  32. package/src/core/hal.ts +63 -0
  33. package/src/core/kv.ts +29 -0
  34. package/src/core/problem.ts +124 -0
  35. package/src/db/README.md +39 -0
  36. package/src/db/guards.ts +61 -0
  37. package/src/db/index.ts +122 -0
  38. package/src/guide/README.md +38 -0
  39. package/src/guide/guide.ts +152 -0
  40. package/src/guide/reference.ts +204 -0
  41. package/src/index.ts +15 -0
  42. package/src/mcp/README.md +34 -0
  43. package/src/mcp/index.ts +251 -0
  44. package/src/oauth/README.md +29 -0
  45. package/src/oauth/index.ts +439 -0
  46. package/src/oauth/schema.ts +7 -0
  47. package/src/oauth/store.ts +34 -0
  48. package/src/pagination/README.md +31 -0
  49. package/src/pagination/index.ts +65 -0
  50. package/src/testing/README.md +31 -0
  51. package/src/testing/index.ts +162 -0
  52. package/src/vector-search/README.md +27 -0
  53. package/src/vector-search/index.ts +367 -0
  54. package/src/vectors/README.md +30 -0
  55. package/src/vectors/index.ts +326 -0
  56. package/src/web/README.md +21 -0
  57. package/src/web/index.ts +100 -0
  58. package/templates/app/AGENTS.md +41 -0
  59. package/templates/app/CLAUDE.md +3 -0
  60. package/templates/app/Dockerfile +12 -0
  61. package/templates/app/container/entrypoint.sh +7 -0
  62. package/templates/app/gitignore +4 -0
  63. package/templates/app/guide/llms.txt +11 -0
  64. package/templates/app/pnpm-workspace.yaml +5 -0
  65. package/templates/app/scripts/guide.ts +8 -0
  66. package/templates/app/src/app.ts +39 -0
  67. package/templates/app/src/features/index.ts +30 -0
  68. package/templates/app/src/server.ts +14 -0
  69. package/templates/app/test/api.test.ts +34 -0
  70. package/templates/app/tsconfig.json +16 -0
  71. package/templates/feature/feature.test.ts +19 -0
  72. package/templates/feature/handlers.ts +43 -0
  73. package/templates/feature/index.ts +34 -0
  74. package/templates/feature/repo.ts +24 -0
  75. package/templates/feature/routes.ts +43 -0
  76. package/templates/feature/schema.ts +14 -0
  77. package/templates/feature/tools.ts +46 -0
  78. package/templates/npm-release/release-please-config.json +60 -0
  79. package/templates/npm-release/release-please-manifest.json +3 -0
  80. package/templates/runtime-cloudflare/dev.vars.example +3 -0
  81. package/templates/runtime-cloudflare/scripts/migrations.ts +43 -0
  82. package/templates/runtime-cloudflare/src/worker.ts +19 -0
  83. package/templates/runtime-cloudflare/test/workers/api.test.ts +37 -0
  84. package/templates/runtime-cloudflare/test/workers/apply-migrations.ts +5 -0
  85. package/templates/runtime-cloudflare/test/workers/env.d.ts +11 -0
  86. package/templates/runtime-cloudflare/test/workers/key.ts +2 -0
  87. package/templates/runtime-cloudflare/test/workers/tsconfig.json +7 -0
  88. package/templates/runtime-cloudflare/vitest.config.ts +23 -0
  89. package/templates/runtime-cloudflare/wrangler.jsonc +16 -0
package/registry.json ADDED
@@ -0,0 +1,548 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema/registry.json",
3
+ "name": "escalay",
4
+ "homepage": "https://github.com/escalay/api-kit",
5
+ "items": [
6
+ {
7
+ "name": "core",
8
+ "type": "registry:item",
9
+ "title": "Core",
10
+ "description": "createAgentApi: OpenAPI 3.1 + Scalar docs, HAL links, problem+json, API keys + Access, ETags and Cache-Control, Idempotency-Key and rate limits, discovery (api-catalog, Link headers, robots.txt, Markdown for agents), a key-value store type; an OAuth server plugs in from the `oauth` part",
11
+ "dependencies": [
12
+ "hono@^4.13.14",
13
+ "@hono/zod-openapi@^1.6.3",
14
+ "zod@^4.6.7",
15
+ "jose@^6.2.14",
16
+ "@scalar/hono-api-reference@^0.12.17"
17
+ ],
18
+ "files": [
19
+ {
20
+ "path": "src/core/api.ts",
21
+ "type": "registry:file",
22
+ "target": "~/src/kit/core/api.ts"
23
+ },
24
+ {
25
+ "path": "src/core/auth.ts",
26
+ "type": "registry:file",
27
+ "target": "~/src/kit/core/auth.ts"
28
+ },
29
+ {
30
+ "path": "src/core/cache.ts",
31
+ "type": "registry:file",
32
+ "target": "~/src/kit/core/cache.ts"
33
+ },
34
+ {
35
+ "path": "src/core/discovery.ts",
36
+ "type": "registry:file",
37
+ "target": "~/src/kit/core/discovery.ts"
38
+ },
39
+ {
40
+ "path": "src/core/guards.ts",
41
+ "type": "registry:file",
42
+ "target": "~/src/kit/core/guards.ts"
43
+ },
44
+ {
45
+ "path": "src/core/hal.ts",
46
+ "type": "registry:file",
47
+ "target": "~/src/kit/core/hal.ts"
48
+ },
49
+ {
50
+ "path": "src/core/kv.ts",
51
+ "type": "registry:file",
52
+ "target": "~/src/kit/core/kv.ts"
53
+ },
54
+ {
55
+ "path": "src/core/problem.ts",
56
+ "type": "registry:file",
57
+ "target": "~/src/kit/core/problem.ts"
58
+ },
59
+ {
60
+ "path": "src/core/README.md",
61
+ "type": "registry:file",
62
+ "target": "~/src/kit/core/README.md"
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ "name": "db",
68
+ "type": "registry:item",
69
+ "title": "Database",
70
+ "description": "The app's database through Drizzle: `openDb` (node:sqlite, Turso/libSQL, or any async Drizzle SQLite database), `migrate` (each feature's steps, recorded in `kit_migrations`), `testDb`; `dbGuardStore` (idempotency and rate limits shared by every instance)",
71
+ "dependencies": [
72
+ "drizzle-orm@^0.45.4"
73
+ ],
74
+ "registryDependencies": [
75
+ "escalay/api-kit/core"
76
+ ],
77
+ "files": [
78
+ {
79
+ "path": "src/db/index.ts",
80
+ "type": "registry:file",
81
+ "target": "~/src/kit/db/index.ts"
82
+ },
83
+ {
84
+ "path": "src/db/guards.ts",
85
+ "type": "registry:file",
86
+ "target": "~/src/kit/db/guards.ts"
87
+ },
88
+ {
89
+ "path": "src/db/README.md",
90
+ "type": "registry:file",
91
+ "target": "~/src/kit/db/README.md"
92
+ }
93
+ ]
94
+ },
95
+ {
96
+ "name": "oauth",
97
+ "type": "registry:item",
98
+ "title": "OAuth server",
99
+ "description": "The app as its own OAuth server: metadata, `/oauth/*`, agent registration (auth.md), ES256 tokens; `createOAuth`, `dbOAuthStore`, `memoryOAuthStore`, `generateOAuthKey`",
100
+ "registryDependencies": [
101
+ "escalay/api-kit/core",
102
+ "escalay/api-kit/db"
103
+ ],
104
+ "files": [
105
+ {
106
+ "path": "src/oauth/index.ts",
107
+ "type": "registry:file",
108
+ "target": "~/src/kit/oauth/index.ts"
109
+ },
110
+ {
111
+ "path": "src/oauth/schema.ts",
112
+ "type": "registry:file",
113
+ "target": "~/src/kit/oauth/schema.ts"
114
+ },
115
+ {
116
+ "path": "src/oauth/store.ts",
117
+ "type": "registry:file",
118
+ "target": "~/src/kit/oauth/store.ts"
119
+ },
120
+ {
121
+ "path": "src/oauth/README.md",
122
+ "type": "registry:file",
123
+ "target": "~/src/kit/oauth/README.md"
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ "name": "pagination",
129
+ "type": "registry:item",
130
+ "title": "Pagination",
131
+ "description": "Cursor pages and sorting: limitQuery, cursorQuery, sortQuery, pageOf, pageSchema",
132
+ "registryDependencies": [
133
+ "escalay/api-kit/core"
134
+ ],
135
+ "files": [
136
+ {
137
+ "path": "src/pagination/index.ts",
138
+ "type": "registry:file",
139
+ "target": "~/src/kit/pagination/index.ts"
140
+ },
141
+ {
142
+ "path": "src/pagination/README.md",
143
+ "type": "registry:file",
144
+ "target": "~/src/kit/pagination/README.md"
145
+ }
146
+ ]
147
+ },
148
+ {
149
+ "name": "guide",
150
+ "type": "registry:item",
151
+ "title": "Agent guide",
152
+ "description": "The agent guide from Markdown templates (llms.txt, agents/, skills/), its generated parts (endpoints, tools, playbooks, how to get unstuck) and the skills discovery index",
153
+ "registryDependencies": [
154
+ "escalay/api-kit/core"
155
+ ],
156
+ "files": [
157
+ {
158
+ "path": "src/guide/guide.ts",
159
+ "type": "registry:file",
160
+ "target": "~/src/kit/guide/guide.ts"
161
+ },
162
+ {
163
+ "path": "src/guide/reference.ts",
164
+ "type": "registry:file",
165
+ "target": "~/src/kit/guide/reference.ts"
166
+ },
167
+ {
168
+ "path": "src/guide/README.md",
169
+ "type": "registry:file",
170
+ "target": "~/src/kit/guide/README.md"
171
+ }
172
+ ]
173
+ },
174
+ {
175
+ "name": "mcp",
176
+ "type": "registry:item",
177
+ "title": "MCP server",
178
+ "description": "An MCP server (2026-07-28) over the app's own routes: tools, resources, prompts, skills, and its Server Card",
179
+ "dependencies": [
180
+ "@modelcontextprotocol/server@^2.4.0"
181
+ ],
182
+ "registryDependencies": [
183
+ "escalay/api-kit/core"
184
+ ],
185
+ "files": [
186
+ {
187
+ "path": "src/mcp/index.ts",
188
+ "type": "registry:file",
189
+ "target": "~/src/kit/mcp/index.ts"
190
+ },
191
+ {
192
+ "path": "src/mcp/README.md",
193
+ "type": "registry:file",
194
+ "target": "~/src/kit/mcp/README.md"
195
+ }
196
+ ],
197
+ "meta": {
198
+ "entry": true
199
+ }
200
+ },
201
+ {
202
+ "name": "a2a",
203
+ "type": "registry:item",
204
+ "title": "A2A",
205
+ "description": "A2A 1.0 over the MCP tools: the Agent Card at /.well-known/agent-card.json and a JSON-RPC endpoint (SendMessage, GetTask, ListTasks, CancelTask) whose skills are tools",
206
+ "registryDependencies": [
207
+ "escalay/api-kit/mcp"
208
+ ],
209
+ "files": [
210
+ {
211
+ "path": "src/a2a/index.ts",
212
+ "type": "registry:file",
213
+ "target": "~/src/kit/a2a/index.ts"
214
+ },
215
+ {
216
+ "path": "src/a2a/README.md",
217
+ "type": "registry:file",
218
+ "target": "~/src/kit/a2a/README.md"
219
+ }
220
+ ],
221
+ "meta": {
222
+ "entry": true
223
+ }
224
+ },
225
+ {
226
+ "name": "vectors",
227
+ "type": "registry:item",
228
+ "title": "Vectors",
229
+ "description": "Gemini Embedding 2 through OpenRouter: look (image) and meaning (text) vectors, append-only ledgers that never pay twice, budgets and spend caps, nearest and standouts search (sharp, for pictures only)",
230
+ "files": [
231
+ {
232
+ "path": "src/vectors/index.ts",
233
+ "type": "registry:file",
234
+ "target": "~/src/kit/vectors/index.ts"
235
+ },
236
+ {
237
+ "path": "src/vectors/README.md",
238
+ "type": "registry:file",
239
+ "target": "~/src/kit/vectors/README.md"
240
+ }
241
+ ],
242
+ "meta": {
243
+ "optionalDependencies": {
244
+ "sharp": "^0.34.5"
245
+ }
246
+ }
247
+ },
248
+ {
249
+ "name": "vector-search",
250
+ "type": "registry:item",
251
+ "title": "Vector search",
252
+ "description": "Search by words, by picture and by likeness over the vectors: three documented routes (rate-limited where they cost) and the MCP tools that call them",
253
+ "registryDependencies": [
254
+ "escalay/api-kit/vectors",
255
+ "escalay/api-kit/mcp"
256
+ ],
257
+ "files": [
258
+ {
259
+ "path": "src/vector-search/index.ts",
260
+ "type": "registry:file",
261
+ "target": "~/src/kit/vector-search/index.ts"
262
+ },
263
+ {
264
+ "path": "src/vector-search/README.md",
265
+ "type": "registry:file",
266
+ "target": "~/src/kit/vector-search/README.md"
267
+ }
268
+ ],
269
+ "meta": {
270
+ "entry": true
271
+ }
272
+ },
273
+ {
274
+ "name": "web",
275
+ "type": "registry:item",
276
+ "title": "Front door",
277
+ "description": "The front door: a public landing page at /, the browser app under /app behind the sign-in, old addresses redirected, and the paths auth must leave open",
278
+ "dependencies": [
279
+ "@hono/node-server@^2.1.5"
280
+ ],
281
+ "registryDependencies": [
282
+ "escalay/api-kit/core"
283
+ ],
284
+ "files": [
285
+ {
286
+ "path": "src/web/index.ts",
287
+ "type": "registry:file",
288
+ "target": "~/src/kit/web/index.ts"
289
+ },
290
+ {
291
+ "path": "src/web/README.md",
292
+ "type": "registry:file",
293
+ "target": "~/src/kit/web/README.md"
294
+ }
295
+ ]
296
+ },
297
+ {
298
+ "name": "boards",
299
+ "type": "registry:item",
300
+ "title": "Boards",
301
+ "description": "The owner's collections of the app's items: boards with notes in SQLite, their routes (idempotent saves, where an item is saved, optional suggestions) and MCP tools",
302
+ "registryDependencies": [
303
+ "escalay/api-kit/db",
304
+ "escalay/api-kit/mcp"
305
+ ],
306
+ "files": [
307
+ {
308
+ "path": "src/boards/index.ts",
309
+ "type": "registry:file",
310
+ "target": "~/src/kit/boards/index.ts"
311
+ },
312
+ {
313
+ "path": "src/boards/handlers.ts",
314
+ "type": "registry:file",
315
+ "target": "~/src/kit/boards/handlers.ts"
316
+ },
317
+ {
318
+ "path": "src/boards/refs.ts",
319
+ "type": "registry:file",
320
+ "target": "~/src/kit/boards/refs.ts"
321
+ },
322
+ {
323
+ "path": "src/boards/repo.ts",
324
+ "type": "registry:file",
325
+ "target": "~/src/kit/boards/repo.ts"
326
+ },
327
+ {
328
+ "path": "src/boards/routes.ts",
329
+ "type": "registry:file",
330
+ "target": "~/src/kit/boards/routes.ts"
331
+ },
332
+ {
333
+ "path": "src/boards/schema.ts",
334
+ "type": "registry:file",
335
+ "target": "~/src/kit/boards/schema.ts"
336
+ },
337
+ {
338
+ "path": "src/boards/tools.ts",
339
+ "type": "registry:file",
340
+ "target": "~/src/kit/boards/tools.ts"
341
+ },
342
+ {
343
+ "path": "src/boards/README.md",
344
+ "type": "registry:file",
345
+ "target": "~/src/kit/boards/README.md"
346
+ }
347
+ ],
348
+ "meta": {
349
+ "entry": true
350
+ }
351
+ },
352
+ {
353
+ "name": "testing",
354
+ "type": "registry:item",
355
+ "title": "Testing",
356
+ "description": "Checks for an app's tests: lintOpenApi, guideRoutes, guideGaps, toolRoutes",
357
+ "registryDependencies": [
358
+ "escalay/api-kit/guide"
359
+ ],
360
+ "files": [
361
+ {
362
+ "path": "src/testing/index.ts",
363
+ "type": "registry:file",
364
+ "target": "~/src/kit/testing/index.ts"
365
+ },
366
+ {
367
+ "path": "src/testing/README.md",
368
+ "type": "registry:file",
369
+ "target": "~/src/kit/testing/README.md"
370
+ }
371
+ ],
372
+ "meta": {
373
+ "entry": true
374
+ }
375
+ },
376
+ {
377
+ "name": "search-client",
378
+ "type": "registry:item",
379
+ "title": "Search client",
380
+ "description": "Browser, no framework: a typed client for vector-search's routes, a controller for one search's state (debounced, cancelling), paste and drop of pictures",
381
+ "files": [
382
+ {
383
+ "path": "src/browser/search-client.ts",
384
+ "type": "registry:file",
385
+ "target": "~/src/kit/browser/search-client.ts"
386
+ },
387
+ {
388
+ "path": "src/browser/README.md",
389
+ "type": "registry:file",
390
+ "target": "~/src/kit/browser/README.md"
391
+ }
392
+ ],
393
+ "meta": {
394
+ "entry": true,
395
+ "web": true
396
+ }
397
+ },
398
+ {
399
+ "name": "search-react",
400
+ "type": "registry:item",
401
+ "title": "Search hooks",
402
+ "description": "Browser, React: useVectorSearch, usePictureInput, useSimilar over search-client; headless, each app draws its own UI",
403
+ "dependencies": [
404
+ "react"
405
+ ],
406
+ "registryDependencies": [
407
+ "escalay/api-kit/search-client"
408
+ ],
409
+ "files": [
410
+ {
411
+ "path": "src/browser/search-react.ts",
412
+ "type": "registry:file",
413
+ "target": "~/src/kit/browser/search-react.ts"
414
+ },
415
+ {
416
+ "path": "src/browser/README.md",
417
+ "type": "registry:file",
418
+ "target": "~/src/kit/browser/README.md"
419
+ }
420
+ ],
421
+ "meta": {
422
+ "entry": true,
423
+ "web": true
424
+ }
425
+ },
426
+ {
427
+ "name": "vector-search-ui",
428
+ "type": "registry:item",
429
+ "title": "Vector search block",
430
+ "description": "Browser, React + shadcn: an optional search block (field with a picture chip, look/meaning switch, results grid) over search-react",
431
+ "dependencies": [
432
+ "react"
433
+ ],
434
+ "registryDependencies": [
435
+ "button",
436
+ "input",
437
+ "escalay/api-kit/search-react"
438
+ ],
439
+ "files": [
440
+ {
441
+ "path": "src/browser/vector-search-block.tsx",
442
+ "type": "registry:file",
443
+ "target": "~/src/kit/browser/vector-search-block.tsx"
444
+ },
445
+ {
446
+ "path": "src/browser/README.md",
447
+ "type": "registry:file",
448
+ "target": "~/src/kit/browser/README.md"
449
+ }
450
+ ],
451
+ "meta": {
452
+ "entry": true,
453
+ "web": true
454
+ }
455
+ },
456
+ {
457
+ "name": "boards-client",
458
+ "type": "registry:item",
459
+ "title": "Boards client",
460
+ "description": "Browser, no framework: a typed client for the board routes",
461
+ "files": [
462
+ {
463
+ "path": "src/browser/boards-client.ts",
464
+ "type": "registry:file",
465
+ "target": "~/src/kit/browser/boards-client.ts"
466
+ },
467
+ {
468
+ "path": "src/boards/refs.ts",
469
+ "type": "registry:file",
470
+ "target": "~/src/kit/boards/refs.ts"
471
+ },
472
+ {
473
+ "path": "src/browser/README.md",
474
+ "type": "registry:file",
475
+ "target": "~/src/kit/browser/README.md"
476
+ }
477
+ ],
478
+ "meta": {
479
+ "entry": true,
480
+ "web": true
481
+ }
482
+ },
483
+ {
484
+ "name": "boards-react",
485
+ "type": "registry:item",
486
+ "title": "Boards hooks",
487
+ "description": "Browser, React: useBoards, useItemBoards over boards-client (headless)",
488
+ "dependencies": [
489
+ "react"
490
+ ],
491
+ "registryDependencies": [
492
+ "escalay/api-kit/boards-client"
493
+ ],
494
+ "files": [
495
+ {
496
+ "path": "src/browser/boards-react.ts",
497
+ "type": "registry:file",
498
+ "target": "~/src/kit/browser/boards-react.ts"
499
+ },
500
+ {
501
+ "path": "src/browser/README.md",
502
+ "type": "registry:file",
503
+ "target": "~/src/kit/browser/README.md"
504
+ }
505
+ ],
506
+ "meta": {
507
+ "entry": true,
508
+ "web": true
509
+ }
510
+ },
511
+ {
512
+ "name": "npm-release",
513
+ "type": "registry:item",
514
+ "title": "npm release",
515
+ "description": "Releases of an npm package with no manual step: release-please keeps a release pull request, merging it publishes every public package from GitHub Actions with npm trusted publishing and provenance, waits until npm serves them and publishes the GitHub release; with a read-only release check and the standard that explains it. For any pnpm repo; its files go to the repo root",
516
+ "files": [
517
+ {
518
+ "path": ".github/workflows/release.yml",
519
+ "type": "registry:file",
520
+ "target": "~/.github/workflows/release.yml"
521
+ },
522
+ {
523
+ "path": "templates/npm-release/release-please-config.json",
524
+ "type": "registry:file",
525
+ "target": "~/release-please-config.json"
526
+ },
527
+ {
528
+ "path": "templates/npm-release/release-please-manifest.json",
529
+ "type": "registry:file",
530
+ "target": "~/.release-please-manifest.json"
531
+ },
532
+ {
533
+ "path": "scripts/release-check.mjs",
534
+ "type": "registry:file",
535
+ "target": "~/scripts/release-check.mjs"
536
+ },
537
+ {
538
+ "path": "docs/releasing.md",
539
+ "type": "registry:file",
540
+ "target": "~/docs/releasing.md"
541
+ }
542
+ ],
543
+ "meta": {
544
+ "root": true
545
+ }
546
+ }
547
+ ]
548
+ }
@@ -0,0 +1,25 @@
1
+ # a2a
2
+
3
+ A2A 1.0 over the MCP tools: an Agent Card at `/.well-known/agent-card.json` and a JSON-RPC endpoint at `/a2a` whose
4
+ skills are tools. Another agent sends a message naming a skill; a slow route leaves the task working and `GetTask`
5
+ asks again.
6
+
7
+ Needs: `mcp`.
8
+
9
+ ```ts
10
+ import { mountA2A } from './kit/a2a/index.js'
11
+
12
+ mountA2A(app, {
13
+ info: { name: 'Recipes', description: 'Finds recipes for a description.', version },
14
+ skills: [{ tool: tools.find((t) => t.name === 'search_recipes')!, text: 'q', tags: ['recipes'], examples: ['a quick soup'] }],
15
+ callApi: inProcess(app),
16
+ store: oauthStore, // any KeyValueStore; tasks are kept a day
17
+ oauth: !!oauth, // advertise the OAuth server beside keys
18
+ })
19
+ ```
20
+
21
+ ## Rules
22
+
23
+ - Pick the 1–3 tools another agent would delegate to; the first skill answers a message that names none.
24
+ - Spec source of truth: `a2aproject/A2A` `specification/a2a.proto` (JSON is camelCase, enums SCREAMING_CASE, header
25
+ `A2A-Version: 1.0`).