forgeos 0.1.0-alpha.2 → 0.1.0-alpha.20

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 (406) hide show
  1. package/.npmignore +4 -0
  2. package/AGENTS.md +168 -81
  3. package/CHANGELOG.md +199 -0
  4. package/README.md +88 -14
  5. package/adapters/go/README.md +23 -0
  6. package/adapters/go/go.mod +3 -0
  7. package/adapters/go/http.go +149 -0
  8. package/adapters/go/registry.go +234 -0
  9. package/adapters/go/types.go +136 -0
  10. package/adapters/java/README.md +68 -0
  11. package/adapters/java/pom.xml +34 -0
  12. package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
  13. package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
  14. package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
  15. package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
  16. package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
  17. package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
  18. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
  19. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
  20. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
  21. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
  22. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
  23. package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
  24. package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
  25. package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
  26. package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
  27. package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
  28. package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
  29. package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
  30. package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
  31. package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
  32. package/adapters/java/target/classes/dev/forgeos/adapter/Auth.class +0 -0
  33. package/adapters/java/target/classes/dev/forgeos/adapter/Diagnostic.class +0 -0
  34. package/adapters/java/target/classes/dev/forgeos/adapter/Entry.class +0 -0
  35. package/adapters/java/target/classes/dev/forgeos/adapter/EntryKind.class +0 -0
  36. package/adapters/java/target/classes/dev/forgeos/adapter/ErrorInfo.class +0 -0
  37. package/adapters/java/target/classes/dev/forgeos/adapter/Forge.class +0 -0
  38. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeCall.class +0 -0
  39. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeContext.class +0 -0
  40. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHandler.class +0 -0
  41. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHttpHandler.class +0 -0
  42. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$EntryOption.class +0 -0
  43. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegisteredEntry.class +0 -0
  44. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegistryOption.class +0 -0
  45. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry.class +0 -0
  46. package/adapters/java/target/classes/dev/forgeos/adapter/Json.class +0 -0
  47. package/adapters/java/target/classes/dev/forgeos/adapter/Manifest.class +0 -0
  48. package/adapters/java/target/classes/dev/forgeos/adapter/RequestEnvelope.class +0 -0
  49. package/adapters/java/target/classes/dev/forgeos/adapter/ResponseEnvelope.class +0 -0
  50. package/adapters/java/target/classes/dev/forgeos/adapter/Risk.class +0 -0
  51. package/adapters/java/target/classes/dev/forgeos/adapter/Schemas.class +0 -0
  52. package/adapters/java/target/classes/dev/forgeos/adapter/Service.class +0 -0
  53. package/adapters/java/target/classes/dev/forgeos/adapter/TransactionMode.class +0 -0
  54. package/adapters/java/target/classes/dev/forgeos/adapter/TypedForgeHandler.class +0 -0
  55. package/adapters/java/target/forge-java-adapter-0.1.0-alpha.11.jar +0 -0
  56. package/adapters/java/target/maven-archiver/pom.properties +3 -0
  57. package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +23 -0
  58. package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +20 -0
  59. package/adapters/java-spring-boot-starter/README.md +32 -0
  60. package/adapters/java-spring-boot-starter/pom.xml +36 -0
  61. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
  62. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
  63. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
  64. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
  65. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
  66. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
  67. package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  68. package/adapters/java-spring-boot-starter/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  69. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeCommand.class +0 -0
  70. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeExternalService.class +0 -0
  71. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeQuery.class +0 -0
  72. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.class +0 -0
  73. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.class +0 -0
  74. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringRuntime.class +0 -0
  75. package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar +0 -0
  76. package/adapters/java-spring-boot-starter/target/maven-archiver/pom.properties +3 -0
  77. package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +6 -0
  78. package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +6 -0
  79. package/bin/forge.mjs +18 -0
  80. package/docs/changelog.md +212 -0
  81. package/docs/forge-protocol.md +189 -0
  82. package/examples/go-billing/go.mod +7 -0
  83. package/examples/go-billing/main.go +120 -0
  84. package/examples/java-billing/pom.xml +52 -0
  85. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
  86. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
  87. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
  88. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/CreateInvoiceInput.class +0 -0
  89. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Invoice.class +0 -0
  90. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$EmptyInput.class +0 -0
  91. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$Options.class +0 -0
  92. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main.class +0 -0
  93. package/examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar +0 -0
  94. package/examples/java-billing/target/java-billing-0.1.0-alpha.11.jar +0 -0
  95. package/examples/java-billing/target/maven-archiver/pom.properties +3 -0
  96. package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +5 -0
  97. package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +3 -0
  98. package/package.json +29 -7
  99. package/schemas/forge-manifest.schema.json +57 -0
  100. package/src/forge/_generated/releaseManifest.json +1 -2
  101. package/src/forge/_generated/releaseManifest.ts +3 -3
  102. package/src/forge/agent-adapters/index.ts +1511 -123
  103. package/src/forge/agent-adapters/types.ts +216 -1
  104. package/src/forge/agent-memory/bridge.ts +1192 -0
  105. package/src/forge/agent-memory/context-pack.ts +151 -0
  106. package/src/forge/agent-memory/hook-runner.ts +312 -0
  107. package/src/forge/agent-memory/mcp.ts +224 -0
  108. package/src/forge/agent-memory/normalize.ts +498 -0
  109. package/src/forge/agent-memory/redaction.ts +103 -0
  110. package/src/forge/agent-memory/sources/claude-code.ts +51 -0
  111. package/src/forge/agent-memory/sources/codex-hook-runner.mjs +84 -0
  112. package/src/forge/agent-memory/sources/codex.ts +119 -0
  113. package/src/forge/agent-memory/sources/cursor.ts +35 -0
  114. package/src/forge/agent-memory/types.ts +191 -0
  115. package/src/forge/bench.ts +248 -0
  116. package/src/forge/brownfield-import/index.ts +736 -0
  117. package/src/forge/brownfield-import/types.ts +127 -0
  118. package/src/forge/cair/action-journal.ts +61 -0
  119. package/src/forge/cair/action-parser.ts +314 -0
  120. package/src/forge/cair/action-validator.ts +40 -0
  121. package/src/forge/cair/actions.ts +1818 -0
  122. package/src/forge/cair/format.ts +77 -0
  123. package/src/forge/cair/index.ts +106 -0
  124. package/src/forge/cair/query.ts +478 -0
  125. package/src/forge/cair/snapshot.ts +315 -0
  126. package/src/forge/cair/types.ts +248 -0
  127. package/src/forge/cli/ai.ts +671 -3
  128. package/src/forge/cli/auth.ts +36 -1
  129. package/src/forge/cli/build.ts +20 -4
  130. package/src/forge/cli/changed.ts +300 -0
  131. package/src/forge/cli/codex-app-server.ts +877 -0
  132. package/src/forge/cli/commands.ts +1285 -7
  133. package/src/forge/cli/db.ts +121 -2
  134. package/src/forge/cli/deps.ts +79 -12
  135. package/src/forge/cli/dev.ts +502 -38
  136. package/src/forge/cli/docs.ts +265 -0
  137. package/src/forge/cli/handoff.ts +250 -0
  138. package/src/forge/cli/index.ts +1 -0
  139. package/src/forge/cli/main.ts +49 -3
  140. package/src/forge/cli/new.ts +3 -1
  141. package/src/forge/cli/next-actions.ts +23 -0
  142. package/src/forge/cli/output.ts +290 -1
  143. package/src/forge/cli/parse.ts +770 -36
  144. package/src/forge/cli/query.ts +32 -0
  145. package/src/forge/cli/release.ts +35 -11
  146. package/src/forge/cli/rls.ts +568 -17
  147. package/src/forge/cli/run.ts +41 -0
  148. package/src/forge/cli/secrets.ts +46 -1
  149. package/src/forge/cli/security.ts +381 -0
  150. package/src/forge/cli/self-host.ts +56 -14
  151. package/src/forge/cli/studio.ts +2163 -0
  152. package/src/forge/cli/verify.ts +1422 -32
  153. package/src/forge/compiler/agent-contract/build.ts +725 -41
  154. package/src/forge/compiler/agent-contract/types.ts +85 -0
  155. package/src/forge/compiler/ai-registry/build.ts +62 -1
  156. package/src/forge/compiler/ai-registry/constants.ts +1 -1
  157. package/src/forge/compiler/ai-registry/parse.ts +168 -5
  158. package/src/forge/compiler/api-surface/build.ts +47 -0
  159. package/src/forge/compiler/app-graph/build.ts +68 -8
  160. package/src/forge/compiler/app-graph/extract.ts +107 -0
  161. package/src/forge/compiler/app-graph/forge-apis.ts +1 -0
  162. package/src/forge/compiler/app-graph/module-graph.ts +73 -78
  163. package/src/forge/compiler/app-graph/parser.ts +24 -24
  164. package/src/forge/compiler/app-graph/profile.ts +26 -0
  165. package/src/forge/compiler/app-graph/versions.ts +1 -1
  166. package/src/forge/compiler/classifier/capabilities.ts +3 -2
  167. package/src/forge/compiler/classifier/classify.ts +32 -8
  168. package/src/forge/compiler/classifier/secrets.ts +3 -2
  169. package/src/forge/compiler/classifier/signals.ts +91 -1
  170. package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
  171. package/src/forge/compiler/client-sdk/render-client.ts +188 -13
  172. package/src/forge/compiler/data-graph/parse.ts +3 -3
  173. package/src/forge/compiler/data-graph/sql/ddl.ts +60 -2
  174. package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
  175. package/src/forge/compiler/data-graph/sql/types.ts +1 -0
  176. package/src/forge/compiler/dev-manifest/build.ts +3 -0
  177. package/src/forge/compiler/diagnostics/codes.ts +35 -0
  178. package/src/forge/compiler/diagnostics/create.ts +8 -3
  179. package/src/forge/compiler/diagnostics/index.ts +2 -0
  180. package/src/forge/compiler/emitter/barrel.ts +3 -0
  181. package/src/forge/compiler/emitter/render.ts +5 -0
  182. package/src/forge/compiler/external-manifest/registry.ts +205 -0
  183. package/src/forge/compiler/external-manifest/types.ts +91 -0
  184. package/src/forge/compiler/external-manifest/validate.ts +373 -0
  185. package/src/forge/compiler/frontend-graph/build.ts +85 -13
  186. package/src/forge/compiler/integration/add.ts +498 -22
  187. package/src/forge/compiler/integration/snapshot.ts +2 -0
  188. package/src/forge/compiler/make-registry/build.ts +19 -7
  189. package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
  190. package/src/forge/compiler/orchestrator/plan.ts +78 -7
  191. package/src/forge/compiler/orchestrator/profile.ts +65 -0
  192. package/src/forge/compiler/orchestrator/run.ts +97 -31
  193. package/src/forge/compiler/orchestrator/serialize.ts +101 -8
  194. package/src/forge/compiler/package-graph/compiler.ts +13 -3
  195. package/src/forge/compiler/package-manager/adapter.ts +4 -1
  196. package/src/forge/compiler/package-manager/commands.ts +4 -0
  197. package/src/forge/compiler/package-manager/executor.ts +30 -1
  198. package/src/forge/compiler/policy-registry/build.ts +44 -1
  199. package/src/forge/compiler/test-graph/build.ts +11 -3
  200. package/src/forge/compiler/types/ai-registry.ts +25 -1
  201. package/src/forge/compiler/types/app-graph.ts +9 -2
  202. package/src/forge/compiler/types/cli.ts +76 -1
  203. package/src/forge/compiler/types/dev-manifest.ts +3 -0
  204. package/src/forge/compiler/types/frontend-graph.ts +2 -2
  205. package/src/forge/delta/classifier.ts +52 -0
  206. package/src/forge/delta/explain.ts +126 -0
  207. package/src/forge/delta/git-observer.ts +43 -0
  208. package/src/forge/delta/ids.ts +44 -0
  209. package/src/forge/delta/index.ts +13 -0
  210. package/src/forge/delta/recorder.ts +402 -0
  211. package/src/forge/delta/redaction.ts +50 -0
  212. package/src/forge/delta/schema.ts +240 -0
  213. package/src/forge/delta/session.ts +142 -0
  214. package/src/forge/delta/status.ts +489 -0
  215. package/src/forge/delta/store.ts +2975 -0
  216. package/src/forge/delta/timeline.ts +104 -0
  217. package/src/forge/dev/server.ts +768 -15
  218. package/src/forge/dev/types.ts +15 -1
  219. package/src/forge/dev/watch.ts +17 -7
  220. package/src/forge/dev-console/cycle.ts +233 -21
  221. package/src/forge/dev-console/types.ts +46 -1
  222. package/src/forge/impact/index.ts +46 -8
  223. package/src/forge/impact/types.ts +6 -0
  224. package/src/forge/intent/index.ts +35 -16
  225. package/src/forge/make/index.ts +149 -6
  226. package/src/forge/make/templates.ts +343 -2
  227. package/src/forge/make/types.ts +3 -1
  228. package/src/forge/refactor/index.ts +1 -0
  229. package/src/forge/repair/rules/index.ts +2 -2
  230. package/src/forge/review/index.ts +158 -12
  231. package/src/forge/review/types.ts +15 -0
  232. package/src/forge/runtime/ai/context.ts +210 -5
  233. package/src/forge/runtime/ai/types.ts +70 -0
  234. package/src/forge/runtime/auth/claims.ts +32 -0
  235. package/src/forge/runtime/auth/errors.ts +2 -0
  236. package/src/forge/runtime/context/create-context.ts +30 -6
  237. package/src/forge/runtime/db/generated-client.ts +13 -2
  238. package/src/forge/runtime/db/memory-adapter.ts +2 -2
  239. package/src/forge/runtime/db/pglite-adapter.ts +77 -2
  240. package/src/forge/runtime/db/postgres-adapter.ts +6 -3
  241. package/src/forge/runtime/executor.ts +112 -2
  242. package/src/forge/runtime/external/bridge.ts +649 -0
  243. package/src/forge/runtime/runner/run-entry.ts +16 -7
  244. package/src/forge/runtime/telemetry/scrubber.ts +91 -10
  245. package/src/forge/runtime/webhooks/security.ts +184 -0
  246. package/src/forge/server.ts +100 -2
  247. package/src/forge/version.ts +1 -1
  248. package/src/forge/vue/index.ts +407 -0
  249. package/src/forge/workspace/change-summary.ts +209 -0
  250. package/src/forge/workspace/forge-cli.ts +14 -0
  251. package/src/forge/workspace/git-summary.ts +279 -0
  252. package/templates/agent-workroom/AGENTS.md +29 -0
  253. package/templates/agent-workroom/README.md +34 -0
  254. package/templates/agent-workroom/forge.config.ts +3 -0
  255. package/templates/agent-workroom/package.json +33 -0
  256. package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
  257. package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
  258. package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
  259. package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
  260. package/templates/agent-workroom/src/forge/schema.ts +54 -0
  261. package/templates/agent-workroom/src/policies.ts +6 -0
  262. package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
  263. package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
  264. package/templates/agent-workroom/tsconfig.json +16 -0
  265. package/templates/agent-workroom/web/index.html +12 -0
  266. package/templates/agent-workroom/web/package.json +21 -0
  267. package/templates/agent-workroom/web/src/App.tsx +345 -0
  268. package/templates/agent-workroom/web/src/lib/forge.ts +13 -0
  269. package/templates/agent-workroom/web/src/main.tsx +13 -0
  270. package/templates/agent-workroom/web/src/styles.css +545 -0
  271. package/templates/agent-workroom/web/tsconfig.json +27 -0
  272. package/templates/b2b-support-web/package.json +2 -0
  273. package/templates/b2b-support-web/tsconfig.json +4 -1
  274. package/templates/b2b-support-web/web/package.json +1 -1
  275. package/templates/minimal-web/package.json +2 -1
  276. package/templates/minimal-web/tsconfig.json +3 -1
  277. package/templates/minimal-web/web/package.json +2 -2
  278. package/src/forge/_generated/actionSubscriptions.json +0 -2
  279. package/src/forge/_generated/actionSubscriptions.ts +0 -10
  280. package/src/forge/_generated/agentAdapterManifest.json +0 -2
  281. package/src/forge/_generated/agentAdapterManifest.ts +0 -73
  282. package/src/forge/_generated/agentContract.json +0 -2
  283. package/src/forge/_generated/agentContract.ts +0 -7696
  284. package/src/forge/_generated/agentQuickstart.md +0 -32
  285. package/src/forge/_generated/aiContext.ts +0 -59
  286. package/src/forge/_generated/aiModels.json +0 -2
  287. package/src/forge/_generated/aiModels.ts +0 -35
  288. package/src/forge/_generated/aiProviders.json +0 -2
  289. package/src/forge/_generated/aiProviders.ts +0 -23
  290. package/src/forge/_generated/aiRegistry.json +0 -2
  291. package/src/forge/_generated/aiRegistry.ts +0 -29
  292. package/src/forge/_generated/api.json +0 -2
  293. package/src/forge/_generated/api.ts +0 -8
  294. package/src/forge/_generated/appGraph.json +0 -2
  295. package/src/forge/_generated/appGraph.ts +0 -14667
  296. package/src/forge/_generated/appMap.md +0 -35
  297. package/src/forge/_generated/artifactManifest.json +0 -2
  298. package/src/forge/_generated/artifactManifest.ts +0 -7
  299. package/src/forge/_generated/authClaims.json +0 -2
  300. package/src/forge/_generated/authClaims.ts +0 -13
  301. package/src/forge/_generated/authConfig.json +0 -2
  302. package/src/forge/_generated/authConfig.ts +0 -17
  303. package/src/forge/_generated/authContext.ts +0 -23
  304. package/src/forge/_generated/authRegistry.json +0 -2
  305. package/src/forge/_generated/authRegistry.ts +0 -25
  306. package/src/forge/_generated/buildInfo.json +0 -2
  307. package/src/forge/_generated/buildInfo.ts +0 -9
  308. package/src/forge/_generated/capabilityMap.json +0 -2
  309. package/src/forge/_generated/capabilityMap.md +0 -15
  310. package/src/forge/_generated/capabilityMap.ts +0 -17
  311. package/src/forge/_generated/client.ts +0 -282
  312. package/src/forge/_generated/clientApi.ts +0 -9
  313. package/src/forge/_generated/clientManifest.json +0 -2
  314. package/src/forge/_generated/clientManifest.ts +0 -39
  315. package/src/forge/_generated/clientTypes.ts +0 -78
  316. package/src/forge/_generated/configRegistry.json +0 -2
  317. package/src/forge/_generated/configRegistry.ts +0 -4
  318. package/src/forge/_generated/dataGraph.json +0 -2
  319. package/src/forge/_generated/dataGraph.ts +0 -8
  320. package/src/forge/_generated/db.json +0 -2
  321. package/src/forge/_generated/db.ts +0 -2
  322. package/src/forge/_generated/dbSecurityManifest.json +0 -2
  323. package/src/forge/_generated/dbSecurityManifest.ts +0 -15
  324. package/src/forge/_generated/dbSessionContext.json +0 -2
  325. package/src/forge/_generated/dbSessionContext.ts +0 -39
  326. package/src/forge/_generated/deployManifest.json +0 -2
  327. package/src/forge/_generated/deployManifest.ts +0 -14
  328. package/src/forge/_generated/devManifest.json +0 -2
  329. package/src/forge/_generated/devManifest.ts +0 -47
  330. package/src/forge/_generated/envSchema.json +0 -2
  331. package/src/forge/_generated/envSchema.ts +0 -59
  332. package/src/forge/_generated/frontendGraph.json +0 -2
  333. package/src/forge/_generated/frontendGraph.ts +0 -27
  334. package/src/forge/_generated/importGuards.json +0 -2
  335. package/src/forge/_generated/importGuards.ts +0 -686
  336. package/src/forge/_generated/index.ts +0 -67
  337. package/src/forge/_generated/liveProductionManifest.json +0 -2
  338. package/src/forge/_generated/liveProductionManifest.ts +0 -23
  339. package/src/forge/_generated/liveProtocol.json +0 -2
  340. package/src/forge/_generated/liveProtocol.ts +0 -21
  341. package/src/forge/_generated/liveQueryRegistry.json +0 -2
  342. package/src/forge/_generated/liveQueryRegistry.ts +0 -9
  343. package/src/forge/_generated/liveTransportConfig.json +0 -2
  344. package/src/forge/_generated/liveTransportConfig.ts +0 -19
  345. package/src/forge/_generated/makeRegistry.json +0 -2
  346. package/src/forge/_generated/makeRegistry.ts +0 -163
  347. package/src/forge/_generated/makeTemplates.json +0 -2
  348. package/src/forge/_generated/makeTemplates.ts +0 -61
  349. package/src/forge/_generated/mockMap.json +0 -2
  350. package/src/forge/_generated/mockMap.ts +0 -7
  351. package/src/forge/_generated/operationPlaybooks.md +0 -147
  352. package/src/forge/_generated/packageGraph.json +0 -2
  353. package/src/forge/_generated/packageGraph.ts +0 -245249
  354. package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
  355. package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
  356. package/src/forge/_generated/permissionMatrix.json +0 -2
  357. package/src/forge/_generated/permissionMatrix.ts +0 -7
  358. package/src/forge/_generated/policyRegistry.json +0 -2
  359. package/src/forge/_generated/policyRegistry.ts +0 -11
  360. package/src/forge/_generated/queryRegistry.json +0 -2
  361. package/src/forge/_generated/queryRegistry.ts +0 -9
  362. package/src/forge/_generated/react.d.ts +0 -22
  363. package/src/forge/_generated/react.ts +0 -29
  364. package/src/forge/_generated/reactManifest.json +0 -2
  365. package/src/forge/_generated/reactManifest.ts +0 -19
  366. package/src/forge/_generated/rlsPolicies.json +0 -2
  367. package/src/forge/_generated/rlsPolicies.sql +0 -34
  368. package/src/forge/_generated/rlsPolicies.ts +0 -6
  369. package/src/forge/_generated/runtimeGraph.json +0 -2
  370. package/src/forge/_generated/runtimeGraph.ts +0 -8
  371. package/src/forge/_generated/runtimeMatrix.json +0 -2
  372. package/src/forge/_generated/runtimeMatrix.ts +0 -327385
  373. package/src/forge/_generated/runtimeRegistry.ts +0 -2
  374. package/src/forge/_generated/runtimeRules.md +0 -79
  375. package/src/forge/_generated/secretRegistry.json +0 -2
  376. package/src/forge/_generated/secretRegistry.ts +0 -50
  377. package/src/forge/_generated/secretsContext.ts +0 -11
  378. package/src/forge/_generated/serverApi.ts +0 -10
  379. package/src/forge/_generated/sourceMapManifest.json +0 -2
  380. package/src/forge/_generated/sourceMapManifest.ts +0 -7
  381. package/src/forge/_generated/sqlPlan.json +0 -2
  382. package/src/forge/_generated/sqlPlan.ts +0 -88
  383. package/src/forge/_generated/subscriptionManifest.json +0 -2
  384. package/src/forge/_generated/subscriptionManifest.ts +0 -7
  385. package/src/forge/_generated/symbolicationManifest.json +0 -2
  386. package/src/forge/_generated/symbolicationManifest.ts +0 -17
  387. package/src/forge/_generated/telemetryRegistry.json +0 -2
  388. package/src/forge/_generated/telemetryRegistry.ts +0 -9
  389. package/src/forge/_generated/telemetrySinks.json +0 -2
  390. package/src/forge/_generated/telemetrySinks.ts +0 -11
  391. package/src/forge/_generated/tenantScope.json +0 -2
  392. package/src/forge/_generated/tenantScope.ts +0 -8
  393. package/src/forge/_generated/testGraph.json +0 -2
  394. package/src/forge/_generated/testGraph.ts +0 -3108
  395. package/src/forge/_generated/testPlanRegistry.json +0 -2
  396. package/src/forge/_generated/testPlanRegistry.ts +0 -33
  397. package/src/forge/_generated/uiRoutes.json +0 -2
  398. package/src/forge/_generated/uiRoutes.ts +0 -16
  399. package/src/forge/_generated/uiScenarios.json +0 -2
  400. package/src/forge/_generated/uiScenarios.ts +0 -30
  401. package/src/forge/_generated/uiTestManifest.json +0 -2
  402. package/src/forge/_generated/uiTestManifest.ts +0 -27
  403. package/src/forge/_generated/workflowRegistry.json +0 -2
  404. package/src/forge/_generated/workflowRegistry.ts +0 -9
  405. package/src/forge/_generated/workflowSubscriptions.json +0 -2
  406. package/src/forge/_generated/workflowSubscriptions.ts +0 -10
