forgeos 0.1.0-alpha.7 → 0.1.0-alpha.71

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 (598) hide show
  1. package/.agents/skills/forge-agent-fabric/SKILL.md +178 -0
  2. package/.agents/skills/forge-agent-fabric/references/managed-workflows.md +95 -0
  3. package/.agents/skills/forge-agent-fabric/references/repository-analysis.md +102 -0
  4. package/.agents/skills/forge-agent-fabric/scripts/fabric.mjs +46 -0
  5. package/.agents/skills/forge-agent-fabric/scripts/repository.mjs +44 -0
  6. package/.npmignore +10 -0
  7. package/AGENTS.md +142 -90
  8. package/CHANGELOG.md +870 -9
  9. package/LICENSE +21 -0
  10. package/README.md +121 -6
  11. package/adapters/go/README.md +23 -0
  12. package/adapters/go/go.mod +3 -0
  13. package/adapters/go/http.go +149 -0
  14. package/adapters/go/registry.go +234 -0
  15. package/adapters/go/types.go +136 -0
  16. package/adapters/java/README.md +68 -0
  17. package/adapters/java/pom.xml +47 -0
  18. package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
  19. package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
  20. package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
  21. package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
  22. package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
  23. package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
  24. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
  25. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
  26. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
  27. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
  28. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
  29. package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
  30. package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
  31. package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
  32. package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
  33. package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
  34. package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
  35. package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
  36. package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
  37. package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
  38. package/adapters/java-spring-boot-starter/README.md +32 -0
  39. package/adapters/java-spring-boot-starter/pom.xml +49 -0
  40. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
  41. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
  42. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
  43. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
  44. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
  45. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
  46. package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  47. package/bin/forge.mjs +18 -0
  48. package/docs/agent-fabric-programs.md +151 -0
  49. package/docs/agent-fabric.md +582 -0
  50. package/docs/architecture/agent-fabric/PORTABLE_PROJECTS_PLAN.md +136 -0
  51. package/docs/architecture/agent-fabric/README.md +180 -0
  52. package/docs/architecture/agent-fabric/REPOSITORY_MANIFEST_PLAN.md +284 -0
  53. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_ADR.md +81 -0
  54. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS.md +39 -0
  55. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS_EVIDENCE.md +53 -0
  56. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_EVIDENCE.md +49 -0
  57. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_PLAN.md +590 -0
  58. package/docs/cair-protocol.md +103 -0
  59. package/docs/changelog.md +1070 -0
  60. package/docs/forge-protocol.md +189 -0
  61. package/docs/repository-agent-benchmark.md +179 -0
  62. package/docs/repository-analysis.md +139 -0
  63. package/docs/repository-context-quality.md +179 -0
  64. package/docs/repository-runtime-observation.md +82 -0
  65. package/examples/agent-fabric-v2/README.md +70 -0
  66. package/examples/agent-fabric-v2/item-child.workflow.ts +11 -0
  67. package/examples/agent-fabric-v2/make-request.mjs +4 -0
  68. package/examples/agent-fabric-v2/map-child.workflow.ts +10 -0
  69. package/examples/agent-fabric-v2/migrate.workflow.ts +35 -0
  70. package/examples/agent-fabric-v2/registry.example.json +256 -0
  71. package/examples/agent-fabric-v2/run-ui-fixture.ts +48 -0
  72. package/examples/agent-fabric-v2/ui-audit.workflow.ts +28 -0
  73. package/examples/agent-fabric-v2/ui-fixture-worker.cjs +36 -0
  74. package/examples/agent-fabric-v2/visual-population.json +13 -0
  75. package/examples/agent-fabric-v2/workers/check.mjs +2 -0
  76. package/examples/agent-fabric-v2/workers/common.mjs +7 -0
  77. package/examples/agent-fabric-v2/workers/discover.mjs +2 -0
  78. package/examples/agent-fabric-v2/workers/migrate.mjs +4 -0
  79. package/examples/agent-fabric-v2/workers/review.mjs +3 -0
  80. package/examples/go-billing/go.mod +7 -0
  81. package/examples/go-billing/main.go +120 -0
  82. package/examples/java-billing/pom.xml +60 -0
  83. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
  84. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
  85. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
  86. package/package.json +60 -5
  87. package/schemas/agent-fabric/v0.1/control-event.schema.json +281 -0
  88. package/schemas/forge-manifest.schema.json +389 -0
  89. package/scripts/field-test-forgeos.mjs +1021 -0
  90. package/scripts/install-agent-fabric-skill.mjs +105 -0
  91. package/src/forge/_generated/releaseManifest.json +1 -2
  92. package/src/forge/_generated/releaseManifest.ts +3 -3
  93. package/src/forge/agent-adapters/index.ts +1592 -125
  94. package/src/forge/agent-adapters/types.ts +225 -1
  95. package/src/forge/agent-fabric/adapter.ts +131 -0
  96. package/src/forge/agent-fabric/attached-snapshot.ts +55 -0
  97. package/src/forge/agent-fabric/attached-task-contract.ts +105 -0
  98. package/src/forge/agent-fabric/attached-task-service.ts +127 -0
  99. package/src/forge/agent-fabric/attached-task-store.ts +109 -0
  100. package/src/forge/agent-fabric/authority.ts +298 -0
  101. package/src/forge/agent-fabric/canonical.ts +135 -0
  102. package/src/forge/agent-fabric/codex-adversarial-review.ts +229 -0
  103. package/src/forge/agent-fabric/codex-sdk-worker.ts +203 -0
  104. package/src/forge/agent-fabric/conductor.ts +754 -0
  105. package/src/forge/agent-fabric/dictionary.ts +12 -0
  106. package/src/forge/agent-fabric/errors.ts +32 -0
  107. package/src/forge/agent-fabric/hardened-conductor.ts +485 -0
  108. package/src/forge/agent-fabric/hardened-reducer.ts +211 -0
  109. package/src/forge/agent-fabric/index.ts +48 -0
  110. package/src/forge/agent-fabric/journal.ts +116 -0
  111. package/src/forge/agent-fabric/local-adaptive-digest-worker.mjs +26 -0
  112. package/src/forge/agent-fabric/local-adaptive-harness.ts +343 -0
  113. package/src/forge/agent-fabric/local-adaptive-service.ts +398 -0
  114. package/src/forge/agent-fabric/local-adaptive-worker.ts +146 -0
  115. package/src/forge/agent-fabric/local-approval-window.ts +211 -0
  116. package/src/forge/agent-fabric/local-change-review-service.ts +374 -0
  117. package/src/forge/agent-fabric/local-coding-worker.ts +285 -0
  118. package/src/forge/agent-fabric/local-control-store.ts +239 -0
  119. package/src/forge/agent-fabric/local-effect-broker.ts +348 -0
  120. package/src/forge/agent-fabric/local-evolution-approval.ts +81 -0
  121. package/src/forge/agent-fabric/local-evolution-profile.ts +87 -0
  122. package/src/forge/agent-fabric/local-evolution-registry.ts +427 -0
  123. package/src/forge/agent-fabric/local-evolution-service.ts +200 -0
  124. package/src/forge/agent-fabric/local-intelligence.ts +281 -0
  125. package/src/forge/agent-fabric/local-paths.ts +18 -0
  126. package/src/forge/agent-fabric/local-task-contract.ts +203 -0
  127. package/src/forge/agent-fabric/local-task-inbox.ts +543 -0
  128. package/src/forge/agent-fabric/local-task-server.ts +374 -0
  129. package/src/forge/agent-fabric/local-task-service.ts +982 -0
  130. package/src/forge/agent-fabric/local-verification.ts +551 -0
  131. package/src/forge/agent-fabric/managed-environment.ts +205 -0
  132. package/src/forge/agent-fabric/managed-run-contract.ts +103 -0
  133. package/src/forge/agent-fabric/managed-run-service.ts +401 -0
  134. package/src/forge/agent-fabric/managed-run-store.ts +165 -0
  135. package/src/forge/agent-fabric/managed-workspace.ts +253 -0
  136. package/src/forge/agent-fabric/p0a.ts +104 -0
  137. package/src/forge/agent-fabric/p0b-model-adapter.ts +434 -0
  138. package/src/forge/agent-fabric/planning.ts +155 -0
  139. package/src/forge/agent-fabric/program-api.ts +37 -0
  140. package/src/forge/agent-fabric/program-contract.ts +283 -0
  141. package/src/forge/agent-fabric/program-dsl.ts +126 -0
  142. package/src/forge/agent-fabric/program-evidence.ts +22 -0
  143. package/src/forge/agent-fabric/program-image.ts +15 -0
  144. package/src/forge/agent-fabric/program-lock.ts +50 -0
  145. package/src/forge/agent-fabric/program-owner.ts +16 -0
  146. package/src/forge/agent-fabric/program-scheduler.ts +38 -0
  147. package/src/forge/agent-fabric/program-service.ts +793 -0
  148. package/src/forge/agent-fabric/program-store.ts +142 -0
  149. package/src/forge/agent-fabric/program-structure.ts +65 -0
  150. package/src/forge/agent-fabric/program-types.ts +110 -0
  151. package/src/forge/agent-fabric/program-view.ts +12 -0
  152. package/src/forge/agent-fabric/program-worker.ts +108 -0
  153. package/src/forge/agent-fabric/project-profile.ts +50 -0
  154. package/src/forge/agent-fabric/project-registry.ts +120 -0
  155. package/src/forge/agent-fabric/project-runtime.ts +85 -0
  156. package/src/forge/agent-fabric/readiness.ts +26 -0
  157. package/src/forge/agent-fabric/reducer.ts +863 -0
  158. package/src/forge/agent-fabric/repository-context.ts +83 -0
  159. package/src/forge/agent-fabric/resource-ledger.ts +266 -0
  160. package/src/forge/agent-fabric/serialized-local-adapter.ts +60 -0
  161. package/src/forge/agent-fabric/types.ts +424 -0
  162. package/src/forge/agent-fabric/validation.ts +500 -0
  163. package/src/forge/agent-fabric/workflow-engine.ts +218 -0
  164. package/src/forge/agent-fabric/workflow-task-actions.ts +104 -0
  165. package/src/forge/agent-fabric/workflow-templates.ts +11 -0
  166. package/src/forge/agent-memory/bridge.ts +1728 -0
  167. package/src/forge/agent-memory/context-pack.ts +284 -0
  168. package/src/forge/agent-memory/hook-runner.ts +331 -0
  169. package/src/forge/agent-memory/mcp.ts +597 -0
  170. package/src/forge/agent-memory/normalize.ts +498 -0
  171. package/src/forge/agent-memory/redaction.ts +103 -0
  172. package/src/forge/agent-memory/sources/claude-code.ts +51 -0
  173. package/src/forge/agent-memory/sources/codex-hook-runner.mjs +343 -0
  174. package/src/forge/agent-memory/sources/codex.ts +161 -0
  175. package/src/forge/agent-memory/sources/cursor.ts +35 -0
  176. package/src/forge/agent-memory/types.ts +215 -0
  177. package/src/forge/bench.ts +248 -0
  178. package/src/forge/brownfield-import/index.ts +896 -0
  179. package/src/forge/brownfield-import/types.ts +127 -0
  180. package/src/forge/cair/action-journal.ts +61 -0
  181. package/src/forge/cair/action-parser.ts +314 -0
  182. package/src/forge/cair/action-validator.ts +40 -0
  183. package/src/forge/cair/actions.ts +1818 -0
  184. package/src/forge/cair/format.ts +77 -0
  185. package/src/forge/cair/index.ts +118 -0
  186. package/src/forge/cair/query.ts +478 -0
  187. package/src/forge/cair/snapshot.ts +315 -0
  188. package/src/forge/cair/types.ts +255 -0
  189. package/src/forge/cli/adaptive.ts +51 -0
  190. package/src/forge/cli/ai.ts +16 -1
  191. package/src/forge/cli/auth.ts +459 -15
  192. package/src/forge/cli/authmd.ts +441 -0
  193. package/src/forge/cli/baseline.ts +112 -0
  194. package/src/forge/cli/build.ts +20 -4
  195. package/src/forge/cli/changed.ts +418 -0
  196. package/src/forge/cli/codex-app-server.ts +877 -0
  197. package/src/forge/cli/commands.ts +1859 -20
  198. package/src/forge/cli/db.ts +209 -2
  199. package/src/forge/cli/deploy.ts +1339 -0
  200. package/src/forge/cli/deps.ts +150 -23
  201. package/src/forge/cli/dev.ts +1137 -53
  202. package/src/forge/cli/docs.ts +265 -0
  203. package/src/forge/cli/doctor.ts +297 -0
  204. package/src/forge/cli/env-placeholders.ts +62 -0
  205. package/src/forge/cli/evolution.ts +40 -0
  206. package/src/forge/cli/fabric.ts +253 -0
  207. package/src/forge/cli/field-test.ts +568 -0
  208. package/src/forge/cli/golden-path.ts +487 -0
  209. package/src/forge/cli/handoff.ts +336 -0
  210. package/src/forge/cli/index.ts +1 -0
  211. package/src/forge/cli/last-run.ts +84 -0
  212. package/src/forge/cli/main.ts +196 -3
  213. package/src/forge/cli/new.ts +169 -17
  214. package/src/forge/cli/next-actions.ts +23 -0
  215. package/src/forge/cli/output.ts +398 -6
  216. package/src/forge/cli/parse.ts +1377 -38
  217. package/src/forge/cli/progress.ts +51 -0
  218. package/src/forge/cli/query.ts +32 -0
  219. package/src/forge/cli/release.ts +35 -11
  220. package/src/forge/cli/repository.ts +151 -0
  221. package/src/forge/cli/run.ts +42 -0
  222. package/src/forge/cli/secrets.ts +137 -1
  223. package/src/forge/cli/seed.ts +581 -0
  224. package/src/forge/cli/self-host.ts +56 -14
  225. package/src/forge/cli/studio.ts +2282 -0
  226. package/src/forge/cli/verify.ts +1458 -32
  227. package/src/forge/cli/windows.ts +23 -0
  228. package/src/forge/cli/workos.ts +3509 -0
  229. package/src/forge/compiler/agent-contract/build.ts +728 -64
  230. package/src/forge/compiler/agent-contract/types.ts +45 -2
  231. package/src/forge/compiler/ai-registry/parse.ts +71 -2
  232. package/src/forge/compiler/api-surface/build.ts +47 -0
  233. package/src/forge/compiler/app-graph/build.ts +112 -9
  234. package/src/forge/compiler/app-graph/extract.ts +107 -0
  235. package/src/forge/compiler/app-graph/module-graph.ts +73 -78
  236. package/src/forge/compiler/app-graph/parser.ts +24 -24
  237. package/src/forge/compiler/app-graph/profile.ts +26 -0
  238. package/src/forge/compiler/app-graph/tsconfig-hash.ts +41 -4
  239. package/src/forge/compiler/app-graph/versions.ts +1 -1
  240. package/src/forge/compiler/classifier/capabilities.ts +3 -2
  241. package/src/forge/compiler/classifier/classify.ts +32 -8
  242. package/src/forge/compiler/classifier/secrets.ts +3 -2
  243. package/src/forge/compiler/classifier/signals.ts +91 -1
  244. package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
  245. package/src/forge/compiler/client-sdk/render-client.ts +295 -13
  246. package/src/forge/compiler/data-graph/build.ts +29 -1
  247. package/src/forge/compiler/data-graph/parse.ts +20 -4
  248. package/src/forge/compiler/data-graph/sql/ddl.ts +144 -31
  249. package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
  250. package/src/forge/compiler/data-graph/sql/types.ts +1 -0
  251. package/src/forge/compiler/diagnostics/codes.ts +38 -0
  252. package/src/forge/compiler/diagnostics/create.ts +28 -2
  253. package/src/forge/compiler/diagnostics/index.ts +2 -0
  254. package/src/forge/compiler/emitter/barrel.ts +3 -0
  255. package/src/forge/compiler/emitter/render.ts +9 -0
  256. package/src/forge/compiler/external-manifest/registry.ts +217 -0
  257. package/src/forge/compiler/external-manifest/types.ts +91 -0
  258. package/src/forge/compiler/external-manifest/validate.ts +373 -0
  259. package/src/forge/compiler/frontend-graph/build.ts +142 -14
  260. package/src/forge/compiler/integration/add.ts +991 -33
  261. package/src/forge/compiler/integration/plan.ts +43 -12
  262. package/src/forge/compiler/integration/render.ts +29 -0
  263. package/src/forge/compiler/integration/snapshot.ts +2 -0
  264. package/src/forge/compiler/integration/templates/convex.ts +70 -0
  265. package/src/forge/compiler/integration/templates/index.ts +1 -0
  266. package/src/forge/compiler/integration/templates/render.ts +38 -0
  267. package/src/forge/compiler/integration/templates/types.ts +3 -0
  268. package/src/forge/compiler/integration/templates/workos.ts +1439 -0
  269. package/src/forge/compiler/make-registry/build.ts +8 -9
  270. package/src/forge/compiler/orchestrator/fast-check.ts +4 -0
  271. package/src/forge/compiler/orchestrator/generate-lock.ts +14 -3
  272. package/src/forge/compiler/orchestrator/manifest.ts +1 -1
  273. package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
  274. package/src/forge/compiler/orchestrator/plan.ts +249 -10
  275. package/src/forge/compiler/orchestrator/profile.ts +65 -0
  276. package/src/forge/compiler/orchestrator/run.ts +101 -33
  277. package/src/forge/compiler/orchestrator/serialize.ts +33 -8
  278. package/src/forge/compiler/orchestrator/types.ts +1 -1
  279. package/src/forge/compiler/package-graph/compiler.ts +3 -1
  280. package/src/forge/compiler/package-graph/constants.ts +1 -1
  281. package/src/forge/compiler/package-graph/dts-extractor.ts +14 -1
  282. package/src/forge/compiler/package-manager/adapter.ts +4 -1
  283. package/src/forge/compiler/package-manager/commands.ts +4 -0
  284. package/src/forge/compiler/package-manager/executor.ts +30 -1
  285. package/src/forge/compiler/package-manager/version.ts +36 -12
  286. package/src/forge/compiler/package-upgrades/planner.ts +155 -18
  287. package/src/forge/compiler/package-upgrades/types.ts +2 -0
  288. package/src/forge/compiler/policy-registry/build.ts +47 -2
  289. package/src/forge/compiler/policy-registry/parse.ts +32 -2
  290. package/src/forge/compiler/recipes/definitions.ts +63 -0
  291. package/src/forge/compiler/recipes/index.ts +2 -0
  292. package/src/forge/compiler/recipes/profiles.ts +81 -0
  293. package/src/forge/compiler/recipes/registry.ts +6 -0
  294. package/src/forge/compiler/test-graph/build.ts +11 -3
  295. package/src/forge/compiler/types/app-graph.ts +8 -2
  296. package/src/forge/compiler/types/cli.ts +76 -1
  297. package/src/forge/compiler/types/dev-manifest.ts +4 -0
  298. package/src/forge/compiler/types/emit.ts +2 -0
  299. package/src/forge/compiler/types/frontend-graph.ts +2 -2
  300. package/src/forge/compiler/types/integration.ts +1 -0
  301. package/src/forge/compiler/types/package-graph.ts +6 -0
  302. package/src/forge/compiler/types/policy-registry.ts +3 -1
  303. package/src/forge/delta/broker-runner.mjs +5 -0
  304. package/src/forge/delta/broker.ts +429 -0
  305. package/src/forge/delta/classifier.ts +52 -0
  306. package/src/forge/delta/explain.ts +238 -0
  307. package/src/forge/delta/git-observer.ts +67 -0
  308. package/src/forge/delta/ids.ts +44 -0
  309. package/src/forge/delta/index.ts +25 -0
  310. package/src/forge/delta/process-identity.ts +37 -0
  311. package/src/forge/delta/queue-status.ts +190 -0
  312. package/src/forge/delta/recorder.ts +540 -0
  313. package/src/forge/delta/redaction.ts +50 -0
  314. package/src/forge/delta/schema.ts +240 -0
  315. package/src/forge/delta/session.ts +142 -0
  316. package/src/forge/delta/status.ts +1139 -0
  317. package/src/forge/delta/store.ts +3329 -0
  318. package/src/forge/delta/timeline.ts +178 -0
  319. package/src/forge/dev/server.ts +1061 -22
  320. package/src/forge/dev/types.ts +15 -1
  321. package/src/forge/dev/watch.ts +17 -7
  322. package/src/forge/dev-console/cycle.ts +285 -33
  323. package/src/forge/dev-console/types.ts +47 -1
  324. package/src/forge/impact/index.ts +222 -30
  325. package/src/forge/impact/types.ts +33 -1
  326. package/src/forge/intent/index.ts +35 -16
  327. package/src/forge/make/fields.ts +26 -0
  328. package/src/forge/make/index.ts +42 -6
  329. package/src/forge/make/templates.ts +211 -4
  330. package/src/forge/make/types.ts +2 -1
  331. package/src/forge/policy.ts +1 -1
  332. package/src/forge/react/index.ts +160 -2
  333. package/src/forge/refactor/index.ts +1 -0
  334. package/src/forge/repair/rules/index.ts +2 -2
  335. package/src/forge/repository-analysis/adapters/common.ts +72 -0
  336. package/src/forge/repository-analysis/adapters/docker.ts +185 -0
  337. package/src/forge/repository-analysis/adapters/java.ts +133 -0
  338. package/src/forge/repository-analysis/adapters/typescript.ts +350 -0
  339. package/src/forge/repository-analysis/adapters/vue.ts +71 -0
  340. package/src/forge/repository-analysis/analyze.ts +434 -0
  341. package/src/forge/repository-analysis/benchmark.ts +336 -0
  342. package/src/forge/repository-analysis/cache-gc.ts +154 -0
  343. package/src/forge/repository-analysis/check-selection.ts +123 -0
  344. package/src/forge/repository-analysis/context-node.ts +17 -0
  345. package/src/forge/repository-analysis/context.ts +456 -0
  346. package/src/forge/repository-analysis/http-resolution.ts +135 -0
  347. package/src/forge/repository-analysis/identity.ts +45 -0
  348. package/src/forge/repository-analysis/index.ts +18 -0
  349. package/src/forge/repository-analysis/nuxt-resolution.ts +188 -0
  350. package/src/forge/repository-analysis/quality.ts +60 -0
  351. package/src/forge/repository-analysis/retrieval.ts +309 -0
  352. package/src/forge/repository-analysis/runtime-artifacts.ts +195 -0
  353. package/src/forge/repository-analysis/runtime-observation.ts +325 -0
  354. package/src/forge/repository-analysis/scanner.ts +174 -0
  355. package/src/forge/repository-analysis/storage.ts +193 -0
  356. package/src/forge/repository-analysis/test-associations.ts +59 -0
  357. package/src/forge/repository-analysis/types.ts +99 -0
  358. package/src/forge/repository-manifest/index.ts +178 -0
  359. package/src/forge/repository-manifest/types.ts +63 -0
  360. package/src/forge/review/index.ts +162 -12
  361. package/src/forge/review/types.ts +15 -0
  362. package/src/forge/runtime/ai/providers.ts +19 -4
  363. package/src/forge/runtime/auth/config.ts +17 -0
  364. package/src/forge/runtime/auth/evaluate.ts +15 -2
  365. package/src/forge/runtime/auth/resolve.ts +61 -6
  366. package/src/forge/runtime/auth/types.ts +1 -0
  367. package/src/forge/runtime/db/factory.ts +1 -3
  368. package/src/forge/runtime/db/generated-client.ts +13 -2
  369. package/src/forge/runtime/db/memory-adapter.ts +139 -32
  370. package/src/forge/runtime/db/pglite-adapter.ts +285 -2
  371. package/src/forge/runtime/executor.ts +129 -16
  372. package/src/forge/runtime/external/bridge.ts +663 -0
  373. package/src/forge/runtime/runner/run-entry.ts +16 -7
  374. package/src/forge/runtime/telemetry/buffer.ts +4 -1
  375. package/src/forge/runtime/telemetry/scrubber.ts +35 -5
  376. package/src/forge/runtime/webhooks/security.ts +12 -7
  377. package/src/forge/server.ts +71 -7
  378. package/src/forge/ui/index.ts +831 -19
  379. package/src/forge/ui/types.ts +3 -1
  380. package/src/forge/version.ts +1 -1
  381. package/src/forge/vue/index.ts +422 -0
  382. package/src/forge/workspace/baseline.ts +112 -0
  383. package/src/forge/workspace/change-summary.ts +292 -0
  384. package/src/forge/workspace/forge-cli.ts +42 -0
  385. package/src/forge/workspace/git-summary.ts +393 -0
  386. package/templates/agent-workroom/AGENTS.md +29 -0
  387. package/templates/agent-workroom/README.md +34 -0
  388. package/templates/agent-workroom/forge.config.ts +3 -0
  389. package/templates/agent-workroom/package.json +34 -0
  390. package/templates/agent-workroom/pnpm-workspace.yaml +2 -0
  391. package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
  392. package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
  393. package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
  394. package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
  395. package/templates/agent-workroom/src/forge/schema.ts +54 -0
  396. package/templates/agent-workroom/src/policies.ts +6 -0
  397. package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
  398. package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
  399. package/templates/agent-workroom/tsconfig.json +16 -0
  400. package/templates/agent-workroom/web/index.html +13 -0
  401. package/templates/agent-workroom/web/package.json +21 -0
  402. package/templates/agent-workroom/web/src/App.tsx +345 -0
  403. package/templates/agent-workroom/web/src/lib/forge.ts +20 -0
  404. package/templates/agent-workroom/web/src/main.tsx +13 -0
  405. package/templates/agent-workroom/web/src/styles.css +545 -0
  406. package/templates/agent-workroom/web/tsconfig.json +27 -0
  407. package/templates/agent-workroom/web/vite.config.ts +36 -0
  408. package/templates/b2b-support-web/package.json +2 -0
  409. package/templates/b2b-support-web/pnpm-workspace.yaml +2 -0
  410. package/templates/b2b-support-web/web/app/page.tsx +2 -2
  411. package/templates/b2b-support-web/web/lib/forge.ts +9 -2
  412. package/templates/b2b-support-web/web/next.config.ts +24 -0
  413. package/templates/b2b-support-web/web/package.json +1 -1
  414. package/templates/minimal-web/package.json +2 -1
  415. package/templates/minimal-web/pnpm-workspace.yaml +2 -0
  416. package/templates/minimal-web/web/index.html +1 -0
  417. package/templates/minimal-web/web/src/App.tsx +12 -6
  418. package/templates/minimal-web/web/src/lib/forge.ts +9 -2
  419. package/templates/minimal-web/web/src/styles.css +34 -0
  420. package/templates/minimal-web/web/vite.config.ts +36 -0
  421. package/templates/nuxt-web/.vscode/settings.json +14 -0
  422. package/templates/nuxt-web/.yarnrc.yml +1 -0
  423. package/templates/nuxt-web/README.md +30 -0
  424. package/templates/nuxt-web/forge.config.ts +3 -0
  425. package/templates/nuxt-web/package.json +37 -0
  426. package/templates/nuxt-web/pnpm-workspace.yaml +2 -0
  427. package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
  428. package/templates/nuxt-web/src/commands/createNote.ts +26 -0
  429. package/templates/nuxt-web/src/forge/schema.ts +12 -0
  430. package/templates/nuxt-web/src/policies.ts +6 -0
  431. package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
  432. package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
  433. package/templates/nuxt-web/tsconfig.json +17 -0
  434. package/templates/nuxt-web/web/app.vue +67 -0
  435. package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
  436. package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
  437. package/templates/nuxt-web/web/composables/forge.ts +13 -0
  438. package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
  439. package/templates/nuxt-web/web/nuxt.config.ts +11 -0
  440. package/templates/nuxt-web/web/package.json +22 -0
  441. package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
  442. package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
  443. package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
  444. package/templates/nuxt-web/web/tsconfig.json +6 -0
  445. package/templates/vendor-access/.vscode/settings.json +14 -0
  446. package/templates/vendor-access/README.md +30 -0
  447. package/templates/vendor-access/forge.config.ts +3 -0
  448. package/templates/vendor-access/package.json +35 -0
  449. package/templates/vendor-access/pnpm-workspace.yaml +2 -0
  450. package/templates/vendor-access/src/commands/addEvidence.ts +42 -0
  451. package/templates/vendor-access/src/commands/approveAccessRequest.ts +43 -0
  452. package/templates/vendor-access/src/commands/createAccessRequest.ts +49 -0
  453. package/templates/vendor-access/src/commands/seedVendorAccessDemo.ts +200 -0
  454. package/templates/vendor-access/src/forge/schema.ts +74 -0
  455. package/templates/vendor-access/src/policies.ts +11 -0
  456. package/templates/vendor-access/src/queries/listVendorAccessDashboard.ts +24 -0
  457. package/templates/vendor-access/src/queries/liveVendorAccessDashboard.ts +24 -0
  458. package/templates/vendor-access/tsconfig.json +17 -0
  459. package/templates/vendor-access/web/index.html +13 -0
  460. package/templates/vendor-access/web/package.json +21 -0
  461. package/templates/vendor-access/web/src/App.tsx +573 -0
  462. package/templates/vendor-access/web/src/lib/forge.ts +20 -0
  463. package/templates/vendor-access/web/src/main.tsx +205 -0
  464. package/templates/vendor-access/web/src/styles.css +682 -0
  465. package/templates/vendor-access/web/tsconfig.json +18 -0
  466. package/templates/vendor-access/web/vite.config.ts +36 -0
  467. package/src/forge/_generated/actionSubscriptions.json +0 -2
  468. package/src/forge/_generated/actionSubscriptions.ts +0 -10
  469. package/src/forge/_generated/agentAdapterManifest.json +0 -2
  470. package/src/forge/_generated/agentAdapterManifest.ts +0 -73
  471. package/src/forge/_generated/agentContract.json +0 -2
  472. package/src/forge/_generated/agentContract.ts +0 -7829
  473. package/src/forge/_generated/agentQuickstart.md +0 -34
  474. package/src/forge/_generated/agentTools.json +0 -2
  475. package/src/forge/_generated/agentTools.md +0 -16
  476. package/src/forge/_generated/agentTools.ts +0 -12
  477. package/src/forge/_generated/aiContext.ts +0 -125
  478. package/src/forge/_generated/aiModels.json +0 -2
  479. package/src/forge/_generated/aiModels.ts +0 -51
  480. package/src/forge/_generated/aiProviders.json +0 -2
  481. package/src/forge/_generated/aiProviders.ts +0 -23
  482. package/src/forge/_generated/aiRegistry.json +0 -2
  483. package/src/forge/_generated/aiRegistry.ts +0 -31
  484. package/src/forge/_generated/api.json +0 -2
  485. package/src/forge/_generated/api.ts +0 -8
  486. package/src/forge/_generated/appGraph.json +0 -2
  487. package/src/forge/_generated/appGraph.ts +0 -14937
  488. package/src/forge/_generated/appMap.md +0 -55
  489. package/src/forge/_generated/artifactManifest.json +0 -2
  490. package/src/forge/_generated/artifactManifest.ts +0 -7
  491. package/src/forge/_generated/authClaims.json +0 -2
  492. package/src/forge/_generated/authClaims.ts +0 -13
  493. package/src/forge/_generated/authConfig.json +0 -2
  494. package/src/forge/_generated/authConfig.ts +0 -17
  495. package/src/forge/_generated/authContext.ts +0 -23
  496. package/src/forge/_generated/authRegistry.json +0 -2
  497. package/src/forge/_generated/authRegistry.ts +0 -25
  498. package/src/forge/_generated/buildInfo.json +0 -2
  499. package/src/forge/_generated/buildInfo.ts +0 -9
  500. package/src/forge/_generated/capabilityMap.json +0 -2
  501. package/src/forge/_generated/capabilityMap.md +0 -15
  502. package/src/forge/_generated/capabilityMap.ts +0 -17
  503. package/src/forge/_generated/client.ts +0 -282
  504. package/src/forge/_generated/clientApi.ts +0 -9
  505. package/src/forge/_generated/clientManifest.json +0 -2
  506. package/src/forge/_generated/clientManifest.ts +0 -39
  507. package/src/forge/_generated/clientTypes.ts +0 -78
  508. package/src/forge/_generated/configRegistry.json +0 -2
  509. package/src/forge/_generated/configRegistry.ts +0 -4
  510. package/src/forge/_generated/dataGraph.json +0 -2
  511. package/src/forge/_generated/dataGraph.ts +0 -8
  512. package/src/forge/_generated/db.json +0 -2
  513. package/src/forge/_generated/db.ts +0 -2
  514. package/src/forge/_generated/dbSecurityManifest.json +0 -2
  515. package/src/forge/_generated/dbSecurityManifest.ts +0 -15
  516. package/src/forge/_generated/dbSessionContext.json +0 -2
  517. package/src/forge/_generated/dbSessionContext.ts +0 -39
  518. package/src/forge/_generated/deployManifest.json +0 -2
  519. package/src/forge/_generated/deployManifest.ts +0 -14
  520. package/src/forge/_generated/devManifest.json +0 -2
  521. package/src/forge/_generated/devManifest.ts +0 -62
  522. package/src/forge/_generated/envSchema.json +0 -2
  523. package/src/forge/_generated/envSchema.ts +0 -59
  524. package/src/forge/_generated/frontendGraph.json +0 -2
  525. package/src/forge/_generated/frontendGraph.ts +0 -27
  526. package/src/forge/_generated/importGuards.json +0 -2
  527. package/src/forge/_generated/importGuards.ts +0 -686
  528. package/src/forge/_generated/index.ts +0 -68
  529. package/src/forge/_generated/liveProductionManifest.json +0 -2
  530. package/src/forge/_generated/liveProductionManifest.ts +0 -23
  531. package/src/forge/_generated/liveProtocol.json +0 -2
  532. package/src/forge/_generated/liveProtocol.ts +0 -21
  533. package/src/forge/_generated/liveQueryRegistry.json +0 -2
  534. package/src/forge/_generated/liveQueryRegistry.ts +0 -9
  535. package/src/forge/_generated/liveTransportConfig.json +0 -2
  536. package/src/forge/_generated/liveTransportConfig.ts +0 -19
  537. package/src/forge/_generated/makeRegistry.json +0 -2
  538. package/src/forge/_generated/makeRegistry.ts +0 -177
  539. package/src/forge/_generated/makeTemplates.json +0 -2
  540. package/src/forge/_generated/makeTemplates.ts +0 -66
  541. package/src/forge/_generated/mockMap.json +0 -2
  542. package/src/forge/_generated/mockMap.ts +0 -7
  543. package/src/forge/_generated/operationPlaybooks.md +0 -167
  544. package/src/forge/_generated/packageGraph.json +0 -2
  545. package/src/forge/_generated/packageGraph.ts +0 -249334
  546. package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
  547. package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
  548. package/src/forge/_generated/permissionMatrix.json +0 -2
  549. package/src/forge/_generated/permissionMatrix.ts +0 -7
  550. package/src/forge/_generated/policyRegistry.json +0 -2
  551. package/src/forge/_generated/policyRegistry.ts +0 -11
  552. package/src/forge/_generated/queryRegistry.json +0 -2
  553. package/src/forge/_generated/queryRegistry.ts +0 -9
  554. package/src/forge/_generated/react.d.ts +0 -22
  555. package/src/forge/_generated/react.ts +0 -29
  556. package/src/forge/_generated/reactManifest.json +0 -2
  557. package/src/forge/_generated/reactManifest.ts +0 -19
  558. package/src/forge/_generated/rlsPolicies.json +0 -2
  559. package/src/forge/_generated/rlsPolicies.sql +0 -34
  560. package/src/forge/_generated/rlsPolicies.ts +0 -6
  561. package/src/forge/_generated/runtimeGraph.json +0 -2
  562. package/src/forge/_generated/runtimeGraph.ts +0 -8
  563. package/src/forge/_generated/runtimeMatrix.json +0 -2
  564. package/src/forge/_generated/runtimeMatrix.ts +0 -334130
  565. package/src/forge/_generated/runtimeRegistry.ts +0 -2
  566. package/src/forge/_generated/runtimeRules.md +0 -91
  567. package/src/forge/_generated/secretRegistry.json +0 -2
  568. package/src/forge/_generated/secretRegistry.ts +0 -50
  569. package/src/forge/_generated/secretsContext.ts +0 -11
  570. package/src/forge/_generated/serverApi.ts +0 -10
  571. package/src/forge/_generated/sourceMapManifest.json +0 -2
  572. package/src/forge/_generated/sourceMapManifest.ts +0 -7
  573. package/src/forge/_generated/sqlPlan.json +0 -2
  574. package/src/forge/_generated/sqlPlan.ts +0 -88
  575. package/src/forge/_generated/subscriptionManifest.json +0 -2
  576. package/src/forge/_generated/subscriptionManifest.ts +0 -7
  577. package/src/forge/_generated/symbolicationManifest.json +0 -2
  578. package/src/forge/_generated/symbolicationManifest.ts +0 -17
  579. package/src/forge/_generated/telemetryRegistry.json +0 -2
  580. package/src/forge/_generated/telemetryRegistry.ts +0 -9
  581. package/src/forge/_generated/telemetrySinks.json +0 -2
  582. package/src/forge/_generated/telemetrySinks.ts +0 -11
  583. package/src/forge/_generated/tenantScope.json +0 -2
  584. package/src/forge/_generated/tenantScope.ts +0 -8
  585. package/src/forge/_generated/testGraph.json +0 -2
  586. package/src/forge/_generated/testGraph.ts +0 -3452
  587. package/src/forge/_generated/testPlanRegistry.json +0 -2
  588. package/src/forge/_generated/testPlanRegistry.ts +0 -33
  589. package/src/forge/_generated/uiRoutes.json +0 -2
  590. package/src/forge/_generated/uiRoutes.ts +0 -16
  591. package/src/forge/_generated/uiScenarios.json +0 -2
  592. package/src/forge/_generated/uiScenarios.ts +0 -30
  593. package/src/forge/_generated/uiTestManifest.json +0 -2
  594. package/src/forge/_generated/uiTestManifest.ts +0 -27
  595. package/src/forge/_generated/workflowRegistry.json +0 -2
  596. package/src/forge/_generated/workflowRegistry.ts +0 -9
  597. package/src/forge/_generated/workflowSubscriptions.json +0 -2
  598. package/src/forge/_generated/workflowSubscriptions.ts +0 -10