@@ -34,24 +34,38 @@ import type { QueryRegistry } from "../types/query-registry.ts";
34
34
  import type { LiveQueryRegistry } from "../types/live-query-registry.ts";
35
35
  import type { ClientManifest } from "../client-sdk/build-manifest.ts";
36
36
  import type { FrontendGraph } from "../types/frontend-graph.ts";
37
+ import type {
38
+ ForgeExternalServiceEntry,
39
+ ForgeExternalServiceGraph,
40
+ } from "../external-manifest/types.ts";
37
41
  import { createDiagnostic } from "../diagnostics/create.ts";
42
+ import { CAIR_SCHEMA_VERSION } from "../../cair/types.ts";
38
43
  import { AUTH_ENV, DEFAULT_AUTH_CLAIMS } from "../../runtime/auth/config.ts";
44
+ import {
45
+ forgeCliCommandForWorkspace,
46
+ forgeCliCommandsForWorkspace,
47
+ shouldUseLocalForgeCli,
48
+ } from "../../workspace/forge-cli.ts";
39
49
  import type {
40
50
  AgentCapabilityMap,
41
51
  AgentCapabilityMapEntry,
42
52
  AgentContract,
43
53
  AgentDependencyApiInfo,
54
+ AgentExternalEntryInfo,
44
55
  AgentFrontendRuntimeBindingInfo,
45
56
  AgentFrontendUsageInfo,
46
57
  AgentHttpEndpointInfo,
47
58
  AgentIntegrationInfo,
48
59
  AgentRuntimeRule,
60
+ AgentProtocolInfo,
61
+ AgentToolRegistry,
49
62
  AgentPlaybook,
50
63
  } from "./types.ts";
51
64
 
52
65
  const AGENTS_USER_START = "<!-- user-notes:start -->";
53
66
  const AGENTS_USER_END = "<!-- user-notes:end -->";
54
67
  const DEFAULT_USER_NOTES = "Project-specific notes can go here.";
68
+ const AGENTS_USER_NOTES_TOKEN = "__FORGE_AGENTS_USER_NOTES__";
55
69
 
56
70
  export interface AgentContractInput {
57
71
  workspaceRoot: string;
@@ -73,17 +87,21 @@ export interface AgentContractInput {
73
87
  apiSurface: ApiSurface;
74
88
  clientManifest: ClientManifest;
75
89
  frontendGraph: FrontendGraph;
90
+ externalServices?: ForgeExternalServiceGraph;
76
91
  }
77
92
 
78
93
  export interface AgentContractArtifacts {
79
94
  contract: AgentContract;
80
95
  capabilityMap: AgentCapabilityMap;
96
+ toolRegistry: AgentToolRegistry;
81
97
  agentsMd: string;
82
98
  appMapMd: string;
83
99
  capabilityMapMd: string;
100
+ agentToolsMd: string;
84
101
  runtimeRulesMd: string;
85
102
  operationPlaybooksMd: string;
86
103
  agentQuickstartMd: string;
104
+ agentCairGuideMd: string;
87
105
  diagnostics: Diagnostic[];
88
106
  }
89
107
 
@@ -245,31 +263,100 @@ function runtimeRules(): AgentRuntimeRule[] {
245
263
  {
246
264
  context: "command",
247
265
  allowed: ["ctx.db writes", "ctx.emit", "ctx.telemetry buffered events"],
248
- forbidden: ["network packages", "ctx.secrets", "ctx.ai", "process.env", "filesystem access"],
266
+ forbidden: ["network packages", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "direct secret/env access", "filesystem access"],
249
267
  },
250
268
  {
251
269
  context: "query",
252
270
  allowed: ["ctx.db reads", "ctx.telemetry buffered events"],
253
- forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "network integrations"],
271
+ forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "network integrations"],
254
272
  },
255
273
  {
256
274
  context: "liveQuery",
257
275
  allowed: ["ctx.db reads", "tenant-scoped subscriptions"],
258
- forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "network integrations"],
276
+ forbidden: ["insert/update/delete", "ctx.emit", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "network integrations"],
259
277
  },
260
278
  {
261
279
  context: "action",
262
- allowed: ["ctx.secrets", "integrations", "ctx.ai", "ctx.db reads/writes", "network packages"],
280
+ allowed: ["ctx.secrets", "integrations", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "AI SDK tools", "ctx.db reads/writes", "network packages"],
263
281
  forbidden: ["uncommitted transactional side effects"],
264
282
  },
265
283
  {
266
284
  context: "workflow",
267
- allowed: ["durable steps", "ctx.secrets", "integrations", "ctx.ai", "retries"],
285
+ allowed: ["durable steps", "ctx.secrets", "integrations", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "AI SDK ToolLoopAgent", "retries"],
268
286
  forbidden: ["non-idempotent step behavior without guards"],
269
287
  },
270
288
  ];
271
289
  }
272
290
 