@@ -1,4 +1,4 @@
1
- import { join } from "node:path";
1
+ import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
2
2
  import { nodeFileSystem } from "../fs/index.ts";
3
3
  import type { ApiSurface } from "../api-surface/build.ts";
4
4
  import type { ClassifiedPackage } from "../classifier/runtime-matrix.ts";
@@ -7,6 +7,7 @@ import { detectSecrets } from "../classifier/secrets.ts";
7
7
  import { GENERATOR_VERSION } from "../emitter/constants.ts";
8
8
  import { stripDeterministicHeader } from "../primitives/header.ts";
9
9
  import { canonicalJson, normalizeNewlines, serializeCanonical } from "../primitives/serialize.ts";
10
+ import { toSnakeCase } from "../data-graph/sql/naming.ts";
10
11
  import { resolveByPackageName } from "../recipes/registry.ts";
11
12
  import {
12
13
  defaultRuntimeCompatibility,
@@ -34,18 +35,30 @@ import type { QueryRegistry } from "../types/query-registry.ts";
34
35
  import type { LiveQueryRegistry } from "../types/live-query-registry.ts";
35
36
  import type { ClientManifest } from "../client-sdk/build-manifest.ts";
36
37
  import type { FrontendGraph } from "../types/frontend-graph.ts";
38
+ import type {
39
+ ForgeExternalServiceEntry,
40
+ ForgeExternalServiceGraph,
41
+ } from "../external-manifest/types.ts";
37
42
  import { createDiagnostic } from "../diagnostics/create.ts";
43
+ import { CAIR_SCHEMA_VERSION } from "../../cair/types.ts";
38
44
  import { AUTH_ENV, DEFAULT_AUTH_CLAIMS } from "../../runtime/auth/config.ts";
45
+ import {
46
+ forgeCliCommandForWorkspace,
47
+ forgeCliCommandsForWorkspace,
48
+ shouldUseLocalForgeCli,
49
+ } from "../../workspace/forge-cli.ts";
39
50
  import type {
40
51
  AgentCapabilityMap,
41
52
  AgentCapabilityMapEntry,
42
53
  AgentContract,
43
54
  AgentDependencyApiInfo,
55
+ AgentExternalEntryInfo,
44
56
  AgentFrontendRuntimeBindingInfo,
45
57
  AgentFrontendUsageInfo,
46
58
  AgentHttpEndpointInfo,
47
59
  AgentIntegrationInfo,
48
60
  AgentRuntimeRule,
61
+ AgentProtocolInfo,
49
62
  AgentToolRegistry,
50
63
  AgentPlaybook,
51
64
  } from "./types.ts";
@@ -53,6 +66,7 @@ import type {
53
66
  const AGENTS_USER_START = "<!-- user-notes:start -->";
54
67
  const AGENTS_USER_END = "<!-- user-notes:end -->";
55
68
  const DEFAULT_USER_NOTES = "Project-specific notes can go here.";
69
+ const AGENTS_USER_NOTES_TOKEN = "__FORGE_AGENTS_USER_NOTES__";
56
70
 
57
71
  export interface AgentContractInput {
58
72
  workspaceRoot: string;
@@ -74,6 +88,7 @@ export interface AgentContractInput {
74
88
  apiSurface: ApiSurface;
75
89
  clientManifest: ClientManifest;
76
90
  frontendGraph: FrontendGraph;
91
+ externalServices?: ForgeExternalServiceGraph;
77
92
  }
78
93
 
79
94
  export interface AgentContractArtifacts {
@@ -87,6 +102,7 @@ export interface AgentContractArtifacts {
87
102
  runtimeRulesMd: string;
88
103
  operationPlaybooksMd: string;
89
104
  agentQuickstartMd: string;
105
+ agentCairGuideMd: string;
90
106
  diagnostics: Diagnostic[];
91
107
  }
92
108
 
@@ -170,17 +186,246 @@ function sourceText(workspaceRoot: string, file: string | undefined): string {
170
186
  return nodeFileSystem.readText(absolute) ?? "";
171
187
  }
172
188
 
189
+ function normalizeProjectPath(path: string): string {
190
+ return path.replace(/\\/g, "/").replace(/^\.\//, "");
191
+ }
192
+
193
+ function isWorkspaceChild(workspaceRoot: string, absolutePath: string): boolean {
194
+ const relativePath = relative(resolve(workspaceRoot), absolutePath);
195
+ return relativePath === "" || (!relativePath.startsWith("..") && !isAbsolute(relativePath));
196
+ }
197
+
198
+ function localImportSpecifiers(text: string): string[] {
199
+ const specifiers: string[] = [];
200
+ const importPattern =
201
+ /\b(?:import|export)\s+(type\s+)?(?:[^"'`]*?\s+from\s+)?["'`](\.{1,2}\/[^"'`]+)["'`]/g;
202
+ for (const match of text.matchAll(importPattern)) {
203
+ if (match[1]) {
204
+ continue;
205
+ }
206
+ const specifier = match[2] ?? "";
207
+ if (specifier) {
208
+ specifiers.push(specifier);
209
+ }
210
+ }
211
+ return uniqueSorted(specifiers);
212
+ }
213
+
214
+ function resolveLocalImport(workspaceRoot: string, fromFile: string, specifier: string): string | undefined {
215
+ const basePath = normalizeProjectPath(join(dirname(fromFile), specifier));
216
+ const candidates = extname(basePath)
217
+ ? [basePath]
218
+ : [
219
+ `${basePath}.ts`,
220
+ `${basePath}.tsx`,
221
+ `${basePath}.js`,
222
+ `${basePath}.jsx`,
223
+ `${basePath}.mjs`,
224
+ `${basePath}.cjs`,
225
+ join(basePath, "index.ts"),
226
+ join(basePath, "index.tsx"),
227
+ join(basePath, "index.js"),
228
+ ];
229
+ for (const candidate of candidates.map(normalizeProjectPath)) {
230
+ if (candidate.includes("/node_modules/") || candidate.startsWith("node_modules/")) {
231
+ continue;
232
+ }
233
+ if (candidate.startsWith("src/forge/_generated/")) {
234
+ continue;
235
+ }
236
+ const absolute = resolve(workspaceRoot, candidate);
237
+ if (!isWorkspaceChild(workspaceRoot, absolute) || !nodeFileSystem.exists(absolute)) {
238
+ continue;
239
+ }
240
+ return normalizeProjectPath(relative(resolve(workspaceRoot), absolute));
241
+ }
242
+ return undefined;
243
+ }
244
+
245
+ function sourceTextWithLocalImports(
246
+ workspaceRoot: string,
247
+ file: string | undefined,
248
+ maxDepth = 2,
249
+ ): string {
250
+ if (!file) {
251
+ return "";
252
+ }
253
+ const chunks: string[] = [];
254
+ const visited = new Set<string>();
255
+
256
+ const visit = (currentFile: string, depth: number): void => {
257
+ const normalizedFile = normalizeProjectPath(currentFile);
258
+ if (visited.has(normalizedFile)) {
259
+ return;
260
+ }
261
+ visited.add(normalizedFile);
262
+ const text = sourceText(workspaceRoot, normalizedFile);
263
+ if (!text) {
264
+ return;
265
+ }
266
+ chunks.push(text);
267
+ if (depth >= maxDepth) {
268
+ return;
269
+ }
270
+ for (const specifier of localImportSpecifiers(text)) {
271
+ const imported = resolveLocalImport(workspaceRoot, normalizedFile, specifier);
272
+ if (imported) {
273
+ visit(imported, depth + 1);
274
+ }
275
+ }
276
+ };
277
+
278
+ visit(file, 0);
279
+ return chunks.join("\n");
280
+ }
281
+
282
+ function escapeRegExp(value: string): string {
283
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
284
+ }
285
+
286
+ function toSnakeCaseName(name: string): string {
287
+ return name
288
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
289
+ .replace(/[-\s]+/g, "_")
290
+ .toLowerCase();
291
+ }
292
+
293
+ function toCamelCaseName(name: string): string {
294
+ return name.replace(/[_-]([a-zA-Z0-9])/g, (_match, char: string) => char.toUpperCase());
295
+ }
296
+
297
+ function dbTableLookup(dataGraph: AgentContractInput["dataGraph"]): Map<string, string> {
298
+ const lookup = new Map<string, string>();
299
+ for (const table of dataGraph.tables) {
300
+ lookup.set(table.name, table.name);
301
+ lookup.set(table.exportName, table.name);
302
+ lookup.set(toSnakeCaseName(table.name), table.name);
303
+ lookup.set(toSnakeCaseName(table.exportName), table.name);
304
+ lookup.set(toCamelCaseName(table.name), table.name);
305
+ lookup.set(toCamelCaseName(table.exportName), table.name);
306
+ }
307
+ return lookup;
308
+ }
309
+
310
+ function addDbAliasesForText(
311
+ text: string,
312
+ tableLookup: Map<string, string>,
313
+ aliases: Map<string, string>,
314
+ ): void {
315
+ for (const match of text.matchAll(
316
+ /\b(?:const|let|var)\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*ctx\.db(?:\.([A-Za-z_$][A-Za-z0-9_$]*)|\[\s*["'`]([^"'`]+)["'`]\s*\])/g,
317
+ )) {
318
+ const alias = match[1] ?? "";
319
+ const table = match[2] ?? match[3] ?? "";
320
+ const canonicalTable = tableLookup.get(table);
321
+ if (alias && canonicalTable) {
322
+ aliases.set(alias, canonicalTable);
323
+ }
324
+ }
325
+
326
+ for (const match of text.matchAll(/\b(?:const|let|var)\s*\{([^}]+)\}\s*=\s*ctx\.db/g)) {
327
+ const body = match[1] ?? "";
328
+ for (const part of body.split(",")) {
329
+ const [rawTable, rawAlias] = part.split(":").map((value) => value.trim());
330
+ const table = rawTable?.replace(/["'`]/g, "") ?? "";
331
+ const alias = (rawAlias ?? rawTable ?? "").replace(/\s*=.*$/, "").trim();
332
+ const canonicalTable = tableLookup.get(table);
333
+ if (canonicalTable && alias) {
334
+ aliases.set(alias, canonicalTable);
335
+ }
336
+ }
337
+ }
338
+ }
339
+
340
+ function dbHelperOpsForText(text: string): Map<string, Set<string>> {
341
+ const helpers = new Map<string, Set<string>>();
342
+ const patterns = [
343
+ /\b(?:async\s+)?function\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*(?:<[^>{}]*>)?\s*\(\s*([A-Za-z_$][A-Za-z0-9_$]*)[\s\S]*?\)\s*(?::[^{]+)?\{/g,
344
+ /\b(?:const|let|var)\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*(?:async\s*)?(?:<[^>{}]*>\s*)?\(\s*([A-Za-z_$][A-Za-z0-9_$]*)[\s\S]*?\)\s*(?::[^=]+)?=>\s*\{/g,
345
+ ];
346
+
347
+ for (const pattern of patterns) {
348
+ for (const match of text.matchAll(pattern)) {
349
+ const name = match[1] ?? "";
350
+ const tableParam = match[2] ?? "";
351
+ const start = match.index === undefined ? -1 : match.index + match[0].length;
352
+ if (!name || !tableParam || start < 0) {
353
+ continue;
354
+ }
355
+ let depth = 1;
356
+ let end = start;
357
+ for (; end < text.length; end++) {
358
+ const char = text[end];
359
+ if (char === "{") depth += 1;
360
+ if (char === "}") depth -= 1;
361
+ if (depth === 0) break;
362
+ }
363
+ const body = text.slice(start, end);
364
+ const ops = helpers.get(name) ?? new Set<string>();
365
+ const opPattern = new RegExp(`\\b${escapeRegExp(tableParam)}\\s*\\.\\s*([A-Za-z_$][A-Za-z0-9_$]*)`, "g");
366
+ for (const opMatch of body.matchAll(opPattern)) {
367
+ const op = opMatch[1] ?? "";
368
+ if (DB_READ_OPS.has(op) || DB_WRITE_OPS.has(op)) {
369
+ ops.add(op);
370
+ }
371
+ }
372
+ if (ops.size > 0) {
373
+ helpers.set(name, ops);
374
+ }
375
+ }
376
+ }
377
+
378
+ return helpers;
379
+ }
380
+
173
381
  function dbTablesForText(
174
382
  text: string,
175
- tableNames: Set<string>,
383
+ tableLookup: Map<string, string>,
176
384
  ops: Set<string>,
177
385
  ): string[] {
178
386
  const tables: string[] = [];
179
387
  for (const match of text.matchAll(/ctx\.db\.([A-Za-z_$][A-Za-z0-9_$]*)\s*\.\s*([A-Za-z_$][A-Za-z0-9_$]*)/g)) {
180
388
  const table = match[1] ?? "";
181
389
  const op = match[2] ?? "";
182
- if (tableNames.has(table) && ops.has(op)) {
183
- tables.push(table);
390
+ const canonicalTable = tableLookup.get(table);
391
+ if (canonicalTable && ops.has(op)) {
392
+ tables.push(canonicalTable);
393
+ }
394
+ }
395
+ for (const match of text.matchAll(/ctx\.db\s*\[\s*["'`]([^"'`]+)["'`]\s*\]\s*\.\s*([A-Za-z_$][A-Za-z0-9_$]*)/g)) {
396
+ const table = match[1] ?? "";
397
+ const op = match[2] ?? "";
398
+ const canonicalTable = tableLookup.get(table);
399
+ if (canonicalTable && ops.has(op)) {
400
+ tables.push(canonicalTable);
401
+ }
402
+ }
403
+ const aliases = new Map<string, string>();
404
+ addDbAliasesForText(text, tableLookup, aliases);
405
+ for (const [alias, table] of aliases) {
406
+ const aliasPattern = new RegExp(`\\b${escapeRegExp(alias)}\\s*\\.\\s*([A-Za-z_$][A-Za-z0-9_$]*)`, "g");
407
+ for (const match of text.matchAll(aliasPattern)) {
408
+ const op = match[1] ?? "";
409
+ if (ops.has(op)) {
410
+ tables.push(table);
411
+ }
412
+ }
413
+ }
414
+ const helperOps = dbHelperOpsForText(text);
415
+ for (const [helperName, helperTableOps] of helperOps) {
416
+ if (![...helperTableOps].some((op) => ops.has(op))) {
417
+ continue;
418
+ }
419
+ const helperCallPattern = new RegExp(
420
+ `\\b${escapeRegExp(helperName)}\\s*\\(\\s*ctx\\.db(?:\\.([A-Za-z_$][A-Za-z0-9_$]*)|\\[\\s*["'\`]([^"'\`]+)["'\`]\\s*\\])`,
421
+ "g",
422
+ );
423
+ for (const match of text.matchAll(helperCallPattern)) {
424
+ const table = match[1] ?? match[2] ?? "";
425
+ const canonicalTable = tableLookup.get(table);
426
+ if (canonicalTable) {
427
+ tables.push(canonicalTable);
428
+ }
184
429
  }
185
430
  }
186
431
  return uniqueSorted(tables);
@@ -189,14 +434,14 @@ function dbTablesForText(
189
434
  function dbTablesForFile(
190
435
  workspaceRoot: string,
191
436
  file: string | undefined,
192
- tableNames: Set<string>,
437
+ tableLookup: Map<string, string>,
193
438
  ops: Set<string>,
194
439
  ): string[] {
195
- return dbTablesForText(sourceText(workspaceRoot, file), tableNames, ops);
440
+ return dbTablesForText(sourceTextWithLocalImports(workspaceRoot, file), tableLookup, ops);
196
441
  }
197
442
 
198
443
  function emittedEventsForFile(workspaceRoot: string, file: string | undefined): string[] {
199
- const text = sourceText(workspaceRoot, file);
444
+ const text = sourceTextWithLocalImports(workspaceRoot, file);
200
445
  return uniqueSorted(
201
446
  [...text.matchAll(/ctx\.emit\s*\(\s*["'`]([^"'`]+)["'`]/g)]
202
447
  .map((match) => match[1] ?? ""),
@@ -248,7 +493,7 @@ function runtimeRules(): AgentRuntimeRule[] {
248
493
  {
249
494
  context: "command",
250
495
  allowed: ["ctx.db writes", "ctx.emit", "ctx.telemetry buffered events"],
251
- forbidden: ["network packages", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "process.env", "filesystem access"],
496
+ forbidden: ["network packages", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "direct secret/env access", "filesystem access"],
252
497
  },
253
498
  {
254
499
  context: "query",
@@ -273,6 +518,104 @@ function runtimeRules(): AgentRuntimeRule[] {
273
518
  ];
274
519
  }
275
520
 
521
+ type TenantTableInfo = {
522
+ tenantIdColumn: string;
523
+ tenantField: string;
524
+ };
525
+
526
+ function buildTenantTableLookup(tenantScope: TenantScope, dataGraph: DataGraph): Map<string, TenantTableInfo> {
527
+ const lookup = new Map<string, TenantTableInfo>();
528
+ for (const scoped of tenantScope.tables) {
529
+ const table = dataGraph.tables.find((candidate) =>
530
+ candidate.name === scoped.table ||
531
+ candidate.exportName === scoped.exportName ||
532
+ toSnakeCase(candidate.name) === scoped.table ||
533
+ toSnakeCase(candidate.exportName) === scoped.table
534
+ );
535
+ const tenantField = table?.fields.find((field) => toSnakeCase(field.name) === scoped.tenantIdColumn)?.name ??
536
+ scoped.tenantIdColumn;
537
+ const info = { tenantIdColumn: scoped.tenantIdColumn, tenantField };
538
+ for (const key of uniqueSorted([
539
+ scoped.table,
540
+ scoped.exportName,
541
+ table?.name,
542
+ table?.exportName,
543
+ ].filter((key): key is string => typeof key === "string" && key.length > 0))) {
544
+ lookup.set(key, info);
545
+ }
546
+ }
547
+ return lookup;
548
+ }
549
+
550
+ function agentProtocols(workspaceRoot: string): AgentProtocolInfo[] {
551
+ return [
552
+ {
553
+ id: "cair",
554
+ kind: "agent-protocol",
555
+ version: CAIR_SCHEMA_VERSION,
556
+ guide: "src/forge/_generated/agentCairGuide.md",
557
+ commands: forgeCliCommandsForWorkspace(workspaceRoot, [
558
+ "forge cair snapshot",
559
+ "forge cair query \"Q ST\"",
560
+ "forge cair query \"Q S name=<symbol>\"",
561
+ "forge cair query \"Q D S#1\"",
562
+ "forge cair query \"Q R S#1\"",
563
+ "forge cair query \"Q I S#1\"",
564
+ "forge cair action --plan \"A RN t=S#1 nn=<newName>\"",
565
+ "forge cair action \"A APPLY plan=<P#|path>\"",
566
+ "forge cair action \"A ROLLBACK journal=<path>\"",
567
+ ]),
568
+ preferredFor: [
569
+ "compact repository orientation",
570
+ "symbol lookup before file reads",
571
+ "semantic code edits",
572
+ "guarded refactors",
573
+ "Forge-native feature creation",
574
+ "impact-aware test selection",
575
+ "token-efficient programming",
576
+ ],
577
+ readQueries: [
578
+ "Q ST",
579
+ "Q S name=<symbol>",
580
+ "Q D S#1",
581
+ "Q R S#1",
582
+ "Q I S#1",
583
+ "Q T S#1",
584
+ "Q DEP.API package=<pkg> symbol=<export>",
585
+ ],
586
+ mutationActions: [
587
+ "A RN t=S#1 nn=<newName>",
588
+ "A MV t=S#1 to=<path>",
589
+ "A OI f=M#1",
590
+ "A FMT f=M#1",
591
+ "A MC n=<command>",
592
+ "A MQ n=<query>",
593
+ "A MA n=<action>",
594
+ "A MT n=<table> fields=<fields>",
595
+ "A AT t=S#1 kind=unit",
596
+ "A WX t=S#1 file=src/index.ts",
597
+ "A APPLY plan=<P#|path>",
598
+ "A ROLLBACK journal=<path>",
599
+ ],
600
+ compactAliases: [
601
+ "Q ST=Q STATUS",
602
+ "Q S=Q SYMBOL",
603
+ "Q D=Q DEF",
604
+ "Q R=Q REFS",
605
+ "Q I=Q IMPACT",
606
+ "A RN=A RENAME.SYMBOL",
607
+ "A MV=A MOVE.SYMBOL",
608
+ "A OI=A ORGANIZE.IMPORTS",
609
+ "A FMT=A FORMAT",
610
+ "A MC=A MAKE.COMMAND",
611
+ "A MT=A MAKE.TABLE",
612
+ "A AT=A ADD.TEST",
613
+ "A WX=A WIRE.EXPORT",
614
+ ],
615
+ },
616
+ ];
617
+ }
618
+
276
619
  function playbooks(): AgentPlaybook[] {
277
620
  return [
278
621
  {
@@ -341,7 +684,7 @@ function playbooks(): AgentPlaybook[] {
341
684
  "Prefer AI SDK ToolLoopAgent semantics through ctx.agent.run or ctx.ai.runAgent instead of custom loops.",
342
685
  "Use stopWhen with stepCount or terminal tool calls to prevent unbounded loops.",
343
686
  "Run agents only in actions, workflows, endpoints, or server code.",
344
- "Run forge inspect all --json and confirm agentContract.ai.agents lists the agent.",
687
+ "Run forge inspect ai --json or forge agent print-context --json and confirm the generated context lists the agent.",
345
688
  "Use forge ai trace <traceId> --json to inspect agent runs and tool calls.",
346
689
  ],
347
690
  },
@@ -358,7 +701,7 @@ function playbooks(): AgentPlaybook[] {
358
701
  {
359
702
  title: "Scaffold a resource",
360
703
  steps: [
361
- "Run forge make resource <name> --fields name:type,status:enum(open,closed) --dry-run --json.",
704
+ "Run forge make resource <name> --fields name:type,status:enum=open+closed --dry-run --json.",
362
705
  "Review the plan and diagnostics.",
363
706
  "Run forge make resource <name> --fields name:type --with-ui --yes when the resource should be visible in the web app.",
364
707
  "Run forge generate.",
@@ -447,17 +790,17 @@ function playbooks(): AgentPlaybook[] {
447
790
  "Run forge dev --once --json for a one-shot diagnostic cycle.",
448
791
  "Use --api-only, --web-only, --no-watch, or --no-worker only when narrowing the loop intentionally.",
449
792
  "When a web app exists, forge dev starts the API runtime and the web dev server together and prints both URLs.",
450
- "Use generated client and React hooks through web/lib/forge.ts.",
793
+ "Use generated client bindings through web/lib/forge.ts, web/src/lib/forge.ts, or Nuxt web/composables/forge.ts.",
451
794
  ],
452
795
  },
453
796
  {
454
797
  title: "Add or update frontend",
455
798
  steps: [
456
- "Run forge make ui --framework vite --dry-run --json when the app does not have a web root.",
799
+ "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.",
457
800
  "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.",
458
- "Use web/lib/forge.ts as the generated client bridge.",
459
- "Mount ForgeProvider once in the web app provider/layout layer; use devAuth for local development.",
460
- "Use useQuery, useCommand, and useLiveQuery instead of raw /commands or /queries fetches.",
801
+ "Use web/lib/forge.ts, web/src/lib/forge.ts, or web/composables/forge.ts as the generated client bridge.",
802
+ "Mount ForgeProvider or install the Nuxt Forge plugin once in the web app provider/layout layer; use devAuth for local development.",
803
+ "Use useQuery/useCommand/useLiveQuery or useForgeQuery/useForgeCommand/useForgeLiveQuery instead of raw /commands or /queries fetches.",
461
804
  "Run forge generate so frontendGraph and agentContract include routes and bindings.",
462
805
  "Run forge inspect capabilities --json to confirm UI actions map to runtime capabilities.",
463
806
  "Run forge dev --once --json and forge doctor --json.",
@@ -536,7 +879,11 @@ function runtimeEntriesWithoutFrontend(contract: AgentContract): AgentCapability
536
879
  emits: commandEntry.emits,
537
880
  dependencies: [],
538
881
  },
539
- notes: ["Runtime entry is available to agents even though no frontend usage was detected."],
882
+ notes: [
883
+ commandEntry.source === "external"
884
+ ? "External runtime entry is imported from a Forge manifest; execution requires an external runtime bridge."
885
+ : "Runtime entry is available to agents even though no frontend usage was detected.",
886
+ ],
540
887
  });
541
888
  }
542
889
  }
@@ -557,7 +904,11 @@ function runtimeEntriesWithoutFrontend(contract: AgentContract): AgentCapability
557
904
  emits: [],
558
905
  dependencies: [],
559
906
  },
560
- notes: ["Runtime entry is available to agents even though no frontend usage was detected."],
907
+ notes: [
908
+ queryEntry.source === "external"
909
+ ? "External runtime entry is imported from a Forge manifest; execution requires an external runtime bridge."
910
+ : "Runtime entry is available to agents even though no frontend usage was detected.",
911
+ ],
561
912
  });
562
913
  }
563
914
  }
@@ -703,9 +1054,15 @@ function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
703
1054
  dependencies: [],
704
1055
  readOnly: false,
705
1056
  risk: "write" as const,
706
- needsApproval: true,
1057
+ needsApproval: command.source === "external"
1058
+ ? command.external?.needsApproval ?? (command.external?.risk !== "read")
1059
+ : true,
707
1060
  requiresAuth: command.policy !== undefined && command.policy !== "public",
708
- execution: "forge-runtime-endpoint" as const,
1061
+ ...(command.source ? { source: command.source } : {}),
1062
+ ...(command.external ? { external: command.external } : {}),
1063
+ execution: command.source === "external"
1064
+ ? "external-runtime-endpoint" as const
1065
+ : "forge-runtime-endpoint" as const,
709
1066
  })),
710
1067
  ...contract.queries.map((query) => ({
711
1068
  name: autoToolName("query", query.name),
@@ -723,7 +1080,11 @@ function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
723
1080
  risk: "read" as const,
724
1081
  needsApproval: false,
725
1082
  requiresAuth: query.policy !== undefined && query.policy !== "public",
726
- execution: "forge-runtime-endpoint" as const,
1083
+ ...(query.source ? { source: query.source } : {}),
1084
+ ...(query.external ? { external: query.external } : {}),
1085
+ execution: query.source === "external"
1086
+ ? "external-runtime-endpoint" as const
1087
+ : "forge-runtime-endpoint" as const,
727
1088
  })),
728
1089
  ...contract.liveQueries.map((liveQuery) => ({
729
1090
  name: autoToolName("liveQuery", liveQuery.name),
@@ -741,6 +1102,7 @@ function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
741
1102
  risk: "read" as const,
742
1103
  needsApproval: false,
743
1104
  requiresAuth: liveQuery.policy !== undefined && liveQuery.policy !== "public",
1105
+ source: "local" as const,
744
1106
  execution: "forge-runtime-endpoint" as const,
745
1107
  })),
746
1108
  ].sort((a, b) => a.name.localeCompare(b.name));
@@ -794,6 +1156,39 @@ function httpEndpointFor(
794
1156
  };
795
1157
  }
796
1158
 
1159
+ function externalEndpointFor(entry: ForgeExternalServiceEntry): AgentHttpEndpointInfo {
1160
+ const encodedService = encodeURIComponent(entry.service);
1161
+ const encodedName = encodeURIComponent(entry.name);
1162
+ const collection = entry.kind === "query" ? "queries" : "commands";
1163
+ return {
1164
+ method: entry.method ?? "POST",
1165
+ path: entry.path ?? `/external/${encodedService}/${collection}/${encodedName}`,
1166
+ exampleBody: { args: {} },
1167
+ };
1168
+ }
1169
+
1170
+ function externalEntryInfo(entry: ForgeExternalServiceEntry): AgentExternalEntryInfo {
1171
+ return {
1172
+ service: entry.service,
1173
+ language: entry.language,
1174
+ ...(entry.framework ? { framework: entry.framework } : {}),
1175
+ transport: entry.transport,
1176
+ ...(entry.transaction ? { transaction: entry.transaction } : {}),
1177
+ ...(entry.risk ? { risk: entry.risk } : {}),
1178
+ ...(typeof entry.needsApproval === "boolean" ? { needsApproval: entry.needsApproval } : {}),
1179
+ effects: entry.effects ?? [],
1180
+ ...(entry.description ? { description: entry.description } : {}),
1181
+ };
1182
+ }
1183
+
1184
+ function externalFrontendUsage(entry: ForgeExternalServiceEntry): AgentFrontendUsageInfo {
1185
+ return {
1186
+ hook: `external manifest '${entry.service}.${entry.name}'; runtime bridge required before client invocation`,
1187
+ routes: [],
1188
+ components: [],
1189
+ };
1190
+ }
1191
+
797
1192
  function frontendUsageFor(
798
1193
  frontendGraph: FrontendGraph,
799
1194
  kind: "command" | "query" | "liveQuery" | "action",
@@ -901,9 +1296,7 @@ export function buildAgentContractArtifacts(
901
1296
  input: AgentContractInput,
902
1297
  ): AgentContractArtifacts {
903
1298
  const project = readPackageInfo(input.workspaceRoot);
904
- const tenantTables = new Map(
905
- input.tenantScope.tables.map((table) => [table.table, table.tenantIdColumn]),
906
- );
1299
+ const tenantTables = buildTenantTableLookup(input.tenantScope, input.dataGraph);
907
1300
  const commandAuth = new Map(
908
1301
  input.policyRegistry.commandAuth.map((binding) => [binding.commandName, binding.auth]),
909
1302
  );
@@ -915,16 +1308,18 @@ export function buildAgentContractArtifacts(
915
1308
  );
916
1309
 
917
1310
  const runtimeEntries = new Map(input.runtimeGraph.entries.map((entry) => [entry.name, entry]));
918
- const tableNames = new Set(input.dataGraph.tables.map((table) => table.name));
919
- const commandInfos: AgentContract["commands"] = sorted(Object.keys(input.apiSurface.commands), (name) => name).map((name) => {
1311
+ const tableLookup = dbTableLookup(input.dataGraph);
1312
+ const externalEntries = input.externalServices?.services.flatMap((service) => service.entries) ?? [];
1313
+ const localCommandInfos: AgentContract["commands"] = sorted(Object.keys(input.apiSurface.commands), (name) => name).map((name) => {
920
1314
  const entry = runtimeEntries.get(name);
921
1315
  const file = entry?.file ?? "";
922
1316
  return {
923
1317
  name,
924
1318
  file,
1319
+ source: "local" as const,
925
1320
  policy: authPolicy(commandAuth.get(name)),
926
- tablesRead: dbTablesForFile(input.workspaceRoot, file, tableNames, DB_READ_OPS),
927
- tablesWritten: dbTablesForFile(input.workspaceRoot, file, tableNames, DB_WRITE_OPS),
1321
+ tablesRead: dbTablesForFile(input.workspaceRoot, file, tableLookup, DB_READ_OPS),
1322
+ tablesWritten: dbTablesForFile(input.workspaceRoot, file, tableLookup, DB_WRITE_OPS),
928
1323
  emits: emittedEventsForFile(input.workspaceRoot, file),
929
1324
  allowedPackages: entry ? packageNamesForModule(input.appGraph, entry.moduleId) : [],
930
1325
  forbiddenCapabilities: forbiddenForContext(input.classified, "command"),
@@ -932,21 +1327,62 @@ export function buildAgentContractArtifacts(
932
1327
  frontend: frontendUsageFor(input.frontendGraph, "command", name),
933
1328
  };
934
1329
  });
935
- const queryInfos: AgentContract["queries"] = sorted(input.queryRegistry.queries, (query) => query.name).map((query) => ({
1330
+ const externalCommandInfos: AgentContract["commands"] = externalEntries
1331
+ .filter((entry) => entry.kind === "command")
1332
+ .map((entry) => ({
1333
+ name: `${entry.service}.${entry.name}`,
1334
+ file: `external:${entry.service}`,
1335
+ source: "external" as const,
1336
+ external: externalEntryInfo(entry),
1337
+ ...(entry.policy ? { policy: entry.policy } : {}),
1338
+ tablesRead: [],
1339
+ tablesWritten: entry.transaction === "read-only" ? [] : [`external:${entry.service}`],
1340
+ emits: entry.effects ?? [],
1341
+ allowedPackages: [],
1342
+ forbiddenCapabilities: [],
1343
+ http: externalEndpointFor(entry),
1344
+ frontend: externalFrontendUsage(entry),
1345
+ }));
1346
+ const commandInfos: AgentContract["commands"] = sorted(
1347
+ [...localCommandInfos, ...externalCommandInfos],
1348
+ (command) => command.name,
1349
+ );
1350
+ const localQueryInfos: AgentContract["queries"] = sorted(input.queryRegistry.queries, (query) => query.name).map((query) => ({
936
1351
  name: query.name,
937
1352
  file: query.file,
1353
+ source: "local" as const,
938
1354
  policy: authPolicy(queryAuth.get(query.name)),
939
1355
  readOnly: true,
940
1356
  tenantScoped: input.tenantScope.tables.length > 0,
941
- tablesRead: dbTablesForFile(input.workspaceRoot, query.file, tableNames, DB_READ_OPS),
1357
+ tablesRead: dbTablesForFile(input.workspaceRoot, query.file, tableLookup, DB_READ_OPS),
942
1358
  allowedPackages: packageNamesForModule(input.appGraph, query.moduleId),
943
1359
  forbiddenCapabilities: forbiddenForContext(input.classified, "query"),
944
1360
  http: httpEndpointFor("query", query.name),
945
1361
  frontend: frontendUsageFor(input.frontendGraph, "query", query.name),
946
1362
  }));
1363
+ const externalQueryInfos: AgentContract["queries"] = externalEntries
1364
+ .filter((entry) => entry.kind === "query")
1365
+ .map((entry) => ({
1366
+ name: `${entry.service}.${entry.name}`,
1367
+ file: `external:${entry.service}`,
1368
+ source: "external" as const,
1369
+ external: externalEntryInfo(entry),
1370
+ ...(entry.policy ? { policy: entry.policy } : {}),
1371
+ readOnly: true as const,
1372
+ tenantScoped: entry.tenantScoped ?? false,
1373
+ tablesRead: [`external:${entry.service}`],
1374
+ allowedPackages: [],
1375
+ forbiddenCapabilities: [],
1376
+ http: externalEndpointFor(entry),
1377
+ frontend: externalFrontendUsage(entry),
1378
+ }));
1379
+ const queryInfos: AgentContract["queries"] = sorted(
1380
+ [...localQueryInfos, ...externalQueryInfos],
1381
+ (query) => query.name,
1382
+ );
947
1383
  const liveQueryInfos: AgentContract["liveQueries"] = sorted(input.liveQueryRegistry.liveQueries, (liveQuery) => liveQuery.name).map(
948
1384
  (liveQuery) => {
949
- const tablesRead = dbTablesForFile(input.workspaceRoot, liveQuery.file, tableNames, DB_READ_OPS);
1385
+ const tablesRead = dbTablesForFile(input.workspaceRoot, liveQuery.file, tableLookup, DB_READ_OPS);
950
1386
  return {
951
1387
  name: liveQuery.name,
952
1388
  file: liveQuery.file,
@@ -968,6 +1404,7 @@ export function buildAgentContractArtifacts(
968
1404
  queries: queryInfos,
969
1405
  liveQueries: liveQueryInfos,
970
1406
  });
1407
+ const protocols = agentProtocols(input.workspaceRoot);
971
1408
  const contract: AgentContract = {
972
1409
  schemaVersion: "0.1.0",
973
1410
  generatorVersion: GENERATOR_VERSION,
@@ -1003,18 +1440,22 @@ export function buildAgentContractArtifacts(
1003
1440
  }),
1004
1441
  ),
1005
1442
  data: {
1006
- tables: sorted(input.dataGraph.tables, (table) => table.name).map((table) => ({
1007
- name: table.name,
1008
- file: table.file,
1009
- tenantScoped: tenantTables.has(table.name),
1010
- ...(tenantTables.has(table.name) ? { tenantField: tenantTables.get(table.name) } : {}),
1011
- fields: uniqueSorted(table.fields.map((field) => field.name)),
1012
- })),
1443
+ tables: sorted(input.dataGraph.tables, (table) => table.name).map((table) => {
1444
+ const tenantInfo = tenantTables.get(table.name);
1445
+ return {
1446
+ name: table.name,
1447
+ file: table.file,
1448
+ tenantScoped: Boolean(tenantInfo),
1449
+ ...(tenantInfo ? { tenantField: tenantInfo.tenantField } : {}),
1450
+ fields: uniqueSorted(table.fields.map((field) => field.name)),
1451
+ };
1452
+ }),
1013
1453
  },
1014
1454
  policies: sorted(input.policyRegistry.policies, (policy) => policy.name).map((policy) => ({
1015
1455
  name: policy.name,
1016
1456
  kind: policy.kind,
1017
1457
  roles: uniqueSorted(policy.roles),
1458
+ permissions: uniqueSorted(policy.permissions ?? []),
1018
1459
  file: policy.file,
1019
1460
  })),
1020
1461
  packages: sorted(input.packageGraph.packages, (pkg) => pkg.name).map((pkg) => {
@@ -1028,6 +1469,19 @@ export function buildAgentContractArtifacts(
1028
1469
  }),
1029
1470
  dependencyApis: buildDependencyApis(input.packageGraph),
1030
1471
  integrations: buildIntegrations(input.classified),
1472
+ externalServices: (input.externalServices?.services ?? []).map((service) => ({
1473
+ name: service.name,
1474
+ language: service.language,
1475
+ ...(service.framework ? { framework: service.framework } : {}),
1476
+ transport: service.transport,
1477
+ ...(service.baseUrl ? { baseUrl: service.baseUrl } : {}),
1478
+ ...(service.command ? { command: service.command } : {}),
1479
+ ...(service.health ? { health: service.health } : {}),
1480
+ commands: sorted(service.entries.filter((entry) => entry.kind === "command"), (entry) => entry.name)
1481
+ .map((entry) => `${service.name}.${entry.name}`),
1482
+ queries: sorted(service.entries.filter((entry) => entry.kind === "query"), (entry) => entry.name)
1483
+ .map((entry) => `${service.name}.${entry.name}`),
1484
+ })),
1031
1485
  secrets: sorted(input.secretRegistry.secrets, (secret) => secret.name).map((secret) => ({
1032
1486
  name: secret.name,
1033
1487
  integration: secret.integration,
@@ -1141,10 +1595,11 @@ export function buildAgentContractArtifacts(
1141
1595
  },
1142
1596
  rules: runtimeRules(),
1143
1597
  playbooks: playbooks(),
1598
+ agentProtocols: protocols,
1144
1599
  commandsToRun: {
1145
- beforeEditing: ["forge do inspect --json", "forge dev --once --json", "forge inspect all --json", "forge check --json"],
1146
- afterEditing: ["forge generate", "forge check", "forge verify --standard", "forge verify --strict"],
1147
- dev: ["forge dev", "forge dev --once --json", "forge do fix --json", "forge do verify --json", "forge dev --api-only", "forge dev --web-only"],
1600
+ 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"]),
1601
+ afterEditing: forgeCliCommandsForWorkspace(input.workspaceRoot, ["forge generate", "forge check", "forge verify --standard", finalVerifyCommand(input.workspaceRoot)]),
1602
+ 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"]),
1148
1603
  },
1149
1604
  };
1150
1605
 
@@ -1153,7 +1608,7 @@ export function buildAgentContractArtifacts(
1153
1608
  ? (nodeFileSystem.readText(existingAgentsPath) ?? "")
1154
1609
  : null;
1155
1610
  const userNotes = extractUserNotes(existingAgents);
1156
- const agentsMd = renderAgentsMd(contract, userNotes);
1611
+ const agentsMd = renderAgentsMd(contract, userNotes, input.workspaceRoot);
1157
1612
  const toolRegistry = buildAgentToolRegistry(contract);
1158
1613
  const capabilityMap = buildCapabilityMap(contract);
1159
1614
  const capabilityMapMd = renderCapabilityMapMd(capabilityMap);
@@ -1161,7 +1616,8 @@ export function buildAgentContractArtifacts(
1161
1616
  const appMapMd = renderAppMapMd(contract);
1162
1617
  const runtimeRulesMd = renderRuntimeRulesMd(contract.rules);
1163
1618
  const operationPlaybooksMd = renderOperationPlaybooksMd(contract.playbooks);
1164
- const agentQuickstartMd = renderAgentQuickstartMd();
1619
+ const agentQuickstartMd = renderAgentQuickstartMd(input.workspaceRoot);
1620
+ const agentCairGuideMd = renderAgentCairGuideMd(contract, input.workspaceRoot);
1165
1621
  const diagnostics = scanAgentContractForLeaks(contract, [
1166
1622
  agentsMd,
1167
1623
  agentToolsMd,
@@ -1170,6 +1626,7 @@ export function buildAgentContractArtifacts(
1170
1626
  runtimeRulesMd,
1171
1627
  operationPlaybooksMd,
1172
1628
  agentQuickstartMd,
1629
+ agentCairGuideMd,
1173
1630
  ]);
1174
1631
 
1175
1632
  return {
@@ -1183,6 +1640,7 @@ export function buildAgentContractArtifacts(
1183
1640
  runtimeRulesMd,
1184
1641
  operationPlaybooksMd,
1185
1642
  agentQuickstartMd,
1643
+ agentCairGuideMd,
1186
1644
  diagnostics: [...diagnostics, ...capabilityMap.diagnostics],
1187
1645
  };
1188
1646
  }
@@ -1229,7 +1687,22 @@ export function serializeAgentToolRegistryTs(registry: AgentToolRegistry): strin
1229
1687
  return `export const agentTools = ${JSON.stringify(parsed, null, 2)} as const;\n`;
1230
1688
  }
1231
1689
 
1232
- function renderAgentsMd(contract: AgentContract, userNotes: string): string {
1690
+ function localizeForgeCliMarkdown(workspaceRoot: string, markdown: string): string {
1691
+ return shouldUseLocalForgeCli(workspaceRoot)
1692
+ ? markdown.replace(/\bforge (?=[a-z])/g, "node bin/forge.mjs ")
1693
+ : markdown;
1694
+ }
1695
+
1696
+ function finalVerifyCommand(workspaceRoot: string): string {
1697
+ const command = shouldUseLocalForgeCli(workspaceRoot) ? "forge verify framework" : "forge verify --strict";
1698
+ return forgeCliCommandForWorkspace(workspaceRoot, command);
1699
+ }
1700
+
1701
+ function renderAgentsMd(contract: AgentContract, userNotes: string, workspaceRoot: string): string {
1702
+ const finalVerify = finalVerifyCommand(workspaceRoot);
1703
+ const cliEntrypoint = shouldUseLocalForgeCli(workspaceRoot)
1704
+ ? "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."
1705
+ : "Use the installed `forge` command for app workflows.";
1233
1706
  const tenantTables = contract.data.tables
1234
1707
  .filter((table) => table.tenantScoped)
1235
1708
  .map((table) => `${table.name} via ${table.tenantField}`);
@@ -1244,7 +1717,7 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
1244
1717
  `${agent.name}: ${agent.provider}/${agent.model} with ${agent.tools.length > 0 ? agent.tools.join(", ") : "no tools"}`,
1245
1718
  );
1246
1719
 
1247
- return normalizeNewlines(`# AGENTS.md
1720
+ const generated = localizeForgeCliMarkdown(workspaceRoot, `# AGENTS.md
1248
1721
 
1249
1722
  <!-- forge-generated:start -->
1250
1723
 
@@ -1252,23 +1725,51 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
1252
1725
 
1253
1726
  This is a ForgeOS application named \`${contract.project.name}\`.
1254
1727
 
1728
+ ## CLI entrypoint
1729
+
1730
+ ${cliEntrypoint}
1731
+
1255
1732
  ## Required workflow
1256
1733
 
1257
1734
  Before editing:
1258
1735
 
1259
1736
  \`\`\`bash
1737
+ forge agent onboard --target codex --json
1738
+ forge status --json
1739
+ forge changed --json
1740
+ forge handoff --json
1260
1741
  forge do inspect --json
1261
1742
  forge dev --once --json
1262
- forge inspect all --json
1743
+ forge agent print-context --json
1263
1744
  forge check --json
1264
1745
  \`\`\`
1265
1746
 
1747
+ ## CAIR first
1748
+
1749
+ Before reading large files or hand-writing patches, prefer the generated CAIR guide:
1750
+
1751
+ \`\`\`bash
1752
+ forge cair snapshot
1753
+ forge cair query "Q ST"
1754
+ forge cair query "Q S name=<symbol>"
1755
+ forge cair query "Q D S#1"
1756
+ forge cair query "Q R S#1"
1757
+ forge cair query "Q I S#1"
1758
+ \`\`\`
1759
+
1760
+ Use \`src/forge/_generated/agentCairGuide.md\` for the full compact protocol. Plan CAIR mutations before applying them:
1761
+
1762
+ \`\`\`bash
1763
+ forge cair action --plan "A RN t=S#1 nn=<newName>"
1764
+ forge cair action "A APPLY plan=<returned-plan-path>"
1765
+ \`\`\`
1766
+
1266
1767
  After editing:
1267
1768
 
1268
1769
  \`\`\`bash
1269
1770
  forge generate
1270
1771
  forge check
1271
- forge verify --strict
1772
+ ${finalVerify}
1272
1773
  \`\`\`
1273
1774
 
1274
1775
  ## Do not edit
@@ -1296,7 +1797,7 @@ Template apps may ignore \`src/forge/_generated/**\` and \`forge.lock\` in git t
1296
1797
  ## Runtime rules
1297
1798
 
1298
1799
  - Do not import network packages inside \`command\`, \`query\`, or \`liveQuery\`.
1299
- - Do not use \`process.env\` directly.
1800
+ - 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.
1300
1801
  - Do not access cross-tenant data.
1301
1802
  - Commands must use \`ctx.emit\` for side effects.
1302
1803
  - Actions and workflows handle side effects after commit.
@@ -1310,8 +1811,10 @@ forge do fix --json
1310
1811
  forge do verify --json
1311
1812
  forge dev --once --json
1312
1813
  forge dev
1814
+ forge handoff --json
1313
1815
  forge inspect app --json
1314
1816
  forge inspect all --json
1817
+ forge inspect all --full --json
1315
1818
  forge inspect frontend --json
1316
1819
  forge inspect capabilities --json
1317
1820
  forge inspect agent-tools --json
@@ -1328,12 +1831,13 @@ forge doctor
1328
1831
  forge doctor windows --json
1329
1832
  forge setup windows --json
1330
1833
  forge agent print-context --json
1834
+ forge agent doctor --target codex --json
1331
1835
  forge ai tools --json
1332
1836
  forge ai agents --json
1333
1837
  forge ai trace <traceId> --json
1334
1838
  forge verify --smoke
1335
1839
  forge verify --standard
1336
- forge verify --strict
1840
+ ${finalVerify}
1337
1841
  \`\`\`
1338
1842
 
1339
1843
  ## Data
@@ -1388,9 +1892,9 @@ ${contract.frontend.dev ? `- Web URL: ${contract.frontend.dev.url}
1388
1892
 
1389
1893
  Rules:
1390
1894
 
1391
- - Use the local \`web/**/lib/forge.ts\` bridge to generated hooks.
1392
- - Mount \`<ForgeProvider devAuth>\` in local development.
1393
- - Use \`useQuery\`, \`useCommand\`, and \`useLiveQuery\` instead of raw Forge endpoint fetches in React components.
1895
+ - Use the local \`web/**/lib/forge.ts\` or Nuxt \`web/composables/forge.ts\` bridge to generated bindings.
1896
+ - Mount \`<ForgeProvider devAuth>\` or install the Nuxt Forge plugin in local development.
1897
+ - Use \`useQuery\`/\`useCommand\`/\`useLiveQuery\` or \`useForgeQuery\`/\`useForgeCommand\`/\`useForgeLiveQuery\` instead of raw Forge endpoint fetches in components.
1394
1898
  - Keep frontend routes reflected in \`src/forge/_generated/frontendGraph.json\`.
1395
1899
 
1396
1900
  ## Common tasks
@@ -1413,16 +1917,17 @@ forge do verify --json
1413
1917
  1. Add file in \`src/commands\`.
1414
1918
  2. Declare \`auth: can("...")\`.
1415
1919
  3. Run \`forge generate\`.
1416
- 4. Run \`forge verify --strict\`.
1920
+ 4. Run \`${finalVerify}\`.
1417
1921
 
1418
1922
  ### Scaffold a resource
1419
1923
 
1420
1924
  Use:
1421
1925
 
1422
1926
  \`\`\`bash
1423
- forge make resource <name> --fields title:text,status:enum(open,closed) --dry-run --json
1424
- forge make resource <name> --fields title:text,status:enum(open,closed) --with-ui --yes
1927
+ forge make resource <name> --fields title:text,status:enum=open+closed --dry-run --json
1928
+ forge make resource <name> --fields title:text,status:enum=open+closed --with-ui --yes
1425
1929
  forge make ui --framework vite --dry-run --json
1930
+ forge make ui --framework nuxt --dry-run --json
1426
1931
  forge make ai-chat support --dry-run --json
1427
1932
  \`\`\`
1428
1933
 
@@ -1439,7 +1944,7 @@ forge inspect frontend --json
1439
1944
  forge inspect capabilities --json
1440
1945
  \`\`\`
1441
1946
 
1442
- \`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.
1947
+ \`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.
1443
1948
 
1444
1949
  ### Apply a feature blueprint
1445
1950
 
@@ -1479,7 +1984,7 @@ forge test run --changed --timeout-ms 120000 --json
1479
1984
  forge verify --standard
1480
1985
  \`\`\`
1481
1986
 
1482
- Use \`forge verify --standard\` for the normal agent development loop. Finish handoffs with \`forge verify --strict\` when the change is ready.
1987
+ Use \`forge verify --standard\` for the normal agent development loop. Finish handoffs with \`${finalVerify}\` when the change is ready.
1483
1988
 
1484
1989
  ### Repair a failing check
1485
1990
 
@@ -1498,7 +2003,8 @@ Use:
1498
2003
 
1499
2004
  \`\`\`bash
1500
2005
  forge generate
1501
- forge inspect all --json
2006
+ forge inspect ai --json
2007
+ forge agent print-context --json
1502
2008
  forge ai check --json
1503
2009
  forge ai trace <traceId> --json
1504
2010
  \`\`\`
@@ -1537,7 +2043,7 @@ forge deps upgrade-plan <package> --to latest
1537
2043
  forge deps inspect <package> --json
1538
2044
  forge deps api <package> <symbol> --json
1539
2045
  forge deps upgrade-apply <plan>
1540
- forge verify --strict
2046
+ ${finalVerify}
1541
2047
  \`\`\`
1542
2048
 
1543
2049
  Do not manually edit \`package.json\` for package upgrades unless necessary.
@@ -1558,10 +2064,11 @@ Durable invalidations live in \`_forge_live_invalidations\`.
1558
2064
 
1559
2065
  ${AGENTS_USER_START}
1560
2066
 
1561
- ${userNotes}
2067
+ ${AGENTS_USER_NOTES_TOKEN}
1562
2068
 
1563
2069
  ${AGENTS_USER_END}
1564
2070
  `);
2071
+ return normalizeNewlines(generated.replace(AGENTS_USER_NOTES_TOKEN, () => userNotes));
1565
2072
  }
1566
2073
 
1567
2074
  function renderAppMapMd(contract: AgentContract): string {
@@ -1922,21 +2429,27 @@ function renderOperationPlaybooksMd(playbookEntries: AgentPlaybook[]): string {
1922
2429
  return normalizeNewlines(lines.join("\n"));
1923
2430
  }
1924
2431
 
1925
- function renderAgentQuickstartMd(): string {
1926
- return normalizeNewlines(`# Agent Quickstart
2432
+ function renderAgentQuickstartMd(workspaceRoot: string): string {
2433
+ const finalVerify = finalVerifyCommand(workspaceRoot);
2434
+ return normalizeNewlines(localizeForgeCliMarkdown(workspaceRoot, `# Agent Quickstart
1927
2435
 
1928
2436
  Run:
1929
2437
 
1930
2438
  \`\`\`bash
2439
+ forge agent onboard --target codex --json
2440
+ forge status --json
2441
+ forge changed --json
2442
+ forge handoff --json
1931
2443
  forge do inspect --json
1932
2444
  forge do fix --json
1933
2445
  forge do verify --json
1934
2446
  forge dev --once --json
1935
2447
  forge dev
1936
- forge inspect all --json
2448
+ forge agent print-context --json
1937
2449
  forge inspect frontend --json
1938
2450
  forge inspect capabilities --json
1939
2451
  forge inspect agent-tools --json
2452
+ forge inspect all --json
1940
2453
  forge check --json
1941
2454
  forge ai trace <traceId> --json
1942
2455
  \`\`\`
@@ -1954,7 +2467,158 @@ Always finish with:
1954
2467
 
1955
2468
  \`\`\`bash
1956
2469
  forge generate
1957
- forge verify --strict
2470
+ ${finalVerify}
1958
2471
  \`\`\`
1959
- `);
2472
+ `));
2473
+ }
2474
+
2475
+ function renderAgentCairGuideMd(contract: AgentContract, workspaceRoot: string): string {
2476
+ const cair = contract.agentProtocols.find((protocol) => protocol.id === "cair");
2477
+ const finalVerify = finalVerifyCommand(workspaceRoot);
2478
+ const summary = [
2479
+ `commands=${contract.commands.length}`,
2480
+ `queries=${contract.queries.length}`,
2481
+ `liveQueries=${contract.liveQueries.length}`,
2482
+ `actions=${contract.actions.length}`,
2483
+ `workflows=${contract.workflows.length}`,
2484
+ `tables=${contract.data.tables.length}`,
2485
+ ].join(" ");
2486
+ return normalizeNewlines(localizeForgeCliMarkdown(workspaceRoot, `# CAIR Agent Guide
2487
+
2488
+ Project: ${contract.project.name}
2489
+ CAIR version: ${cair?.version ?? CAIR_SCHEMA_VERSION}
2490
+ Surface: ${summary}
2491
+
2492
+ 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.
2493
+
2494
+ ## First commands
2495
+
2496
+ \`\`\`bash
2497
+ forge cair snapshot
2498
+ forge cair query "Q ST"
2499
+ \`\`\`
2500
+
2501
+ The snapshot emits compact ids:
2502
+
2503
+ - \`M#\` modules/files
2504
+ - \`S#\` symbols
2505
+ - \`P#\` packages
2506
+ - \`API#\` dependency APIs
2507
+ - \`T#\` tests
2508
+
2509
+ ## Read before editing
2510
+
2511
+ \`\`\`bash
2512
+ forge cair query "Q S name=<symbol>"
2513
+ forge cair query "Q D S#1"
2514
+ forge cair query "Q R S#1"
2515
+ forge cair query "Q I S#1"
2516
+ forge cair query "Q T S#1"
2517
+ forge cair query "Q DEP.API package=<pkg> symbol=<export>"
2518
+ \`\`\`
2519
+
2520
+ Only open source files after CAIR shows that the exact file or body is needed.
2521
+
2522
+ ## Plan, apply, rollback
2523
+
2524
+ Never apply semantic mutations first. Create a plan:
2525
+
2526
+ \`\`\`bash
2527
+ forge cair action --plan "A RN t=S#1 nn=<newName>"
2528
+ \`\`\`
2529
+
2530
+ Apply the returned plan path:
2531
+
2532
+ \`\`\`bash
2533
+ forge cair action "A APPLY plan=<P#|.forge/cair/plans/...json>"
2534
+ \`\`\`
2535
+
2536
+ Keep returned journal paths for rollback:
2537
+
2538
+ \`\`\`bash
2539
+ forge cair action "A ROLLBACK journal=.forge/cair/journal/<journal>.json"
2540
+ \`\`\`
2541
+
2542
+ ## Semantic actions
2543
+
2544
+ \`\`\`txt
2545
+ A RN t=S#1 nn=<newName>
2546
+ A MV t=S#1 to=src/target.ts
2547
+ A SIG t=S#1 signature="export function x(input: string): boolean"
2548
+ A PARAM t=S#1 name=tenantId type=string default="defaultTenant"
2549
+ A CALLS t=S#1 appendArg="defaultTenant"
2550
+ A OI f=M#1
2551
+ A FMT f=M#1
2552
+ \`\`\`
2553
+
2554
+ For high-risk semantic actions, include expectations when available:
2555
+
2556
+ \`\`\`txt
2557
+ expect.file=src/path.ts
2558
+ expect.kind=command
2559
+ expect.hash=<sha256>
2560
+ \`\`\`
2561
+
2562
+ ## Forge-native actions
2563
+
2564
+ Prefer Forge-native CAIR actions over hand-writing boilerplate:
2565
+
2566
+ \`\`\`txt
2567
+ A MC n=createTicket
2568
+ A MQ n=listTickets
2569
+ A MA n=chargeCustomer
2570
+ A MT n=tickets fields=title:text,status:text
2571
+ A AT t=S#1 kind=unit
2572
+ A WX t=S#1 file=src/index.ts
2573
+ \`\`\`
2574
+
2575
+ ## Compact aliases
2576
+
2577
+ Queries:
2578
+
2579
+ \`\`\`txt
2580
+ Q ST = Q STATUS
2581
+ Q S = Q SYMBOL
2582
+ Q D = Q DEF
2583
+ Q R = Q REFS
2584
+ Q I = Q IMPACT
2585
+ Q M = Q MODULE
2586
+ Q T = Q TESTS
2587
+ Q API = Q DEP.API
2588
+ \`\`\`
2589
+
2590
+ Actions:
2591
+
2592
+ \`\`\`txt
2593
+ A RN = A RENAME.SYMBOL
2594
+ A MV = A MOVE.SYMBOL
2595
+ A OI = A ORGANIZE.IMPORTS
2596
+ A FMT = A FORMAT
2597
+ A MC = A MAKE.COMMAND
2598
+ A MQ = A MAKE.QUERY
2599
+ A MA = A MAKE.ACTION
2600
+ A MT = A MAKE.TABLE
2601
+ A AT = A ADD.TEST
2602
+ A WX = A WIRE.EXPORT
2603
+ A AP = A APPLY
2604
+ A RB = A ROLLBACK
2605
+ \`\`\`
2606
+
2607
+ ## Verification
2608
+
2609
+ After CAIR edits, run the narrowest useful checks:
2610
+
2611
+ \`\`\`bash
2612
+ forge check --json
2613
+ forge verify --standard
2614
+ ${finalVerify}
2615
+ \`\`\`
2616
+
2617
+ ## Constraints
2618
+
2619
+ - Do not edit \`src/forge/_generated/**\` unless explicitly allowed.
2620
+ - Do not bypass \`--plan\` for semantic edits.
2621
+ - Do not use CAIR as blind text replacement when a semantic action exists.
2622
+ - Use TypeScript language service, ast-grep, ts-morph, or raw file reads only as implementation backends or fallbacks. CAIR is the agent-facing protocol.
2623
+ `));
1960
2624
  }