291
+ function agentProtocols(workspaceRoot: string): AgentProtocolInfo[] {
292
+ return [
293
+ {
294
+ id: "cair",
295
+ kind: "agent-protocol",
296
+ version: CAIR_SCHEMA_VERSION,
297
+ guide: "src/forge/_generated/agentCairGuide.md",
298
+ commands: forgeCliCommandsForWorkspace(workspaceRoot, [
299
+ "forge cair snapshot",
300
+ "forge cair query \"Q ST\"",
301
+ "forge cair query \"Q S name=<symbol>\"",
302
+ "forge cair query \"Q D S#1\"",
303
+ "forge cair query \"Q R S#1\"",
304
+ "forge cair query \"Q I S#1\"",
305
+ "forge cair action --plan \"A RN t=S#1 nn=<newName>\"",
306
+ "forge cair action \"A APPLY plan=<P#|path>\"",
307
+ "forge cair action \"A ROLLBACK journal=<path>\"",
308
+ ]),
309
+ preferredFor: [
310
+ "compact repository orientation",
311
+ "symbol lookup before file reads",
312
+ "semantic code edits",
313
+ "guarded refactors",
314
+ "Forge-native feature creation",
315
+ "impact-aware test selection",
316
+ "token-efficient programming",
317
+ ],
318
+ readQueries: [
319
+ "Q ST",
320
+ "Q S name=<symbol>",
321
+ "Q D S#1",
322
+ "Q R S#1",
323
+ "Q I S#1",
324
+ "Q T S#1",
325
+ "Q DEP.API package=<pkg> symbol=<export>",
326
+ ],
327
+ mutationActions: [
328
+ "A RN t=S#1 nn=<newName>",
329
+ "A MV t=S#1 to=<path>",
330
+ "A OI f=M#1",
331
+ "A FMT f=M#1",
332
+ "A MC n=<command>",
333
+ "A MQ n=<query>",
334
+ "A MA n=<action>",
335
+ "A MT n=<table> fields=<fields>",
336
+ "A AT t=S#1 kind=unit",
337
+ "A WX t=S#1 file=src/index.ts",
338
+ "A APPLY plan=<P#|path>",
339
+ "A ROLLBACK journal=<path>",
340
+ ],
341
+ compactAliases: [
342
+ "Q ST=Q STATUS",
343
+ "Q S=Q SYMBOL",
344
+ "Q D=Q DEF",
345
+ "Q R=Q REFS",
346
+ "Q I=Q IMPACT",
347
+ "A RN=A RENAME.SYMBOL",
348
+ "A MV=A MOVE.SYMBOL",
349
+ "A OI=A ORGANIZE.IMPORTS",
350
+ "A FMT=A FORMAT",
351
+ "A MC=A MAKE.COMMAND",
352
+ "A MT=A MAKE.TABLE",
353
+ "A AT=A ADD.TEST",
354
+ "A WX=A WIRE.EXPORT",
355
+ ],
356
+ },
357
+ ];
358
+ }
359
+
273
360
  function playbooks(): AgentPlaybook[] {
274
361
  return [
275
362
  {
@@ -320,6 +407,28 @@ function playbooks(): AgentPlaybook[] {
320
407
  "Reconnect with Last-Event-ID or ?lastRevision=<revision> to verify resume behavior.",
321
408
  ],
322
409
  },
410
+ {
411
+ title: "Add an AI tool",
412
+ steps: [
413
+ "Add a server-only file under src/ai or src/tools.",
414
+ "Export aiTool({ description, inputSchema, outputSchema, risk, needsApproval, handler }).",
415
+ "Use zod schemas for inputSchema and outputSchema.",
416
+ "Access secrets through the tool context, not process.env.",
417
+ "Mark destructive or external side effects with risk and needsApproval.",
418
+ "Run forge generate and inspect src/forge/_generated/aiRegistry.json.",
419
+ ],
420
+ },
421
+ {
422
+ title: "Add an agent",
423
+ steps: [
424
+ "Export agent({ provider, model, instructions, tools, stopWhen }) from server-only source.",
425
+ "Prefer AI SDK ToolLoopAgent semantics through ctx.agent.run or ctx.ai.runAgent instead of custom loops.",
426
+ "Use stopWhen with stepCount or terminal tool calls to prevent unbounded loops.",
427
+ "Run agents only in actions, workflows, endpoints, or server code.",
428
+ "Run forge inspect ai --json or forge agent print-context --json and confirm the generated context lists the agent.",
429
+ "Use forge ai trace <traceId> --json to inspect agent runs and tool calls.",
430
+ ],
431
+ },
323
432
  {
324
433
  title: "Add a table",
325
434
  steps: [
@@ -355,7 +464,8 @@ function playbooks(): AgentPlaybook[] {
355
464
  title: "Safely refactor a feature",
356
465
  steps: [
357
466
  "Run forge refactor rename field <table.field> <table.field> --dry-run --json.",
358
- "Rename codemods are AST-aware for extract-action, rename field, and rename table.",
467
+ "Run forge refactor rename command <oldName> <newName> --dry-run --json when renaming runtime entrypoints.",
468
+ "Rename codemods are AST-aware for extract-action, rename command, rename field, and rename table.",
359
469
  "Field renames are scoped to the target table, so tickets.priority only rewrites references linked to tickets.",
360
470
  "Review filesToModify, migrationPlan, diagnostics, and risk.",
361
471
  "Use --allow-high-risk only for intentional high-risk refactors.",
@@ -421,16 +531,17 @@ function playbooks(): AgentPlaybook[] {
421
531
  "Run forge dev --once --json for a one-shot diagnostic cycle.",
422
532
  "Use --api-only, --web-only, --no-watch, or --no-worker only when narrowing the loop intentionally.",
423
533
  "When a web app exists, forge dev starts the API runtime and the web dev server together and prints both URLs.",
424
- "Use generated client and React hooks through web/lib/forge.ts.",
534
+ "Use generated client bindings through web/lib/forge.ts, web/src/lib/forge.ts, or Nuxt web/composables/forge.ts.",
425
535
  ],
426
536
  },
427
537
  {
428
538
  title: "Add or update frontend",
429
539
  steps: [
430
- "Run forge make ui --framework vite --dry-run --json when the app does not have a web root.",
431
- "Use web/lib/forge.ts as the generated client bridge.",
432
- "Mount ForgeProvider once in the web app provider/layout layer; use devAuth for local development.",
433
- "Use useQuery, useCommand, and useLiveQuery instead of raw /commands or /queries fetches.",
540
+ "Run forge make ui --framework vite --dry-run --json or forge make ui --framework nuxt --dry-run --json when the app does not have a web root.",
541
+ "Run forge make ai-chat support --dry-run --json to add a chat surface backed by /ai/agents/chat streaming and /ai/agents/run JSON automation.",
542
+ "Use web/lib/forge.ts, web/src/lib/forge.ts, or web/composables/forge.ts as the generated client bridge.",
543
+ "Mount ForgeProvider or install the Nuxt Forge plugin once in the web app provider/layout layer; use devAuth for local development.",
544
+ "Use useQuery/useCommand/useLiveQuery or useForgeQuery/useForgeCommand/useForgeLiveQuery instead of raw /commands or /queries fetches.",
434
545
  "Run forge generate so frontendGraph and agentContract include routes and bindings.",
435
546
  "Run forge inspect capabilities --json to confirm UI actions map to runtime capabilities.",
436
547
  "Run forge dev --once --json and forge doctor --json.",
@@ -509,7 +620,11 @@ function runtimeEntriesWithoutFrontend(contract: AgentContract): AgentCapability
509
620
  emits: commandEntry.emits,
510
621
  dependencies: [],
511
622
  },
512
- notes: ["Runtime entry is available to agents even though no frontend usage was detected."],
623
+ notes: [
624
+ commandEntry.source === "external"
625
+ ? "External runtime entry is imported from a Forge manifest; execution requires an external runtime bridge."
626
+ : "Runtime entry is available to agents even though no frontend usage was detected.",
627
+ ],
513
628
  });
514
629
  }
515
630
  }
@@ -530,7 +645,11 @@ function runtimeEntriesWithoutFrontend(contract: AgentContract): AgentCapability
530
645
  emits: [],
531
646
  dependencies: [],
532
647
  },
533
- notes: ["Runtime entry is available to agents even though no frontend usage was detected."],
648
+ notes: [
649
+ queryEntry.source === "external"
650
+ ? "External runtime entry is imported from a Forge manifest; execution requires an external runtime bridge."
651
+ : "Runtime entry is available to agents even though no frontend usage was detected.",
652
+ ],
534
653
  });
535
654
  }
536
655
  }
@@ -656,6 +775,89 @@ function buildCapabilityMap(contract: AgentContract): AgentCapabilityMap {
656
775
  };
657
776
  }
658
777
 
778
+ function autoToolName(kind: "command" | "query" | "liveQuery", name: string): string {
779
+ return `forge_${kind}_${name}`.replace(/[^A-Za-z0-9_$]/g, "_");
780
+ }
781
+
782
+ function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
783
+ const autoTools: AgentToolRegistry["autoTools"] = [
784
+ ...contract.commands.map((command) => ({
785
+ name: autoToolName("command", command.name),
786
+ sourceKind: "command" as const,
787
+ sourceName: command.name,
788
+ ...(command.policy ? { policy: command.policy } : {}),
789
+ file: command.file,
790
+ http: command.http,
791
+ frontend: command.frontend,
792
+ tablesRead: command.tablesRead,
793
+ tablesWritten: command.tablesWritten,
794
+ emits: command.emits,
795
+ dependencies: [],
796
+ readOnly: false,
797
+ risk: "write" as const,
798
+ needsApproval: command.source === "external"
799
+ ? command.external?.needsApproval ?? (command.external?.risk !== "read")
800
+ : true,
801
+ requiresAuth: command.policy !== undefined && command.policy !== "public",
802
+ ...(command.source ? { source: command.source } : {}),
803
+ ...(command.external ? { external: command.external } : {}),
804
+ execution: command.source === "external"
805
+ ? "external-runtime-endpoint" as const
806
+ : "forge-runtime-endpoint" as const,
807
+ })),
808
+ ...contract.queries.map((query) => ({
809
+ name: autoToolName("query", query.name),
810
+ sourceKind: "query" as const,
811
+ sourceName: query.name,
812
+ ...(query.policy ? { policy: query.policy } : {}),
813
+ file: query.file,
814
+ http: query.http,
815
+ frontend: query.frontend,
816
+ tablesRead: query.tablesRead,
817
+ tablesWritten: [],
818
+ emits: [],
819
+ dependencies: [],
820
+ readOnly: true,
821
+ risk: "read" as const,
822
+ needsApproval: false,
823
+ requiresAuth: query.policy !== undefined && query.policy !== "public",
824
+ ...(query.source ? { source: query.source } : {}),
825
+ ...(query.external ? { external: query.external } : {}),
826
+ execution: query.source === "external"
827
+ ? "external-runtime-endpoint" as const
828
+ : "forge-runtime-endpoint" as const,
829
+ })),
830
+ ...contract.liveQueries.map((liveQuery) => ({
831
+ name: autoToolName("liveQuery", liveQuery.name),
832
+ sourceKind: "liveQuery" as const,
833
+ sourceName: liveQuery.name,
834
+ ...(liveQuery.policy ? { policy: liveQuery.policy } : {}),
835
+ file: liveQuery.file,
836
+ http: liveQuery.http,
837
+ frontend: liveQuery.frontend,
838
+ tablesRead: liveQuery.tablesRead,
839
+ tablesWritten: [],
840
+ emits: [],
841
+ dependencies: liveQuery.dependencies,
842
+ readOnly: true,
843
+ risk: "read" as const,
844
+ needsApproval: false,
845
+ requiresAuth: liveQuery.policy !== undefined && liveQuery.policy !== "public",
846
+ source: "local" as const,
847
+ execution: "forge-runtime-endpoint" as const,
848
+ })),
849
+ ].sort((a, b) => a.name.localeCompare(b.name));
850
+
851
+ return {
852
+ schemaVersion: "0.1.0",
853
+ generatorVersion: GENERATOR_VERSION,
854
+ project: contract.project,
855
+ explicitTools: contract.ai.tools,
856
+ autoTools,
857
+ agents: contract.ai.agents,
858
+ };
859
+ }
860
+
659
861
  function jsAccess(group: string, name: string): string {
660
862
  return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)
661
863
  ? `api.${group}.${name}`
@@ -695,6 +897,39 @@ function httpEndpointFor(
695
897
  };
696
898
  }
697
899
 
900
+ function externalEndpointFor(entry: ForgeExternalServiceEntry): AgentHttpEndpointInfo {
901
+ const encodedService = encodeURIComponent(entry.service);
902
+ const encodedName = encodeURIComponent(entry.name);
903
+ const collection = entry.kind === "query" ? "queries" : "commands";
904
+ return {
905
+ method: entry.method ?? "POST",
906
+ path: entry.path ?? `/external/${encodedService}/${collection}/${encodedName}`,
907
+ exampleBody: { args: {} },
908
+ };
909
+ }
910
+
911
+ function externalEntryInfo(entry: ForgeExternalServiceEntry): AgentExternalEntryInfo {
912
+ return {
913
+ service: entry.service,
914
+ language: entry.language,
915
+ ...(entry.framework ? { framework: entry.framework } : {}),
916
+ transport: entry.transport,
917
+ ...(entry.transaction ? { transaction: entry.transaction } : {}),
918
+ ...(entry.risk ? { risk: entry.risk } : {}),
919
+ ...(typeof entry.needsApproval === "boolean" ? { needsApproval: entry.needsApproval } : {}),
920
+ effects: entry.effects ?? [],
921
+ ...(entry.description ? { description: entry.description } : {}),
922
+ };
923
+ }
924
+
925
+ function externalFrontendUsage(entry: ForgeExternalServiceEntry): AgentFrontendUsageInfo {
926
+ return {
927
+ hook: `external manifest '${entry.service}.${entry.name}'; runtime bridge required before client invocation`,
928
+ routes: [],
929
+ components: [],
930
+ };
931
+ }
932
+
698
933
  function frontendUsageFor(
699
934
  frontendGraph: FrontendGraph,
700
935
  kind: "command" | "query" | "liveQuery" | "action",
@@ -817,12 +1052,14 @@ export function buildAgentContractArtifacts(
817
1052
 
818
1053
  const runtimeEntries = new Map(input.runtimeGraph.entries.map((entry) => [entry.name, entry]));
819
1054
  const tableNames = new Set(input.dataGraph.tables.map((table) => table.name));
820
- const commandInfos: AgentContract["commands"] = sorted(Object.keys(input.apiSurface.commands), (name) => name).map((name) => {
1055
+ const externalEntries = input.externalServices?.services.flatMap((service) => service.entries) ?? [];
1056
+ const localCommandInfos: AgentContract["commands"] = sorted(Object.keys(input.apiSurface.commands), (name) => name).map((name) => {
821
1057
  const entry = runtimeEntries.get(name);
822
1058
  const file = entry?.file ?? "";
823
1059
  return {
824
1060
  name,
825
1061
  file,
1062
+ source: "local" as const,
826
1063
  policy: authPolicy(commandAuth.get(name)),
827
1064
  tablesRead: dbTablesForFile(input.workspaceRoot, file, tableNames, DB_READ_OPS),
828
1065
  tablesWritten: dbTablesForFile(input.workspaceRoot, file, tableNames, DB_WRITE_OPS),
@@ -833,9 +1070,30 @@ export function buildAgentContractArtifacts(
833
1070
  frontend: frontendUsageFor(input.frontendGraph, "command", name),
834
1071
  };
835
1072
  });
836
- const queryInfos: AgentContract["queries"] = sorted(input.queryRegistry.queries, (query) => query.name).map((query) => ({
1073
+ const externalCommandInfos: AgentContract["commands"] = externalEntries
1074
+ .filter((entry) => entry.kind === "command")
1075
+ .map((entry) => ({
1076
+ name: `${entry.service}.${entry.name}`,
1077
+ file: `external:${entry.service}`,
1078
+ source: "external" as const,
1079
+ external: externalEntryInfo(entry),
1080
+ ...(entry.policy ? { policy: entry.policy } : {}),
1081
+ tablesRead: [],
1082
+ tablesWritten: entry.transaction === "read-only" ? [] : [`external:${entry.service}`],
1083
+ emits: entry.effects ?? [],
1084
+ allowedPackages: [],
1085
+ forbiddenCapabilities: [],
1086
+ http: externalEndpointFor(entry),
1087
+ frontend: externalFrontendUsage(entry),
1088
+ }));
1089
+ const commandInfos: AgentContract["commands"] = sorted(
1090
+ [...localCommandInfos, ...externalCommandInfos],
1091
+ (command) => command.name,
1092
+ );
1093
+ const localQueryInfos: AgentContract["queries"] = sorted(input.queryRegistry.queries, (query) => query.name).map((query) => ({
837
1094
  name: query.name,
838
1095
  file: query.file,
1096
+ source: "local" as const,
839
1097
  policy: authPolicy(queryAuth.get(query.name)),
840
1098
  readOnly: true,
841
1099
  tenantScoped: input.tenantScope.tables.length > 0,
@@ -845,6 +1103,26 @@ export function buildAgentContractArtifacts(
845
1103
  http: httpEndpointFor("query", query.name),
846
1104
  frontend: frontendUsageFor(input.frontendGraph, "query", query.name),
847
1105
  }));
1106
+ const externalQueryInfos: AgentContract["queries"] = externalEntries
1107
+ .filter((entry) => entry.kind === "query")
1108
+ .map((entry) => ({
1109
+ name: `${entry.service}.${entry.name}`,
1110
+ file: `external:${entry.service}`,
1111
+ source: "external" as const,
1112
+ external: externalEntryInfo(entry),
1113
+ ...(entry.policy ? { policy: entry.policy } : {}),
1114
+ readOnly: true as const,
1115
+ tenantScoped: entry.tenantScoped ?? false,
1116
+ tablesRead: [`external:${entry.service}`],
1117
+ allowedPackages: [],
1118
+ forbiddenCapabilities: [],
1119
+ http: externalEndpointFor(entry),
1120
+ frontend: externalFrontendUsage(entry),
1121
+ }));
1122
+ const queryInfos: AgentContract["queries"] = sorted(
1123
+ [...localQueryInfos, ...externalQueryInfos],
1124
+ (query) => query.name,
1125
+ );
848
1126
  const liveQueryInfos: AgentContract["liveQueries"] = sorted(input.liveQueryRegistry.liveQueries, (liveQuery) => liveQuery.name).map(
849
1127
  (liveQuery) => {
850
1128
  const tablesRead = dbTablesForFile(input.workspaceRoot, liveQuery.file, tableNames, DB_READ_OPS);
@@ -869,6 +1147,7 @@ export function buildAgentContractArtifacts(
869
1147
  queries: queryInfos,
870
1148
  liveQueries: liveQueryInfos,
871
1149
  });
1150
+ const protocols = agentProtocols(input.workspaceRoot);
872
1151
  const contract: AgentContract = {
873
1152
  schemaVersion: "0.1.0",
874
1153
  generatorVersion: GENERATOR_VERSION,
@@ -929,6 +1208,19 @@ export function buildAgentContractArtifacts(
929
1208
  }),
930
1209
  dependencyApis: buildDependencyApis(input.packageGraph),
931
1210
  integrations: buildIntegrations(input.classified),
1211
+ externalServices: (input.externalServices?.services ?? []).map((service) => ({
1212
+ name: service.name,
1213
+ language: service.language,
1214
+ ...(service.framework ? { framework: service.framework } : {}),
1215
+ transport: service.transport,
1216
+ ...(service.baseUrl ? { baseUrl: service.baseUrl } : {}),
1217
+ ...(service.command ? { command: service.command } : {}),
1218
+ ...(service.health ? { health: service.health } : {}),
1219
+ commands: sorted(service.entries.filter((entry) => entry.kind === "command"), (entry) => entry.name)
1220
+ .map((entry) => `${service.name}.${entry.name}`),
1221
+ queries: sorted(service.entries.filter((entry) => entry.kind === "query"), (entry) => entry.name)
1222
+ .map((entry) => `${service.name}.${entry.name}`),
1223
+ })),
932
1224
  secrets: sorted(input.secretRegistry.secrets, (secret) => secret.name).map((secret) => ({
933
1225
  name: secret.name,
934
1226
  integration: secret.integration,
@@ -951,6 +1243,23 @@ export function buildAgentContractArtifacts(
951
1243
  ...(generation.purpose ? { purpose: generation.purpose } : {}),
952
1244
  }))
953
1245
  .sort((a, b) => `${a.file}:${a.method}:${a.model}`.localeCompare(`${b.file}:${b.method}:${b.model}`)),
1246
+ tools: input.aiRegistry.tools.map((tool) => ({
1247
+ name: tool.name,
1248
+ file: tool.file,
1249
+ ...(tool.description ? { description: tool.description } : {}),
1250
+ risk: tool.risk,
1251
+ strict: tool.strict,
1252
+ needsApproval: tool.needsApproval,
1253
+ })),
1254
+ agents: input.aiRegistry.agents.map((agent) => ({
1255
+ name: agent.name,
1256
+ file: agent.file,
1257
+ provider: agent.provider,
1258
+ model: agent.model,
1259
+ ...(agent.instructions ? { instructions: agent.instructions } : {}),
1260
+ tools: agent.tools,
1261
+ stopWhen: agent.stopWhen,
1262
+ })),
954
1263
  },
955
1264
  client: {
956
1265
  queries: input.clientManifest.queries,
@@ -1025,10 +1334,11 @@ export function buildAgentContractArtifacts(
1025
1334
  },
1026
1335
  rules: runtimeRules(),
1027
1336
  playbooks: playbooks(),
1337
+ agentProtocols: protocols,
1028
1338
  commandsToRun: {
1029
- beforeEditing: ["forge do inspect --json", "forge dev --once --json", "forge inspect all --json", "forge check --json"],
1030
- afterEditing: ["forge generate", "forge check", "forge verify --standard", "forge verify --strict"],
1031
- dev: ["forge dev", "forge dev --once --json", "forge do fix --json", "forge do verify --json", "forge dev --api-only", "forge dev --web-only"],
1339
+ beforeEditing: forgeCliCommandsForWorkspace(input.workspaceRoot, ["forge agent onboard --target codex --json", "forge status --json", "forge changed --json", "forge handoff --json", "forge do inspect --json", "forge cair snapshot", "forge cair query \"Q ST\"", "forge dev --once --json", "forge agent print-context --json", "forge check --json"]),
1340
+ afterEditing: forgeCliCommandsForWorkspace(input.workspaceRoot, ["forge generate", "forge check", "forge verify --standard", finalVerifyCommand(input.workspaceRoot)]),
1341
+ dev: forgeCliCommandsForWorkspace(input.workspaceRoot, ["forge dev", "forge dev --once --json", "forge handoff --json", "forge do fix --json", "forge do verify --json", "forge dev --api-only", "forge dev --web-only"]),
1032
1342
  },
1033
1343
  };
1034
1344
 
@@ -1037,31 +1347,39 @@ export function buildAgentContractArtifacts(
1037
1347
  ? (nodeFileSystem.readText(existingAgentsPath) ?? "")
1038
1348
  : null;
1039
1349
  const userNotes = extractUserNotes(existingAgents);
1040
- const agentsMd = renderAgentsMd(contract, userNotes);
1350
+ const agentsMd = renderAgentsMd(contract, userNotes, input.workspaceRoot);
1351
+ const toolRegistry = buildAgentToolRegistry(contract);
1041
1352
  const capabilityMap = buildCapabilityMap(contract);
1042
1353
  const capabilityMapMd = renderCapabilityMapMd(capabilityMap);
1354
+ const agentToolsMd = renderAgentToolsMd(toolRegistry);
1043
1355
  const appMapMd = renderAppMapMd(contract);
1044
1356
  const runtimeRulesMd = renderRuntimeRulesMd(contract.rules);
1045
1357
  const operationPlaybooksMd = renderOperationPlaybooksMd(contract.playbooks);
1046
- const agentQuickstartMd = renderAgentQuickstartMd();
1358
+ const agentQuickstartMd = renderAgentQuickstartMd(input.workspaceRoot);
1359
+ const agentCairGuideMd = renderAgentCairGuideMd(contract, input.workspaceRoot);
1047
1360
  const diagnostics = scanAgentContractForLeaks(contract, [
1048
1361
  agentsMd,
1362
+ agentToolsMd,
1049
1363
  capabilityMapMd,
1050
1364
  appMapMd,
1051
1365
  runtimeRulesMd,
1052
1366
  operationPlaybooksMd,
1053
1367
  agentQuickstartMd,
1368
+ agentCairGuideMd,
1054
1369
  ]);
1055
1370
 
1056
1371
  return {
1057
1372
  contract,
1058
1373
  capabilityMap,
1374
+ toolRegistry,
1059
1375
  agentsMd,
1060
1376
  appMapMd,
1061
1377
  capabilityMapMd,
1378
+ agentToolsMd,
1062
1379
  runtimeRulesMd,
1063
1380
  operationPlaybooksMd,
1064
1381
  agentQuickstartMd,
1382
+ agentCairGuideMd,
1065
1383
  diagnostics: [...diagnostics, ...capabilityMap.diagnostics],
1066
1384
  };
1067
1385
  }
@@ -1099,7 +1417,31 @@ export function serializeCapabilityMapTs(capabilityMap: AgentCapabilityMap): str
1099
1417
  return `export const capabilityMap = ${JSON.stringify(parsed, null, 2)} as const;\n`;
1100
1418
  }
1101
1419
 
1102
- function renderAgentsMd(contract: AgentContract, userNotes: string): string {
1420
+ export function serializeAgentToolRegistryJson(registry: AgentToolRegistry): string {
1421
+ return serializeCanonical(registry);
1422
+ }
1423
+
1424
+ export function serializeAgentToolRegistryTs(registry: AgentToolRegistry): string {
1425
+ const parsed = JSON.parse(serializeAgentToolRegistryJson(registry)) as unknown;
1426
+ return `export const agentTools = ${JSON.stringify(parsed, null, 2)} as const;\n`;
1427
+ }
1428
+
1429
+ function localizeForgeCliMarkdown(workspaceRoot: string, markdown: string): string {
1430
+ return shouldUseLocalForgeCli(workspaceRoot)
1431
+ ? markdown.replace(/\bforge (?=[a-z])/g, "node bin/forge.mjs ")
1432
+ : markdown;
1433
+ }
1434
+
1435
+ function finalVerifyCommand(workspaceRoot: string): string {
1436
+ const command = shouldUseLocalForgeCli(workspaceRoot) ? "forge verify framework" : "forge verify --strict";
1437
+ return forgeCliCommandForWorkspace(workspaceRoot, command);
1438
+ }
1439
+
1440
+ function renderAgentsMd(contract: AgentContract, userNotes: string, workspaceRoot: string): string {
1441
+ const finalVerify = finalVerifyCommand(workspaceRoot);
1442
+ const cliEntrypoint = shouldUseLocalForgeCli(workspaceRoot)
1443
+ ? "This is the ForgeOS framework checkout. Use `node bin/forge.mjs ...` so maintainer commands run against this source tree; reserve the global `forge` command for installed-package smoke tests."
1444
+ : "Use the installed `forge` command for app workflows.";
1103
1445
  const tenantTables = contract.data.tables
1104
1446
  .filter((table) => table.tenantScoped)
1105
1447
  .map((table) => `${table.name} via ${table.tenantField}`);
@@ -1107,8 +1449,14 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
1107
1449
  `${policy.name}: ${policy.roles.length > 0 ? policy.roles.join(", ") : policy.kind}`,
1108
1450
  );
1109
1451
  const secrets = contract.secrets.map((secret) => `${secret.name}${secret.required ? " (required)" : " (optional)"}`);
1452
+ const aiTools = contract.ai.tools.map((tool) =>
1453
+ `${tool.name}: ${tool.description ?? "no description"} (${tool.risk}${tool.needsApproval ? ", approval" : ""})`,
1454
+ );
1455
+ const aiAgents = contract.ai.agents.map((agent) =>
1456
+ `${agent.name}: ${agent.provider}/${agent.model} with ${agent.tools.length > 0 ? agent.tools.join(", ") : "no tools"}`,
1457
+ );
1110
1458
 
1111
- return normalizeNewlines(`# AGENTS.md
1459
+ const generated = localizeForgeCliMarkdown(workspaceRoot, `# AGENTS.md
1112
1460
 
1113
1461
  <!-- forge-generated:start -->
1114
1462
 
@@ -1116,23 +1464,51 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
1116
1464
 
1117
1465
  This is a ForgeOS application named \`${contract.project.name}\`.
1118
1466
 
1467
+ ## CLI entrypoint
1468
+
1469
+ ${cliEntrypoint}
1470
+
1119
1471
  ## Required workflow
1120
1472
 
1121
1473
  Before editing:
1122
1474
 
1123
1475
  \`\`\`bash
1476
+ forge agent onboard --target codex --json
1477
+ forge status --json
1478
+ forge changed --json
1479
+ forge handoff --json
1124
1480
  forge do inspect --json
1125
1481
  forge dev --once --json
1126
- forge inspect all --json
1482
+ forge agent print-context --json
1127
1483
  forge check --json
1128
1484
  \`\`\`
1129
1485
 
1486
+ ## CAIR first
1487
+
1488
+ Before reading large files or hand-writing patches, prefer the generated CAIR guide:
1489
+
1490
+ \`\`\`bash
1491
+ forge cair snapshot
1492
+ forge cair query "Q ST"
1493
+ forge cair query "Q S name=<symbol>"
1494
+ forge cair query "Q D S#1"
1495
+ forge cair query "Q R S#1"
1496
+ forge cair query "Q I S#1"
1497
+ \`\`\`
1498
+
1499
+ Use \`src/forge/_generated/agentCairGuide.md\` for the full compact protocol. Plan CAIR mutations before applying them:
1500
+
1501
+ \`\`\`bash
1502
+ forge cair action --plan "A RN t=S#1 nn=<newName>"
1503
+ forge cair action "A APPLY plan=<returned-plan-path>"
1504
+ \`\`\`
1505
+
1130
1506
  After editing:
1131
1507
 
1132
1508
  \`\`\`bash
1133
1509
  forge generate
1134
1510
  forge check
1135
- forge verify --strict
1511
+ ${finalVerify}
1136
1512
  \`\`\`
1137
1513
 
1138
1514
  ## Do not edit
@@ -1160,7 +1536,7 @@ Template apps may ignore \`src/forge/_generated/**\` and \`forge.lock\` in git t
1160
1536
  ## Runtime rules
1161
1537
 
1162
1538
  - Do not import network packages inside \`command\`, \`query\`, or \`liveQuery\`.
1163
- - Do not use \`process.env\` directly.
1539
+ - Do not read secrets or server runtime config through \`process.env\` in Forge runtime code; use \`ctx.secrets\` or generated config context. Public frontend bridge env such as \`NEXT_PUBLIC_*\` and \`NUXT_PUBLIC_*\` is allowed in web bridge files.
1164
1540
  - Do not access cross-tenant data.
1165
1541
  - Commands must use \`ctx.emit\` for side effects.
1166
1542
  - Actions and workflows handle side effects after commit.
@@ -1174,10 +1550,13 @@ forge do fix --json
1174
1550
  forge do verify --json
1175
1551
  forge dev --once --json
1176
1552
  forge dev
1553
+ forge handoff --json
1177
1554
  forge inspect app --json
1178
1555
  forge inspect all --json
1556
+ forge inspect all --full --json
1179
1557
  forge inspect frontend --json
1180
1558
  forge inspect capabilities --json
1559
+ forge inspect agent-tools --json
1181
1560
  forge deps inspect <package> --json
1182
1561
  forge deps api <package> <symbol> --json
1183
1562
  forge deps trace <package> --json
@@ -1191,9 +1570,13 @@ forge doctor
1191
1570
  forge doctor windows --json
1192
1571
  forge setup windows --json
1193
1572
  forge agent print-context --json
1573
+ forge agent doctor --target codex --json
1574
+ forge ai tools --json
1575
+ forge ai agents --json
1576
+ forge ai trace <traceId> --json
1194
1577
  forge verify --smoke
1195
1578
  forge verify --standard
1196
- forge verify --strict
1579
+ ${finalVerify}
1197
1580
  \`\`\`
1198
1581
 
1199
1582
  ## Data
@@ -1210,6 +1593,21 @@ ${renderList(policies)}
1210
1593
 
1211
1594
  ${renderList(secrets)}
1212
1595
 
1596
+ ## AI Tools And Agents
1597
+
1598
+ - AI SDK engine: Vercel AI SDK v6.
1599
+ - Forge layer: generated registry, runtime rules, telemetry, secrets, tenant/auth context, and agent contract.
1600
+ - Use \`ctx.agent.run\` or \`ctx.ai.runAgent\` only in actions, workflows, endpoints, and server code.
1601
+ - Do not create custom tool loops; use Forge tools and AI SDK \`ToolLoopAgent\` through the Forge runtime.
1602
+
1603
+ Tools:
1604
+
1605
+ ${renderList(aiTools)}
1606
+
1607
+ Agents:
1608
+
1609
+ ${renderList(aiAgents)}
1610
+
1213
1611
  ## Auth
1214
1612
 
1215
1613
  - Modes: ${contract.auth.modes.join(", ")}
@@ -1233,9 +1631,9 @@ ${contract.frontend.dev ? `- Web URL: ${contract.frontend.dev.url}
1233
1631
 
1234
1632
  Rules:
1235
1633
 
1236
- - Use the local \`web/**/lib/forge.ts\` bridge to generated hooks.
1237
- - Mount \`<ForgeProvider devAuth>\` in local development.
1238
- - Use \`useQuery\`, \`useCommand\`, and \`useLiveQuery\` instead of raw Forge endpoint fetches in React components.
1634
+ - Use the local \`web/**/lib/forge.ts\` or Nuxt \`web/composables/forge.ts\` bridge to generated bindings.
1635
+ - Mount \`<ForgeProvider devAuth>\` or install the Nuxt Forge plugin in local development.
1636
+ - Use \`useQuery\`/\`useCommand\`/\`useLiveQuery\` or \`useForgeQuery\`/\`useForgeCommand\`/\`useForgeLiveQuery\` instead of raw Forge endpoint fetches in components.
1239
1637
  - Keep frontend routes reflected in \`src/forge/_generated/frontendGraph.json\`.
1240
1638
 
1241
1639
  ## Common tasks
@@ -1258,7 +1656,7 @@ forge do verify --json
1258
1656
  1. Add file in \`src/commands\`.
1259
1657
  2. Declare \`auth: can("...")\`.
1260
1658
  3. Run \`forge generate\`.
1261
- 4. Run \`forge verify --strict\`.
1659
+ 4. Run \`${finalVerify}\`.
1262
1660
 
1263
1661
  ### Scaffold a resource
1264
1662
 
@@ -1268,6 +1666,8 @@ Use:
1268
1666
  forge make resource <name> --fields title:text,status:enum(open,closed) --dry-run --json
1269
1667
  forge make resource <name> --fields title:text,status:enum(open,closed) --with-ui --yes
1270
1668
  forge make ui --framework vite --dry-run --json
1669
+ forge make ui --framework nuxt --dry-run --json
1670
+ forge make ai-chat support --dry-run --json
1271
1671
  \`\`\`
1272
1672
 
1273
1673
  Review the plan before applying when the resource touches schema or policies.
@@ -1283,7 +1683,7 @@ forge inspect frontend --json
1283
1683
  forge inspect capabilities --json
1284
1684
  \`\`\`
1285
1685
 
1286
- \`forge dev\` starts the API runtime and web app together when \`web/\` exists. \`forge dev --once --json\` reports routes, components, \`ForgeProvider\`, bridge files, generated client bindings, direct runtime fetch warnings, capability-map parity warnings, and fix hints.
1686
+ \`forge dev\` starts the API runtime and web app together when \`web/\` exists. \`forge dev --once --json\` reports routes, components, providers/plugins, bridge files, generated client bindings, direct runtime fetch warnings, capability-map parity warnings, and fix hints.
1287
1687
 
1288
1688
  ### Apply a feature blueprint
1289
1689
 
@@ -1304,11 +1704,13 @@ Use:
1304
1704
  \`\`\`bash
1305
1705
  forge refactor rename field tickets.priority tickets.urgency --dry-run --json
1306
1706
  forge refactor rename field tickets.priority tickets.urgency --yes
1707
+ forge refactor rename command createTicket openTicket --dry-run --json
1708
+ forge refactor rename command createTicket openTicket --yes
1307
1709
  \`\`\`
1308
1710
 
1309
- These codemods are AST-aware for \`extract-action\`, \`rename field\`, and \`rename table\`. Field renames are scoped to the target table, so \`tickets.priority\` only rewrites references linked to \`tickets\`.
1711
+ These codemods are AST-aware for \`extract-action\`, \`rename command\`, \`rename field\`, and \`rename table\`. Command renames update runtime registries, generated client references, frontend hooks, tests, and string references where safe. Field renames are scoped to the target table, so \`tickets.priority\` only rewrites references linked to \`tickets\`.
1310
1712
 
1311
- Never edit \`src/forge/_generated/**\` directly. Review migration hints before applying field or table renames.
1713
+ Never edit \`src/forge/_generated/**\` directly. Review migration hints before applying command, field, or table renames.
1312
1714
 
1313
1715
  ### Plan impact-based tests
1314
1716
 
@@ -1321,7 +1723,7 @@ forge test run --changed --timeout-ms 120000 --json
1321
1723
  forge verify --standard
1322
1724
  \`\`\`
1323
1725
 
1324
- Use \`forge verify --standard\` for the normal agent development loop. Finish handoffs with \`forge verify --strict\` when the change is ready.
1726
+ Use \`forge verify --standard\` for the normal agent development loop. Finish handoffs with \`${finalVerify}\` when the change is ready.
1325
1727
 
1326
1728
  ### Repair a failing check
1327
1729
 
@@ -1334,6 +1736,20 @@ forge repair plan --from-last-test-run --write
1334
1736
 
1335
1737
  Apply only high-confidence deterministic repairs automatically. Review medium or low confidence repairs before changing code.
1336
1738
 
1739
+ ### Add AI tools or agents
1740
+
1741
+ Use:
1742
+
1743
+ \`\`\`bash
1744
+ forge generate
1745
+ forge inspect ai --json
1746
+ forge agent print-context --json
1747
+ forge ai check --json
1748
+ forge ai trace <traceId> --json
1749
+ \`\`\`
1750
+
1751
+ Define tools with \`aiTool({ inputSchema, outputSchema, risk, needsApproval, handler })\` and agents with \`agent({ provider, model, instructions, tools, stopWhen })\`. Execute agents with \`ctx.agent.run\` or \`ctx.ai.runAgent\` only from actions, workflows, endpoints, or server code. In dev, POST \`/ai/agents/run\` returns JSON for automation and POST \`/ai/agents/chat\` returns an AI SDK UIMessage stream for React \`useChat\`; both accept \`agent: "<exportedAgentName>"\` and use generated auto-tools from \`agentTools.json\`.
1752
+
1337
1753
  ### Export agent adapters
1338
1754
 
1339
1755
  Use:
@@ -1366,7 +1782,7 @@ forge deps upgrade-plan <package> --to latest
1366
1782
  forge deps inspect <package> --json
1367
1783
  forge deps api <package> <symbol> --json
1368
1784
  forge deps upgrade-apply <plan>
1369
- forge verify --strict
1785
+ ${finalVerify}
1370
1786
  \`\`\`
1371
1787
 
1372
1788
  Do not manually edit \`package.json\` for package upgrades unless necessary.
@@ -1387,10 +1803,11 @@ Durable invalidations live in \`_forge_live_invalidations\`.
1387
1803
 
1388
1804
  ${AGENTS_USER_START}
1389
1805
 
1390
- ${userNotes}
1806
+ ${AGENTS_USER_NOTES_TOKEN}
1391
1807
 
1392
1808
  ${AGENTS_USER_END}
1393
1809
  `);
1810
+ return normalizeNewlines(generated.replace(AGENTS_USER_NOTES_TOKEN, () => userNotes));
1394
1811
  }
1395
1812
 
1396
1813
  function renderAppMapMd(contract: AgentContract): string {
@@ -1471,6 +1888,48 @@ function renderAppMapMd(contract: AgentContract): string {
1471
1888
  lines.push(`### ${workflow.name}`, `Trigger: ${workflow.trigger ?? "manual"}`, "Steps:", ...renderList(workflow.steps).split("\n"), "");
1472
1889
  }
1473
1890
 
1891
+ lines.push("## AI", "");
1892
+ lines.push("### Providers", "", ...renderList(contract.ai.providers).split("\n"), "");
1893
+ lines.push("### Generations", "");
1894
+ for (const generation of contract.ai.generations) {
1895
+ lines.push(
1896
+ `- ${generation.method}: ${generation.provider}/${generation.model} in ${generation.file}${generation.purpose ? ` (${generation.purpose})` : ""}`,
1897
+ );
1898
+ }
1899
+ if (contract.ai.generations.length === 0) {
1900
+ lines.push("- none");
1901
+ }
1902
+ lines.push("", "### Tools", "");
1903
+ for (const tool of contract.ai.tools) {
1904
+ lines.push(
1905
+ `#### ${tool.name}`,
1906
+ `File: ${tool.file}`,
1907
+ `Risk: ${tool.risk}`,
1908
+ `Strict: ${tool.strict ? "yes" : "no"}`,
1909
+ `Needs approval: ${String(tool.needsApproval)}`,
1910
+ `Description: ${tool.description ?? "none"}`,
1911
+ "",
1912
+ );
1913
+ }
1914
+ if (contract.ai.tools.length === 0) {
1915
+ lines.push("- none", "");
1916
+ }
1917
+ lines.push("### Agents", "");
1918
+ for (const agent of contract.ai.agents) {
1919
+ lines.push(
1920
+ `#### ${agent.name}`,
1921
+ `File: ${agent.file}`,
1922
+ `Model: ${agent.provider}/${agent.model}`,
1923
+ "Tools:",
1924
+ ...renderList(agent.tools).split("\n"),
1925
+ `Stop when: ${JSON.stringify(agent.stopWhen)}`,
1926
+ "",
1927
+ );
1928
+ }
1929
+ if (contract.ai.agents.length === 0) {
1930
+ lines.push("- none", "");
1931
+ }
1932
+
1474
1933
  lines.push("## Frontend", "");
1475
1934
  lines.push(`Present: ${contract.frontend.present ? "yes" : "no"}`);
1476
1935
  lines.push(`Framework: ${contract.frontend.framework}`);
@@ -1631,6 +2090,72 @@ function renderCapabilityMapMd(capabilityMap: AgentCapabilityMap): string {
1631
2090
  return normalizeNewlines(lines.join("\n"));
1632
2091
  }
1633
2092
 
2093
+ function renderAgentToolsMd(registry: AgentToolRegistry): string {
2094
+ const lines = [
2095
+ "# Agent Tools",
2096
+ "",
2097
+ `Project: ${registry.project.name}`,
2098
+ "",
2099
+ "## Explicit AI Tools",
2100
+ "",
2101
+ ];
2102
+
2103
+ for (const tool of registry.explicitTools) {
2104
+ lines.push(
2105
+ `### ${tool.name}`,
2106
+ `File: ${tool.file}`,
2107
+ `Risk: ${tool.risk}`,
2108
+ `Strict: ${tool.strict ? "yes" : "no"}`,
2109
+ `Needs approval: ${String(tool.needsApproval)}`,
2110
+ `Description: ${tool.description ?? "none"}`,
2111
+ "",
2112
+ );
2113
+ }
2114
+ if (registry.explicitTools.length === 0) {
2115
+ lines.push("- none", "");
2116
+ }
2117
+
2118
+ lines.push("## Auto Tools From Forge Runtime", "");
2119
+ for (const tool of registry.autoTools) {
2120
+ lines.push(
2121
+ `### ${tool.name}`,
2122
+ `Source: ${tool.sourceKind} ${tool.sourceName}`,
2123
+ `File: ${tool.file}`,
2124
+ `HTTP: ${tool.http.method} ${tool.http.path}`,
2125
+ `Policy: ${tool.policy ?? "none"}`,
2126
+ `Requires auth: ${tool.requiresAuth ? "yes" : "no"}`,
2127
+ `Read-only: ${tool.readOnly ? "yes" : "no"}`,
2128
+ `Risk: ${tool.risk}`,
2129
+ `Needs approval: ${String(tool.needsApproval)}`,
2130
+ `Frontend hook: \`${tool.frontend.hook}\``,
2131
+ `Reads: ${tool.tablesRead.length > 0 ? tool.tablesRead.join(", ") : "none"}`,
2132
+ `Writes: ${tool.tablesWritten.length > 0 ? tool.tablesWritten.join(", ") : "none"}`,
2133
+ `Emits: ${tool.emits.length > 0 ? tool.emits.join(", ") : "none"}`,
2134
+ "",
2135
+ );
2136
+ }
2137
+ if (registry.autoTools.length === 0) {
2138
+ lines.push("- none", "");
2139
+ }
2140
+
2141
+ lines.push("## Agents", "");
2142
+ for (const agent of registry.agents) {
2143
+ lines.push(
2144
+ `### ${agent.name}`,
2145
+ `File: ${agent.file}`,
2146
+ `Model: ${agent.provider}/${agent.model}`,
2147
+ `Tools: ${agent.tools.length > 0 ? agent.tools.join(", ") : "none"}`,
2148
+ `Stop when: ${JSON.stringify(agent.stopWhen)}`,
2149
+ "",
2150
+ );
2151
+ }
2152
+ if (registry.agents.length === 0) {
2153
+ lines.push("- none", "");
2154
+ }
2155
+
2156
+ return normalizeNewlines(lines.join("\n"));
2157
+ }
2158
+
1634
2159
  function renderOperationPlaybooksMd(playbookEntries: AgentPlaybook[]): string {
1635
2160
  const lines = ["# Operation Playbooks", ""];
1636
2161
  for (const playbook of playbookEntries) {
@@ -1643,21 +2168,29 @@ function renderOperationPlaybooksMd(playbookEntries: AgentPlaybook[]): string {
1643
2168
  return normalizeNewlines(lines.join("\n"));
1644
2169
  }
1645
2170
 
1646
- function renderAgentQuickstartMd(): string {
1647
- return normalizeNewlines(`# Agent Quickstart
2171
+ function renderAgentQuickstartMd(workspaceRoot: string): string {
2172
+ const finalVerify = finalVerifyCommand(workspaceRoot);
2173
+ return normalizeNewlines(localizeForgeCliMarkdown(workspaceRoot, `# Agent Quickstart
1648
2174
 
1649
2175
  Run:
1650
2176
 
1651
2177
  \`\`\`bash
2178
+ forge agent onboard --target codex --json
2179
+ forge status --json
2180
+ forge changed --json
2181
+ forge handoff --json
1652
2182
  forge do inspect --json
1653
2183
  forge do fix --json
1654
2184
  forge do verify --json
1655
2185
  forge dev --once --json
1656
2186
  forge dev
1657
- forge inspect all --json
2187
+ forge agent print-context --json
1658
2188
  forge inspect frontend --json
1659
2189
  forge inspect capabilities --json
2190
+ forge inspect agent-tools --json
2191
+ forge inspect all --json
1660
2192
  forge check --json
2193
+ forge ai trace <traceId> --json
1661
2194
  \`\`\`
1662
2195
 
1663
2196
  Never edit:
@@ -1673,7 +2206,158 @@ Always finish with:
1673
2206
 
1674
2207
  \`\`\`bash
1675
2208
  forge generate
1676
- forge verify --strict
2209
+ ${finalVerify}
1677
2210
  \`\`\`
1678
- `);
2211
+ `));
2212
+ }
2213
+
2214
+ function renderAgentCairGuideMd(contract: AgentContract, workspaceRoot: string): string {
2215
+ const cair = contract.agentProtocols.find((protocol) => protocol.id === "cair");
2216
+ const finalVerify = finalVerifyCommand(workspaceRoot);
2217
+ const summary = [
2218
+ `commands=${contract.commands.length}`,
2219
+ `queries=${contract.queries.length}`,
2220
+ `liveQueries=${contract.liveQueries.length}`,
2221
+ `actions=${contract.actions.length}`,
2222
+ `workflows=${contract.workflows.length}`,
2223
+ `tables=${contract.data.tables.length}`,
2224
+ ].join(" ");
2225
+ return normalizeNewlines(localizeForgeCliMarkdown(workspaceRoot, `# CAIR Agent Guide
2226
+
2227
+ Project: ${contract.project.name}
2228
+ CAIR version: ${cair?.version ?? CAIR_SCHEMA_VERSION}
2229
+ Surface: ${summary}
2230
+
2231
+ CAIR is the compact agent protocol for reading and changing this Forge workspace. Use it before opening whole files when symbol, module, dependency, test, or impact context is enough.
2232
+
2233
+ ## First commands
2234
+
2235
+ \`\`\`bash
2236
+ forge cair snapshot
2237
+ forge cair query "Q ST"
2238
+ \`\`\`
2239
+
2240
+ The snapshot emits compact ids:
2241
+
2242
+ - \`M#\` modules/files
2243
+ - \`S#\` symbols
2244
+ - \`P#\` packages
2245
+ - \`API#\` dependency APIs
2246
+ - \`T#\` tests
2247
+
2248
+ ## Read before editing
2249
+
2250
+ \`\`\`bash
2251
+ forge cair query "Q S name=<symbol>"
2252
+ forge cair query "Q D S#1"
2253
+ forge cair query "Q R S#1"
2254
+ forge cair query "Q I S#1"
2255
+ forge cair query "Q T S#1"
2256
+ forge cair query "Q DEP.API package=<pkg> symbol=<export>"
2257
+ \`\`\`
2258
+
2259
+ Only open source files after CAIR shows that the exact file or body is needed.
2260
+
2261
+ ## Plan, apply, rollback
2262
+
2263
+ Never apply semantic mutations first. Create a plan:
2264
+
2265
+ \`\`\`bash
2266
+ forge cair action --plan "A RN t=S#1 nn=<newName>"
2267
+ \`\`\`
2268
+
2269
+ Apply the returned plan path:
2270
+
2271
+ \`\`\`bash
2272
+ forge cair action "A APPLY plan=<P#|.forge/cair/plans/...json>"
2273
+ \`\`\`
2274
+
2275
+ Keep returned journal paths for rollback:
2276
+
2277
+ \`\`\`bash
2278
+ forge cair action "A ROLLBACK journal=.forge/cair/journal/<journal>.json"
2279
+ \`\`\`
2280
+
2281
+ ## Semantic actions
2282
+
2283
+ \`\`\`txt
2284
+ A RN t=S#1 nn=<newName>
2285
+ A MV t=S#1 to=src/target.ts
2286
+ A SIG t=S#1 signature="export function x(input: string): boolean"
2287
+ A PARAM t=S#1 name=tenantId type=string default="defaultTenant"
2288
+ A CALLS t=S#1 appendArg="defaultTenant"
2289
+ A OI f=M#1
2290
+ A FMT f=M#1
2291
+ \`\`\`
2292
+
2293
+ For high-risk semantic actions, include expectations when available:
2294
+
2295
+ \`\`\`txt
2296
+ expect.file=src/path.ts
2297
+ expect.kind=command
2298
+ expect.hash=<sha256>
2299
+ \`\`\`
2300
+
2301
+ ## Forge-native actions
2302
+
2303
+ Prefer Forge-native CAIR actions over hand-writing boilerplate:
2304
+
2305
+ \`\`\`txt
2306
+ A MC n=createTicket
2307
+ A MQ n=listTickets
2308
+ A MA n=chargeCustomer
2309
+ A MT n=tickets fields=title:text,status:text
2310
+ A AT t=S#1 kind=unit
2311
+ A WX t=S#1 file=src/index.ts
2312
+ \`\`\`
2313
+
2314
+ ## Compact aliases
2315
+
2316
+ Queries:
2317
+
2318
+ \`\`\`txt
2319
+ Q ST = Q STATUS
2320
+ Q S = Q SYMBOL
2321
+ Q D = Q DEF
2322
+ Q R = Q REFS
2323
+ Q I = Q IMPACT
2324
+ Q M = Q MODULE
2325
+ Q T = Q TESTS
2326
+ Q API = Q DEP.API
2327
+ \`\`\`
2328
+
2329
+ Actions:
2330
+
2331
+ \`\`\`txt
2332
+ A RN = A RENAME.SYMBOL
2333
+ A MV = A MOVE.SYMBOL
2334
+ A OI = A ORGANIZE.IMPORTS
2335
+ A FMT = A FORMAT
2336
+ A MC = A MAKE.COMMAND
2337
+ A MQ = A MAKE.QUERY
2338
+ A MA = A MAKE.ACTION
2339
+ A MT = A MAKE.TABLE
2340
+ A AT = A ADD.TEST
2341
+ A WX = A WIRE.EXPORT
2342
+ A AP = A APPLY
2343
+ A RB = A ROLLBACK
2344
+ \`\`\`
2345
+
2346
+ ## Verification
2347
+
2348
+ After CAIR edits, run the narrowest useful checks:
2349
+
2350
+ \`\`\`bash
2351
+ forge check --json
2352
+ forge verify --standard
2353
+ ${finalVerify}
2354
+ \`\`\`
2355
+
2356
+ ## Constraints
2357
+
2358
+ - Do not edit \`src/forge/_generated/**\` unless explicitly allowed.
2359
+ - Do not bypass \`--plan\` for semantic edits.
2360
+ - Do not use CAIR as blind text replacement when a semantic action exists.
2361
+ - Use TypeScript language service, ast-grep, ts-morph, or raw file reads only as implementation backends or fallbacks. CAIR is the agent-facing protocol.
2362
+ `));
1679
2363
  }