@kindgi/cli 0.1.4 → 0.1.5-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/README.md +13 -7
  2. package/dist/build/defaults.d.ts +3 -1
  3. package/dist/build/defaults.d.ts.map +1 -1
  4. package/dist/build/defaults.js +44 -1
  5. package/dist/build/defaults.js.map +1 -1
  6. package/dist/build/java-image.d.ts +31 -0
  7. package/dist/build/java-image.d.ts.map +1 -0
  8. package/dist/build/java-image.js +146 -0
  9. package/dist/build/java-image.js.map +1 -0
  10. package/dist/build/pack-root.d.ts +1 -31
  11. package/dist/build/pack-root.d.ts.map +1 -1
  12. package/dist/build/pack-root.js +22 -2
  13. package/dist/build/pack-root.js.map +1 -1
  14. package/dist/build/runners.d.ts +44 -0
  15. package/dist/build/runners.d.ts.map +1 -1
  16. package/dist/build/scala-image.d.ts +21 -0
  17. package/dist/build/scala-image.d.ts.map +1 -0
  18. package/dist/build/scala-image.js +150 -0
  19. package/dist/build/scala-image.js.map +1 -0
  20. package/dist/cli-pin.d.ts +16 -0
  21. package/dist/cli-pin.d.ts.map +1 -0
  22. package/dist/cli-pin.js +66 -0
  23. package/dist/cli-pin.js.map +1 -0
  24. package/dist/commands/agents.d.ts.map +1 -1
  25. package/dist/commands/agents.js +9 -8
  26. package/dist/commands/agents.js.map +1 -1
  27. package/dist/commands/approvals.d.ts.map +1 -1
  28. package/dist/commands/approvals.js +30 -4
  29. package/dist/commands/approvals.js.map +1 -1
  30. package/dist/commands/artifacts.d.ts.map +1 -1
  31. package/dist/commands/artifacts.js +100 -37
  32. package/dist/commands/artifacts.js.map +1 -1
  33. package/dist/commands/auth.js +2 -2
  34. package/dist/commands/blocks.d.ts.map +1 -1
  35. package/dist/commands/blocks.js +5 -4
  36. package/dist/commands/blocks.js.map +1 -1
  37. package/dist/commands/build.d.ts +10 -2
  38. package/dist/commands/build.d.ts.map +1 -1
  39. package/dist/commands/build.js +109 -16
  40. package/dist/commands/build.js.map +1 -1
  41. package/dist/commands/capabilities.d.ts.map +1 -1
  42. package/dist/commands/capabilities.js +37 -10
  43. package/dist/commands/capabilities.js.map +1 -1
  44. package/dist/commands/console.d.ts +21 -0
  45. package/dist/commands/console.d.ts.map +1 -0
  46. package/dist/commands/console.js +87 -0
  47. package/dist/commands/console.js.map +1 -0
  48. package/dist/commands/conversations.d.ts.map +1 -1
  49. package/dist/commands/conversations.js +13 -2
  50. package/dist/commands/conversations.js.map +1 -1
  51. package/dist/commands/deploy.d.ts.map +1 -1
  52. package/dist/commands/deploy.js +2 -2
  53. package/dist/commands/deploy.js.map +1 -1
  54. package/dist/commands/dev.d.ts +11 -0
  55. package/dist/commands/dev.d.ts.map +1 -1
  56. package/dist/commands/dev.js +211 -39
  57. package/dist/commands/dev.js.map +1 -1
  58. package/dist/commands/doctor.d.ts +14 -2
  59. package/dist/commands/doctor.d.ts.map +1 -1
  60. package/dist/commands/doctor.js +355 -19
  61. package/dist/commands/doctor.js.map +1 -1
  62. package/dist/commands/env-scoped.d.ts +44 -0
  63. package/dist/commands/env-scoped.d.ts.map +1 -0
  64. package/dist/commands/env-scoped.js +222 -0
  65. package/dist/commands/env-scoped.js.map +1 -0
  66. package/dist/commands/env.d.ts.map +1 -1
  67. package/dist/commands/env.js +85 -123
  68. package/dist/commands/env.js.map +1 -1
  69. package/dist/commands/eval-runs.d.ts +9 -0
  70. package/dist/commands/eval-runs.d.ts.map +1 -1
  71. package/dist/commands/eval-runs.js +20 -19
  72. package/dist/commands/eval-runs.js.map +1 -1
  73. package/dist/commands/eval-suites.d.ts.map +1 -1
  74. package/dist/commands/eval-suites.js +16 -8
  75. package/dist/commands/eval-suites.js.map +1 -1
  76. package/dist/commands/exports.d.ts +3 -0
  77. package/dist/commands/exports.d.ts.map +1 -0
  78. package/dist/commands/exports.js +82 -0
  79. package/dist/commands/exports.js.map +1 -0
  80. package/dist/commands/feedback.d.ts.map +1 -1
  81. package/dist/commands/feedback.js +6 -5
  82. package/dist/commands/feedback.js.map +1 -1
  83. package/dist/commands/flows.d.ts.map +1 -1
  84. package/dist/commands/flows.js +2 -1
  85. package/dist/commands/flows.js.map +1 -1
  86. package/dist/commands/gate-policies.d.ts.map +1 -1
  87. package/dist/commands/gate-policies.js +2 -1
  88. package/dist/commands/gate-policies.js.map +1 -1
  89. package/dist/commands/guardrails.d.ts.map +1 -1
  90. package/dist/commands/guardrails.js +3 -2
  91. package/dist/commands/guardrails.js.map +1 -1
  92. package/dist/commands/helpers.js +5 -5
  93. package/dist/commands/helpers.js.map +1 -1
  94. package/dist/commands/index.d.ts.map +1 -1
  95. package/dist/commands/index.js +14 -0
  96. package/dist/commands/index.js.map +1 -1
  97. package/dist/commands/init.d.ts +1 -1
  98. package/dist/commands/init.d.ts.map +1 -1
  99. package/dist/commands/init.js +254 -18
  100. package/dist/commands/init.js.map +1 -1
  101. package/dist/commands/judge-classes.d.ts.map +1 -1
  102. package/dist/commands/judge-classes.js +11 -10
  103. package/dist/commands/judge-classes.js.map +1 -1
  104. package/dist/commands/judgments.d.ts.map +1 -1
  105. package/dist/commands/judgments.js +7 -6
  106. package/dist/commands/judgments.js.map +1 -1
  107. package/dist/commands/key.js +4 -4
  108. package/dist/commands/memory.d.ts.map +1 -1
  109. package/dist/commands/memory.js +277 -25
  110. package/dist/commands/memory.js.map +1 -1
  111. package/dist/commands/people.d.ts +3 -0
  112. package/dist/commands/people.d.ts.map +1 -0
  113. package/dist/commands/people.js +166 -0
  114. package/dist/commands/people.js.map +1 -0
  115. package/dist/commands/proposals.d.ts.map +1 -1
  116. package/dist/commands/proposals.js +390 -69
  117. package/dist/commands/proposals.js.map +1 -1
  118. package/dist/commands/provenance.d.ts.map +1 -1
  119. package/dist/commands/provenance.js +6 -7
  120. package/dist/commands/provenance.js.map +1 -1
  121. package/dist/commands/providers.d.ts.map +1 -1
  122. package/dist/commands/providers.js +6 -5
  123. package/dist/commands/providers.js.map +1 -1
  124. package/dist/commands/reviewers.d.ts.map +1 -1
  125. package/dist/commands/reviewers.js +3 -2
  126. package/dist/commands/reviewers.js.map +1 -1
  127. package/dist/commands/runs.d.ts.map +1 -1
  128. package/dist/commands/runs.js +24 -14
  129. package/dist/commands/runs.js.map +1 -1
  130. package/dist/commands/schedules.d.ts +3 -0
  131. package/dist/commands/schedules.d.ts.map +1 -0
  132. package/dist/commands/schedules.js +275 -0
  133. package/dist/commands/schedules.js.map +1 -0
  134. package/dist/commands/secrets.d.ts.map +1 -1
  135. package/dist/commands/secrets.js +10 -11
  136. package/dist/commands/secrets.js.map +1 -1
  137. package/dist/commands/service-accounts.d.ts +3 -0
  138. package/dist/commands/service-accounts.d.ts.map +1 -0
  139. package/dist/commands/service-accounts.js +175 -0
  140. package/dist/commands/service-accounts.js.map +1 -0
  141. package/dist/commands/skills.d.ts +1 -1
  142. package/dist/commands/skills.d.ts.map +1 -1
  143. package/dist/commands/skills.js +11 -4
  144. package/dist/commands/skills.js.map +1 -1
  145. package/dist/commands/sso.d.ts +6 -0
  146. package/dist/commands/sso.d.ts.map +1 -0
  147. package/dist/commands/sso.js +318 -0
  148. package/dist/commands/sso.js.map +1 -0
  149. package/dist/commands/tokens.d.ts +11 -0
  150. package/dist/commands/tokens.d.ts.map +1 -1
  151. package/dist/commands/tokens.js +144 -11
  152. package/dist/commands/tokens.js.map +1 -1
  153. package/dist/commands/tools.d.ts.map +1 -1
  154. package/dist/commands/tools.js +4 -3
  155. package/dist/commands/tools.js.map +1 -1
  156. package/dist/commands/unwired.d.ts.map +1 -1
  157. package/dist/commands/unwired.js +1 -30
  158. package/dist/commands/unwired.js.map +1 -1
  159. package/dist/commands/upgrade.d.ts +11 -0
  160. package/dist/commands/upgrade.d.ts.map +1 -0
  161. package/dist/commands/upgrade.js +160 -0
  162. package/dist/commands/upgrade.js.map +1 -0
  163. package/dist/context.d.ts +7 -0
  164. package/dist/context.d.ts.map +1 -1
  165. package/dist/context.js +1 -0
  166. package/dist/context.js.map +1 -1
  167. package/dist/dev/defaults.d.ts +28 -11
  168. package/dist/dev/defaults.d.ts.map +1 -1
  169. package/dist/dev/defaults.js +114 -35
  170. package/dist/dev/defaults.js.map +1 -1
  171. package/dist/dev/google-credentials.d.ts +50 -0
  172. package/dist/dev/google-credentials.d.ts.map +1 -0
  173. package/dist/dev/google-credentials.js +157 -0
  174. package/dist/dev/google-credentials.js.map +1 -0
  175. package/dist/dev/java-builder.d.ts +56 -0
  176. package/dist/dev/java-builder.d.ts.map +1 -0
  177. package/dist/dev/java-builder.js +204 -0
  178. package/dist/dev/java-builder.js.map +1 -0
  179. package/dist/dev/jvm-run-files.d.ts +29 -0
  180. package/dist/dev/jvm-run-files.d.ts.map +1 -0
  181. package/dist/dev/jvm-run-files.js +94 -0
  182. package/dist/dev/jvm-run-files.js.map +1 -0
  183. package/dist/dev/lines.d.ts +13 -0
  184. package/dist/dev/lines.d.ts.map +1 -0
  185. package/dist/dev/lines.js +24 -0
  186. package/dist/dev/lines.js.map +1 -0
  187. package/dist/dev/log-view.d.ts +116 -0
  188. package/dist/dev/log-view.d.ts.map +1 -0
  189. package/dist/dev/log-view.js +233 -0
  190. package/dist/dev/log-view.js.map +1 -0
  191. package/dist/dev/pack-code.d.ts +79 -4
  192. package/dist/dev/pack-code.d.ts.map +1 -1
  193. package/dist/dev/pack-code.js +262 -3
  194. package/dist/dev/pack-code.js.map +1 -1
  195. package/dist/dev/pack-env.d.ts.map +1 -1
  196. package/dist/dev/pack-env.js +4 -0
  197. package/dist/dev/pack-env.js.map +1 -1
  198. package/dist/dev/pack-service.d.ts +11 -1
  199. package/dist/dev/pack-service.d.ts.map +1 -1
  200. package/dist/dev/pack-service.js +56 -20
  201. package/dist/dev/pack-service.js.map +1 -1
  202. package/dist/dev/paths.d.ts +6 -0
  203. package/dist/dev/paths.d.ts.map +1 -1
  204. package/dist/dev/paths.js +8 -0
  205. package/dist/dev/paths.js.map +1 -1
  206. package/dist/dev/project-database.js +1 -1
  207. package/dist/dev/project-database.js.map +1 -1
  208. package/dist/dev/runners.d.ts +35 -9
  209. package/dist/dev/runners.d.ts.map +1 -1
  210. package/dist/dev/runtime-container.d.ts +10 -2
  211. package/dist/dev/runtime-container.d.ts.map +1 -1
  212. package/dist/dev/runtime-container.js +48 -20
  213. package/dist/dev/runtime-container.js.map +1 -1
  214. package/dist/dev/runtime-env.d.ts +10 -0
  215. package/dist/dev/runtime-env.d.ts.map +1 -1
  216. package/dist/dev/runtime-env.js +8 -4
  217. package/dist/dev/runtime-env.js.map +1 -1
  218. package/dist/dev/runtime-image.d.ts +1 -1
  219. package/dist/dev/runtime-image.d.ts.map +1 -1
  220. package/dist/dev/runtime-image.js +1 -1
  221. package/dist/dev/runtime-image.js.map +1 -1
  222. package/dist/dev/scala-builder.d.ts +72 -0
  223. package/dist/dev/scala-builder.d.ts.map +1 -0
  224. package/dist/dev/scala-builder.js +347 -0
  225. package/dist/dev/scala-builder.js.map +1 -0
  226. package/dist/env/project-env.d.ts.map +1 -1
  227. package/dist/env/project-env.js +3 -1
  228. package/dist/env/project-env.js.map +1 -1
  229. package/dist/errors.d.ts +9 -0
  230. package/dist/errors.d.ts.map +1 -1
  231. package/dist/errors.js +15 -0
  232. package/dist/errors.js.map +1 -1
  233. package/dist/init/dependency-specs.d.ts +26 -0
  234. package/dist/init/dependency-specs.d.ts.map +1 -1
  235. package/dist/init/dependency-specs.js +38 -0
  236. package/dist/init/dependency-specs.js.map +1 -1
  237. package/dist/init/java-augment.d.ts +24 -0
  238. package/dist/init/java-augment.d.ts.map +1 -0
  239. package/dist/init/java-augment.js +198 -0
  240. package/dist/init/java-augment.js.map +1 -0
  241. package/dist/init/mode-detect.d.ts +2 -2
  242. package/dist/init/mode-detect.d.ts.map +1 -1
  243. package/dist/init/mode-detect.js +12 -1
  244. package/dist/init/mode-detect.js.map +1 -1
  245. package/dist/init/scala-augment.d.ts +23 -0
  246. package/dist/init/scala-augment.d.ts.map +1 -0
  247. package/dist/init/scala-augment.js +213 -0
  248. package/dist/init/scala-augment.js.map +1 -0
  249. package/dist/init/template-files.d.ts +40 -2
  250. package/dist/init/template-files.d.ts.map +1 -1
  251. package/dist/init/template-files.js +56 -5
  252. package/dist/init/template-files.js.map +1 -1
  253. package/dist/main.d.ts +3 -0
  254. package/dist/main.d.ts.map +1 -1
  255. package/dist/main.js +20 -2
  256. package/dist/main.js.map +1 -1
  257. package/dist/open-url.d.ts +15 -0
  258. package/dist/open-url.d.ts.map +1 -0
  259. package/dist/open-url.js +41 -0
  260. package/dist/open-url.js.map +1 -0
  261. package/dist/package-manager.d.ts +10 -3
  262. package/dist/package-manager.d.ts.map +1 -1
  263. package/dist/package-manager.js +19 -1
  264. package/dist/package-manager.js.map +1 -1
  265. package/dist/providers/presets/anthropic.json +11 -3
  266. package/dist/sdk-skills/kindgi-authoring-agents/SKILL.md +26 -2
  267. package/dist/sdk-skills/kindgi-authoring-flows/SKILL.md +1 -1
  268. package/dist/sdk-skills/kindgi-authoring-guardrails/SKILL.md +47 -3
  269. package/dist/sdk-skills/kindgi-authoring-mcp-servers/SKILL.md +7 -5
  270. package/dist/sdk-skills/kindgi-authoring-providers/SKILL.md +40 -15
  271. package/dist/sdk-skills/kindgi-authoring-tools/SKILL.md +27 -1
  272. package/dist/sdk-skills/kindgi-framework-feedback/SKILL.md +5 -4
  273. package/dist/sdk-skills/kindgi-getting-started/SKILL.md +1 -1
  274. package/dist/sdk-skills/kindgi-java-authoring-agents/SKILL.md +220 -0
  275. package/dist/sdk-skills/kindgi-java-authoring-flows/SKILL.md +390 -0
  276. package/dist/sdk-skills/kindgi-java-authoring-guardrails/SKILL.md +209 -0
  277. package/dist/sdk-skills/kindgi-java-authoring-tools/SKILL.md +334 -0
  278. package/dist/sdk-skills/kindgi-java-getting-started/SKILL.md +270 -0
  279. package/dist/sdk-skills/kindgi-python-authoring-agents/SKILL.md +21 -3
  280. package/dist/sdk-skills/kindgi-python-authoring-flows/SKILL.md +1 -1
  281. package/dist/sdk-skills/kindgi-python-authoring-guardrails/SKILL.md +10 -3
  282. package/dist/sdk-skills/kindgi-python-authoring-tools/SKILL.md +36 -5
  283. package/dist/sdk-skills/kindgi-python-getting-started/SKILL.md +2 -2
  284. package/dist/sdk-skills/kindgi-scala-authoring-agents/SKILL.md +217 -0
  285. package/dist/sdk-skills/kindgi-scala-authoring-flows/SKILL.md +357 -0
  286. package/dist/sdk-skills/kindgi-scala-authoring-guardrails/SKILL.md +199 -0
  287. package/dist/sdk-skills/kindgi-scala-authoring-tools/SKILL.md +302 -0
  288. package/dist/sdk-skills/kindgi-scala-getting-started/SKILL.md +302 -0
  289. package/dist/templates/java/.mvn/wrapper/maven-wrapper.properties +3 -0
  290. package/dist/templates/java/AGENTS.md +31 -0
  291. package/dist/templates/java/README.md.tmpl +69 -0
  292. package/dist/templates/java/gitignore +9 -0
  293. package/dist/templates/java/kindgi.config.json.tmpl +8 -0
  294. package/dist/templates/java/kindgiw +33 -0
  295. package/dist/templates/java/kindgiw.cmd +28 -0
  296. package/dist/templates/java/mvnw +295 -0
  297. package/dist/templates/java/pom.xml.tmpl +65 -0
  298. package/dist/templates/java/src/main/java/__PACKAGE__/agents/EchoAgent.java.tmpl +27 -0
  299. package/dist/templates/java/src/main/java/__PACKAGE__/flows/EchoFlow.java.tmpl +18 -0
  300. package/dist/templates/java/src/main/java/__PACKAGE__/guardrails/ResponseNotEmpty.java.tmpl +28 -0
  301. package/dist/templates/java/src/main/java/__PACKAGE__/tools/Echo.java.tmpl +22 -0
  302. package/dist/templates/java/src/main/java/__PACKAGE__/tools/Greet.java.tmpl +23 -0
  303. package/dist/templates/java/src/test/java/__PACKAGE__/ToolsTest.java.tmpl +30 -0
  304. package/dist/templates/minimal/README.md.tmpl +6 -12
  305. package/dist/templates/python/README.md.tmpl +4 -4
  306. package/dist/templates/sample/README.md.tmpl +5 -11
  307. package/dist/templates/scala/AGENTS.md +32 -0
  308. package/dist/templates/scala/README.md.tmpl +75 -0
  309. package/dist/templates/scala/build.sbt.tmpl +16 -0
  310. package/dist/templates/scala/gitignore +13 -0
  311. package/dist/templates/scala/kindgi.config.json.tmpl +8 -0
  312. package/dist/templates/scala/project/build.properties +1 -0
  313. package/dist/templates/scala/src/main/scala/__PACKAGE__/agents/EchoAgent.scala.tmpl +23 -0
  314. package/dist/templates/scala/src/main/scala/__PACKAGE__/flows/EchoFlow.scala.tmpl +16 -0
  315. package/dist/templates/scala/src/main/scala/__PACKAGE__/guardrails/ResponseNotEmpty.scala.tmpl +21 -0
  316. package/dist/templates/scala/src/main/scala/__PACKAGE__/tools/Echo.scala.tmpl +16 -0
  317. package/dist/templates/scala/src/main/scala/__PACKAGE__/tools/Greet.scala.tmpl +17 -0
  318. package/dist/templates/scala/src/test/scala/__PACKAGE__/ToolsSuite.scala.tmpl +23 -0
  319. package/package.json +13 -12
@@ -0,0 +1,220 @@
1
+ ---
2
+ name: kindgi-java-authoring-agents
3
+ description: >
4
+ Covers writing agents for a Kindgi pack in Java (`com.kindgi:kindgi-pack`):
5
+ `Agent.define(id)` as a `public static final` field, wiring tools (`Tool`
6
+ objects or an id with a version range) and guardrails, capabilities and
7
+ model choice (preferredProvider / preferredModel), conversation policy,
8
+ turn budgets, prompt parameters, a typed answer from a record, and
9
+ tool-error retries, all as data. Load this whenever you are authoring or
10
+ editing code in a Java pack's agents packages (a pack whose
11
+ `kindgi.config.json` says `"language": "java"`), defining an agent, or
12
+ when the user asks to add, change or refactor one. Java tools are covered
13
+ by kindgi-java-authoring-tools, Java guardrails by
14
+ kindgi-java-authoring-guardrails, connecting a real model by
15
+ kindgi-authoring-providers.
16
+ type: core
17
+ library: "kindgi-pack (Java)"
18
+ version: "0.1.0"
19
+ sdk_version: "0.1.5-rc.0"
20
+ pack_languages: [java]
21
+ sources:
22
+ - sdks/java/kindgi-pack/README.md
23
+ - sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/Agent.java
24
+ - packages/specs/schemas/agent.schema.json
25
+ - packages/specs/schemas/pack-index.schema.json
26
+ ---
27
+
28
+ # Authoring Kindgi agents in Java
29
+
30
+ > **Running `kindgi`:** the pack pins its CLI (`"cli"` in
31
+ > `kindgi.config.json`), and `./kindgiw` runs that version, so every
32
+ > `kindgi <command>` below runs as `./kindgiw <command>`. Maven runs as
33
+ > `./mvnw`.
34
+ >
35
+ > Java support is in preview: tested and supported, but the API may still
36
+ > change in 0.1.6 without the usual deprecation period.
37
+
38
+ An **agent** is a versioned, model-driven orchestrator. It's made of:
39
+ - instructions (a prompt template);
40
+ - the tools it may call;
41
+ - the capabilities its model needs;
42
+ - guardrails that gate its answer;
43
+ - optionally, a conversation policy.
44
+
45
+ In a Java pack it is **data**: a `public static final Agent` field of a class
46
+ in an `agents` package. The model runs in the Kindgi runtime, not in your
47
+ JVM. Your Java code runs only inside the agent's tools and guardrail checks.
48
+
49
+ ## Ask before building
50
+
51
+ "Add an agent" is a conversation opener, not a ticket. Before writing a
52
+ file, ask:
53
+
54
+ - **What should the agent do?** The purpose drives everything else.
55
+ - **Which tools does it need?** New ones, or existing ones?
56
+ - **Multi-turn or one-shot?** History changes the shape.
57
+ - **Any rules it must respect?** Those become guardrails.
58
+
59
+ The pack's sample agent proves the runtime works end to end. It is not the
60
+ shape to imitate unless the user asks for that.
61
+
62
+ ## An agent
63
+
64
+ ```java
65
+ // src/main/java/acme/agents/BriefWriter.java
66
+ package acme.agents;
67
+
68
+ import acme.guardrails.ResponseNotEmpty;
69
+ import acme.tools.Echo;
70
+ import com.kindgi.pack.Agent;
71
+ import java.util.List;
72
+ import java.util.Map;
73
+
74
+ /** acme.brief-writer: drafts a brief's argument from the case facts. */
75
+ public final class BriefWriter {
76
+ /** The typed answer: the final message must be JSON of this shape. */
77
+ public record Brief(String argument, List<String> citations) {}
78
+
79
+ public static final Agent AGENT = Agent.define("acme.brief-writer")
80
+ .version("0.1.0")
81
+ .name("Brief Writer")
82
+ .description("Drafts appellate briefs from a case file; cites precedents.")
83
+ .instructions("You are drafting a brief in {{ jurisdiction }}. The user gives the case facts; you write "
84
+ + "a Section IV argument citing at least two precedents. Check every cite with the echo tool "
85
+ + "before using it. Never invent one.")
86
+ .capability(Map.of("needs", List.of(Map.of("feature", "tool-use"))))
87
+ .tool(Echo.TOOL)
88
+ .guardrail(ResponseNotEmpty.GUARDRAIL)
89
+ .set("parameters", List.of(Map.of("name", "jurisdiction", "type", "string", "required", true)))
90
+ .set("conversationPolicy", Map.of("historyLimit", 20))
91
+ .set("budget", Map.of("maxSteps", 8, "maxCostUsd", 0.5, "maxWallMs", 60_000))
92
+ .set("toolErrors", Map.of("maxRetries", 1, "retryOn", List.of("invalid-arguments", "unknown-tool")))
93
+ .output(Brief.class)
94
+ .build();
95
+
96
+ private BriefWriter() {}
97
+ }
98
+ ```
99
+
100
+ - Tools and guardrails are the pack's own fields, imported like any class:
101
+ `.tool(Echo.TOOL)`, `.guardrail(ResponseNotEmpty.GUARDRAIL)`.
102
+ - **`build()` needs a version, a name and instructions.** Anything missing
103
+ is an error where the agent is defined, and the indexer reports it with
104
+ the file.
105
+ - **Every other field is `set(field, value)`, keyed as on the wire:** the
106
+ field and its maps are camelCase (`conversationPolicy`, `maxSteps`,
107
+ `historyLimit`), as `agent.schema.json` names them. The indexer checks
108
+ each agent against the pack index's schema, and `kindgi dev` reports a
109
+ mistake with its file.
110
+ - A class may hold several agents, each in its own `static final` field.
111
+
112
+ ## Field by field
113
+
114
+ - **`id`:** `<pack-id>.<agent-name>`, kebab-case, dot-namespaced.
115
+ - **`version`:** an exact semver. Conversations pin the version they started
116
+ on.
117
+ - **`name`, `description`**, and `set("tags", List.of(…))`: for people and
118
+ listings. The model never sees the description.
119
+ - **`instructions`:** a LiquidJS template. `{{ variable }}` comes from
120
+ `parameters` or the runtime's own variables (`today`, `now`, `agent.*`,
121
+ `conversation.*`). It's rendered strictly: an unknown variable fails the
122
+ turn. Write it as a brief for a capable colleague: what to do, which tools
123
+ to prefer, what to refuse, the quality bar. Name a tool by what it does
124
+ ("the verify-citation tool"), never by its dotted id. The model sees ids in
125
+ its provider's form (`acme__verify-citation` for Anthropic and
126
+ OpenAI-compatible models), and a dotted id in the instructions can make it
127
+ call a name it wasn't given. `instructions(Map.of("prompt", …, "version", …))`
128
+ references a registered prompt block instead.
129
+ - **`capability(Map)`:** what the model must support, such as
130
+ `Map.of("needs", List.of(Map.of("feature", "tool-use")))`. Call it once per
131
+ capability. The turn routes its first capability to pick a provider and
132
+ model; with none declared, the turn fails.
133
+ - **`tool(Tool)`:** pins that tool's version (its own, or the pack's).
134
+ **`tool(id, range)`** is a tool of another pack, with a semver **range**
135
+ (`"^1.0.0"`); the highest active matching version is picked at turn
136
+ start. An agent with no tools is chat-only.
137
+ - **`guardrail(Guardrail)`** or **`guardrail(id)`:** evaluated once per turn
138
+ on the final answer, before it is stored. An id with no registered
139
+ guardrail fails the turn.
140
+ - **`set("parameters", List.of(Map.of("name", …, "type", …, "required", …)))`:**
141
+ inputs the caller supplies per run. They fill `{{ … }}` in the
142
+ instructions.
143
+ - **`set("preferredProvider", "anthropic")`, `set("preferredModel", "claude-haiku-4-5")`:**
144
+ soft hints. The router prefers them when they satisfy the capabilities.
145
+ To *require* a model, put it in the capability:
146
+ `Map.of("needs", List.of(Map.of("feature", "tool-use"), Map.of("models", Map.of("allow", List.of("claude-haiku-4-5")))))`.
147
+ - **`set("conversationPolicy", …)`:** `historyLimit` caps the prior messages
148
+ loaded, and `hitl` configures approval gates. Absent, the turn loads the
149
+ full history with no gates. A tenant's `hitl` policy can tighten the gates
150
+ (a shorter timeout, a higher reviewer role, stricter per tool), never
151
+ loosen them.
152
+ - **`set("budget", …)`:** per turn. `maxSteps` counts model calls (default
153
+ 8); `maxCostUsd`; `maxWallMs` (default 120 000). Exceeding the steps or the
154
+ cost fails the turn (`budget-exceeded`); running out of wall time aborts
155
+ it. Leave room for real models: a turn with tool calls can take tens of
156
+ seconds.
157
+ - **`output(Type.class)`:** a typed answer, with its schema derived from the
158
+ record. The final answer must be JSON matching it. A wrong one goes back
159
+ to the model with the problems (`maxRepairs`, default 1), and then the
160
+ turn fails (`output-schema-violation`). For `maxRepairs` or a schema of
161
+ your own, use `set("output", Map.of("schema", …, "maxRepairs", 2))`. The
162
+ parsed answer is the turn result's `output`. In a flow it is
163
+ `nodeOutputs.<step>.output.<field>`.
164
+ - **`set("toolErrors", …)`:** `maxRetries` and `retryOn`. A failed tool call
165
+ goes back to the model as the call's result, so it can fix the call. The
166
+ default kinds are `invalid-arguments` and `unknown-tool` (nothing ran). Add
167
+ `tool-error` only when retrying the tool is safe. Each retry costs a step.
168
+
169
+ ## Which model answers
170
+
171
+ Agents run on a registered model provider: the router picks one whose
172
+ models satisfy the capabilities. `kindgi dev` gives a new pack `dev-echo`, a
173
+ **fallback** that answers only while no other provider fits. It calls the
174
+ first tool and replies "⚠ dev-echo isn't a real model: …", then "Tool
175
+ responded: …". The turn carries the `fallback-provider` and
176
+ `dev-echo-not-a-model` warnings. dev-echo can't fill in any other tool
177
+ input, and can't give a typed answer: an agent with `output` fails with
178
+ `output-schema-violation` until a real model is registered. To register one,
179
+ see `kindgi-authoring-providers` (`./kindgiw providers register --preset=anthropic`,
180
+ or `"providers": [{"preset": "anthropic"}]` in `kindgi.config.json`).
181
+
182
+ ## Iterating
183
+
184
+ Save the file: `kindgi dev` recompiles, re-indexes, and the next run uses
185
+ it, with no restart. Bump `version` when you break what callers rely on (a
186
+ removed parameter, an incompatible output), not on every save.
187
+
188
+ Run an agent from another terminal in the pack directory:
189
+
190
+ ```sh
191
+ ./kindgiw runs start --agent=acme.brief-writer --input='{"userMessage":"…","parameters":{"jurisdiction":"US"}}'
192
+ ```
193
+
194
+ or from a Java app with the client (`kindgi-java-getting-started`).
195
+
196
+ ## Common mistakes
197
+
198
+ 1. **Building an agent without asking what it should do.** Copying the
199
+ sample's shape answers the wrong question.
200
+ 2. **No `capability(…)`.** The turn can't pick a model.
201
+ 3. **Java names inside the maps.** `set("budget", Map.of("max_steps", 4))`
202
+ isn't a budget: the keys are the wire's camelCase (`maxSteps`,
203
+ `historyLimit`, `maxRetries`).
204
+ 4. **An unregistered guardrail id.** Pass the `Guardrail` field, or make sure
205
+ the id is one the tenant has.
206
+ 5. **`{{ variable }}` not in `parameters`.** The turn fails when the
207
+ instructions render.
208
+ 6. **An agent that isn't a `static final` field.** Only static fields are
209
+ indexed.
210
+ 7. **A tight `maxWallMs` with a real model.** 15 s aborts real turns under
211
+ load; 60 s is a safer start.
212
+ 8. **Expecting dev-echo to give a typed answer.** It can't: register a real
213
+ model first.
214
+
215
+ ## When the framework itself is the problem
216
+
217
+ If the bug is in Kindgi or kindgi-pack (the index dropping a field, a
218
+ misleading error, the router picking the wrong model) and not in the pack's
219
+ code, load `kindgi-framework-feedback` and file it with
220
+ `./kindgiw feedback write`.
@@ -0,0 +1,390 @@
1
+ ---
2
+ name: kindgi-java-authoring-flows
3
+ description: >
4
+ Covers writing flows for a Kindgi pack in Java (`com.kindgi:kindgi-pack`):
5
+ `Flow.define(id)` as a `public static final` field, tool and agent steps
6
+ (`toolNode`, `agentNode`, or a node map with `inputMapping` and `config`),
7
+ edges and their `when` conditions and `policy`, branches that join again,
8
+ inputMapping from runInput / nodeOutputs, typed agent output in a flow,
9
+ the flow's declared output, loops and fanout, and running a flow (runs
10
+ start --flow, in the background, as a dry run) and reading its journal.
11
+ Load this whenever you are authoring or editing code in a Java pack's
12
+ flows packages (a pack whose `kindgi.config.json` says
13
+ `"language": "java"`), defining a flow, or when the user asks to add,
14
+ change or debug one. Java tools are covered by
15
+ kindgi-java-authoring-tools, Java agents by kindgi-java-authoring-agents.
16
+ type: core
17
+ library: "kindgi-pack (Java)"
18
+ version: "0.1.0"
19
+ sdk_version: "0.1.5-rc.0"
20
+ pack_languages: [java]
21
+ sources:
22
+ - sdks/java/kindgi-pack/README.md
23
+ - sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/Flow.java
24
+ - packages/specs/schemas/flow.schema.json
25
+ ---
26
+
27
+ # Authoring Kindgi flows in Java
28
+
29
+ > **Running `kindgi`:** the pack pins its CLI (`"cli"` in
30
+ > `kindgi.config.json`), and `./kindgiw` runs that version, so every
31
+ > `kindgi <command>` below runs as `./kindgiw <command>`. Maven runs as
32
+ > `./mvnw`.
33
+ >
34
+ > Java support is in preview: tested and supported, but the API may still
35
+ > change in 0.1.6 without the usual deprecation period.
36
+
37
+ A **flow** is a versioned, durable graph of steps: tools (your code) and
38
+ agents (a model's judgment), joined by edges that can carry conditions. It
39
+ is **data**, not code: a `public static final Flow` field of a class in a
40
+ `flows` package. The runtime runs it step by step, journals every step, and
41
+ can resume a run that was interrupted. A run pins the flow version it
42
+ started on.
43
+
44
+ Use a flow when the order of the work is known: parse, then classify, then
45
+ branch, then write. Use a single agent when the model should decide the
46
+ order.
47
+
48
+ ## Ask before building
49
+
50
+ - **What goes in, and what comes out?** The run input's shape and the
51
+ output the caller reads. They become `runInput.*` paths and `output`.
52
+ - **Which steps are code, which are judgment?** Deterministic work (parse,
53
+ rank, look up, write) is a tool. Judgment (classify, draft, summarize) is
54
+ an agent with a typed `output`.
55
+ - **Where does it branch?** Every branch needs a condition, and the steps
56
+ after a branch must cope with the branch that didn't run.
57
+ - **What does it change outside Kindgi?** Know which tools write: a dry run
58
+ stops before them (see "Running a flow").
59
+
60
+ ## A flow
61
+
62
+ The tools and the agent it runs:
63
+
64
+ ```java
65
+ // src/main/java/acme/tools/Tickets.java
66
+ package acme.tools;
67
+
68
+ import com.kindgi.pack.Tool;
69
+ import org.jspecify.annotations.Nullable;
70
+
71
+ /** The ticket tools: parse one, look its invoice up, draft the reply. */
72
+ public final class Tickets {
73
+ public record Ticket(String customerId, String body) {}
74
+
75
+ public record ParseInput(Ticket ticket) {}
76
+
77
+ public record Parsed(String text) {}
78
+
79
+ public record InvoiceInput(String customerId) {}
80
+
81
+ public record Invoice(String number, double amount) {}
82
+
83
+ public record Found(Invoice invoice) {}
84
+
85
+ /** `invoice` is absent when the billing step didn't run: it may be null. */
86
+ public record ReplyInput(String category, @Nullable Invoice invoice) {}
87
+
88
+ public record Reply(String text) {}
89
+
90
+ public static final Tool<ParseInput, Parsed> PARSE = Tool.define("acme.parse-ticket")
91
+ .description("Extracts a ticket's text.")
92
+ .input(ParseInput.class)
93
+ .output(Parsed.class)
94
+ .mutating(false)
95
+ .handler((input, ctx) -> new Parsed(input.ticket().body().strip()));
96
+
97
+ public static final Tool<InvoiceInput, Found> LOOKUP_INVOICE = Tool.define("acme.lookup-invoice")
98
+ .description("The customer's latest invoice.")
99
+ .input(InvoiceInput.class)
100
+ .output(Found.class)
101
+ .mutating(false)
102
+ .handler((input, ctx) -> new Found(new Invoice("INV-1", 42.0)));
103
+
104
+ public static final Tool<ReplyInput, Reply> DRAFT_REPLY = Tool.define("acme.draft-reply")
105
+ .description("Drafts a reply for the ticket's category.")
106
+ .input(ReplyInput.class)
107
+ .output(Reply.class)
108
+ .mutating(false)
109
+ .handler((input, ctx) -> new Reply(input.invoice() == null
110
+ ? "Thanks, we're on it (" + input.category() + ")."
111
+ : "Invoice " + input.invoice().number() + " is " + input.invoice().amount() + "."));
112
+
113
+ private Tickets() {}
114
+ }
115
+ ```
116
+
117
+ ```java
118
+ // src/main/java/acme/agents/TicketClassifier.java
119
+ package acme.agents;
120
+
121
+ import com.kindgi.pack.Agent;
122
+ import java.util.List;
123
+ import java.util.Map;
124
+
125
+ /** acme.ticket-classifier: one word for a ticket's category. */
126
+ public final class TicketClassifier {
127
+ public record Category(String category) {}
128
+
129
+ public static final Agent AGENT = Agent.define("acme.ticket-classifier")
130
+ .version("0.1.0")
131
+ .name("Ticket classifier")
132
+ .instructions("Classify the support ticket for {{ product }}: answer billing, bug or other, "
133
+ + "as JSON with one field, category.")
134
+ .capability(Map.of("needs", List.of(Map.of("feature", "tool-use"))))
135
+ .set("parameters", List.of(Map.of("name", "product", "type", "string", "required", true)))
136
+ .output(Category.class)
137
+ .build();
138
+
139
+ private TicketClassifier() {}
140
+ }
141
+ ```
142
+
143
+ The flow:
144
+
145
+ ```java
146
+ // src/main/java/acme/flows/TriageTicket.java
147
+ package acme.flows;
148
+
149
+ import acme.agents.TicketClassifier;
150
+ import acme.tools.Tickets;
151
+ import com.kindgi.pack.Flow;
152
+ import java.util.List;
153
+ import java.util.Map;
154
+
155
+ /** acme.triage-ticket: parse, classify, look billing up when needed, reply. */
156
+ public final class TriageTicket {
157
+ static final Map<String, Object> IS_BILLING = Map.of(
158
+ "op", "eq",
159
+ "left", Map.of("path", "nodeOutputs.classify.output.category"),
160
+ "right", Map.of("literal", "billing"));
161
+
162
+ public static final Flow FLOW = Flow.define("acme.triage-ticket")
163
+ .version("0.1.0")
164
+ .set("name", "Triage a support ticket")
165
+ .set("description", "Parses a ticket, classifies it, looks billing up when needed, drafts a reply.")
166
+ .node(Map.of("id", "parse", "kind", "tool", "ref", Tickets.PARSE,
167
+ "inputMapping", Map.of("ticket", Map.of("path", "runInput.ticket"))))
168
+ .node(Map.of("id", "classify", "kind", "agent", "ref", TicketClassifier.AGENT,
169
+ "inputMapping", Map.of("text", Map.of("path", "nodeOutputs.parse.text")),
170
+ "config", Map.of("parameters", Map.of("product", "acme-cloud"))))
171
+ .node(Map.of("id", "billing", "kind", "tool", "ref", Tickets.LOOKUP_INVOICE,
172
+ "inputMapping", Map.of("customerId", Map.of("path", "runInput.ticket.customerId"))))
173
+ .node(Map.of("id", "reply", "kind", "tool", "ref", Tickets.DRAFT_REPLY,
174
+ "inputMapping", Map.of(
175
+ "category", Map.of("path", "nodeOutputs.classify.output.category"),
176
+ "invoice", Map.of("path", "nodeOutputs.billing.invoice"))))
177
+ .edge("e0", "$start", "parse")
178
+ .edge("e1", "parse", "classify")
179
+ .edge(Map.of("id", "e2", "from", "classify", "to", "billing", "when", IS_BILLING))
180
+ .edge(Map.of("id", "e3", "from", "classify", "to", "reply", "when", Map.of("op", "not", "child", IS_BILLING)))
181
+ .edge("e4", "billing", "reply")
182
+ .edge("e5", "reply", "$end")
183
+ .set("output", Map.of(
184
+ "mapping", Map.of(
185
+ "category", Map.of("path", "nodeOutputs.classify.output.category"),
186
+ "reply", Map.of("path", "nodeOutputs.reply.text")),
187
+ "schema", Map.of(
188
+ "type", "object",
189
+ "properties", Map.of("category", Map.of("type", "string"), "reply", Map.of("type", "string")),
190
+ "required", List.of("category", "reply"))))
191
+ .build();
192
+
193
+ private TriageTicket() {}
194
+ }
195
+ ```
196
+
197
+ - **Steps:** `toolNode(id, Tool)` and `agentNode(id, Agent)` are a step with
198
+ nothing more. A step with an `inputMapping`, a `config`, a loop or a fanout
199
+ is a map, `node(Map.of(…))`, as `flow.schema.json` describes it. In a
200
+ node's map, a `Tool`, `Agent` or `Flow` (loop bodies and fanout branches
201
+ included) becomes its id. A primitive of another pack is its id string.
202
+ - **Edges:** `edge(id, from, to)` joins two steps. An edge with a condition
203
+ (`when`) or a `policy` is a map, `edge(Map.of(…))`.
204
+ - **Other fields:** `set(field, value)` takes `name`, `description`,
205
+ `output`, `maxParallelism` and `metadata`. `build()` needs a version.
206
+ - **The maps are the wire's shape,** so their keys are camelCase
207
+ (`inputMapping`, `loopKind`, `maxIterations`).
208
+ - **Where it's checked:** the indexer checks every flow against
209
+ `flow.schema.json` (version, node and edge shapes, `$start` / `$end`).
210
+ `kindgi dev` reports a mistake as a file error that says what and where,
211
+ while the pack's other primitives keep serving. Whether a step's tool or
212
+ agent exists is checked when a run starts (see "Running a flow").
213
+ - `Map.of` takes up to ten pairs. For a bigger map, use `Map.ofEntries` or a
214
+ `LinkedHashMap`.
215
+
216
+ ## Nodes
217
+
218
+ - **A tool step** (`"kind": "tool"`) runs the tool `ref`.
219
+ - Its input is what the node's `inputMapping` builds; else, the output of
220
+ the node's single upstream node (the run input after `$start`).
221
+ - The input is checked against the tool's input schema, so a mismatch
222
+ fails the step with `input-validation-failed`.
223
+ - The node's output is what the tool returned, as JSON (its Jackson names).
224
+ - **An agent step** (`"kind": "agent"`) runs one turn of the agent `ref`, as a
225
+ child run of the flow run.
226
+ - The agent gets the node's input two ways: as structured input
227
+ (`{{ input.text }}` in its instructions), and as its user message (the
228
+ input as JSON).
229
+ - `"config": {"parameters": {…}}` fills the agent's `parameters` (string,
230
+ number or boolean values). `"config": {"version": "1.2.0"}` pins an agent
231
+ version; without it, the latest active version runs.
232
+ - The node's output: `output` is the agent's typed answer (its
233
+ `output(Type.class)`); `text` is the answer as text; `runId` and
234
+ `conversationId` are the child run's. Read a field as
235
+ `nodeOutputs.<node>.output.<field>`.
236
+ - An answer that doesn't fit the agent's output, after its repairs, fails
237
+ the step with `output-schema-violation`. An approval inside the agent's
238
+ turn parks the flow until it's decided.
239
+ - **A loop** (`"kind": "loop"`) repeats a body.
240
+ - `"loopKind": "foreach"` runs it once per element of `iterateOver`
241
+ (`concurrency` up to 32 in parallel). `"loopKind": "while"` runs it until
242
+ `exitCondition`.
243
+ - The body (`"body": {"nodes": […], "edges": […]}`) has its own nodes and
244
+ edges, with `$loop-start` and `$loop-end`. The element is the body's
245
+ input.
246
+ - `maxIterations` and `outputSchema` are required.
247
+ - The loop's output is `finalOutput`, plus `outputs` with
248
+ `"collectAllIterations": true`.
249
+ - Node ids must be unique across the whole flow, bodies included.
250
+ - **A fanout** (`"kind": "fanout"`) runs several handlers on the same input
251
+ at once. Each is a branch (`branchId`, `handler`: a `Tool` or an id, and
252
+ `outputSchema`). `convergence` decides the result: `all-succeed`,
253
+ `any-succeed` (the first success wins), or `settle-all` (wait for every
254
+ branch and report each).
255
+ - **A sub-flow** (`"kind": "subgraph"`) is part of the flow schema, but a run
256
+ refuses it today (`flow-unbound`). Inline the steps instead.
257
+
258
+ ## Edges and conditions
259
+
260
+ An edge goes from a node (or `$start`) to a node (or `$end`). Without `when`
261
+ it fires when its source completes. With `when`, it fires only if the
262
+ condition is true. Conditions are maps:
263
+
264
+ | Operator | Shape |
265
+ |---|---|
266
+ | `eq` `ne` `lt` `lte` `gt` `gte` | `op`, `left`, `right` |
267
+ | `in` `notIn` | `op`, `value`, `set` |
268
+ | `exists` `notExists` `truthy` `falsy` | `op`, `value` |
269
+ | `and` `or` | `op`, `children` (a list) |
270
+ | `not` | `op`, `child` |
271
+
272
+ Each operand is `Map.of("literal", …)` or `Map.of("path", …)`. When a path
273
+ doesn't resolve, `eq`, `lt`, `lte`, `gt` and `gte` are false, and `ne` is
274
+ true. So for the "otherwise" branch, wrap the condition in `not` (as above)
275
+ rather than writing a second comparison: it covers exactly what the first
276
+ edge doesn't. A condition used twice is easiest as a constant (`IS_BILLING`).
277
+
278
+ **Joining branches.** A node with several incoming edges runs once every one
279
+ of them is decided and at least one fired. Above, `reply` runs after
280
+ `billing` on the billing branch, and straight after `classify` otherwise. A
281
+ node none of whose incoming edges fired is skipped, and so is everything
282
+ only it leads to.
283
+
284
+ **Edge policy** (`"policy"` on the edge into a node with a single incoming
285
+ edge; a node with several ignores it):
286
+ - `"retry": {"maxAttempts", "delayMs"?, "backoff"?, "maxDelayMs"?}`, up to 10
287
+ attempts in all;
288
+ - `"timeoutMs"`: a step that takes longer fails with `reason: timeout`;
289
+ - `"concurrencyKey"`: at most one such step at a time in the tenant;
290
+ - `"priority"`: −100 to 100.
291
+
292
+ ## Inputs and the output
293
+
294
+ `inputMapping` maps each key to a `literal` or a `path`. Its keys are the
295
+ tool's input **as it travels**: the record's Jackson names (a component
296
+ `customerId` is the key `customerId`; with
297
+ `@JsonProperty("customer_id")`, it's `customer_id`). Paths are dot-separated
298
+ (a number segment indexes an array: `items.0.sku`), rooted at:
299
+ - `runInput.…`: the input the run started with;
300
+ - `nodeOutputs.<nodeId>.…`: a step's output. For an agent step, add
301
+ `.output.<field>` to read its typed answer;
302
+ - `state.…`: values the runtime's own handlers write. Pack tools don't
303
+ write it, so use `nodeOutputs`.
304
+
305
+ A path that doesn't resolve leaves its key out. So a step after a branch
306
+ that didn't run gets no `invoice` key at all, rather than `null`. Make that
307
+ component optional in the tool's input (`@Nullable Invoice invoice`, as
308
+ above).
309
+
310
+ `set("output", …)` is what the run returns: a `mapping` resolved when the
311
+ run finishes, checked against `schema` if you give one. A run whose output
312
+ doesn't match fails. Without an output, the run returns the output of the
313
+ step that reached `$end`.
314
+
315
+ ## Running a flow
316
+
317
+ From another terminal in the pack directory, while `kindgi dev` runs:
318
+
319
+ ```sh
320
+ ./kindgiw runs start --flow=acme.triage-ticket --input='{"ticket":{"customerId":"c-1","body":"Charged twice"}}'
321
+ ./kindgiw runs start --flow=acme.triage-ticket --input=@ticket.json --no-wait # the run id now; it finishes in the background
322
+ ./kindgiw runs start --flow=acme.triage-ticket --input=@ticket.json --dry-run # stops before a tool that may write
323
+ ./kindgiw runs get <run-id> # status, output, failureMessage
324
+ ./kindgiw runs journal <run-id> # every step.started / step.completed / edge.evaluated
325
+ ./kindgiw runs stream <run-id> # follow a running one
326
+ ./kindgiw runs cancel <run-id>
327
+ ```
328
+
329
+ From a Java app, the client starts one the same way:
330
+ `client.runs().start(StartRunBody.WithFlow.builder().flow("acme.triage-ticket").input(…).build())`.
331
+
332
+ - **A refusal before the run exists:** `422 flow-unbound` names the nodes a
333
+ run can't bind: a tool or agent id the tenant doesn't have, or a
334
+ sub-flow. Fix the ids; nothing ran.
335
+ - **A failed step fails the run**, and `failureMessage` says which step and
336
+ why. Retry it on its edge with `policy.retry`, but only if running the
337
+ step twice is safe.
338
+ - **`--no-wait`** is how an application starts runs
339
+ (`"options": {"wait": false}`). It answers with the run id at once; poll
340
+ the run or follow its stream.
341
+ - **`--dry-run`** runs a tool only if it's declared read-only:
342
+ `mutating(false)` and no `writes`, `deletes`, `spawns-run`, `emits-event`
343
+ or `external-side-effect` effect. The first other tool stops the run with
344
+ `dry-run-effectful-tool`, and everything before it really ran. That's
345
+ useful for checking the wiring without the writes.
346
+
347
+ ## Iterating on a flow
348
+
349
+ Save the file, and `kindgi dev` recompiles and re-indexes. The next run uses
350
+ the new definition, with no restart. A run already in flight keeps the
351
+ version it started on. Bump `version` when callers' contract changes (the
352
+ input or the output), not on every save.
353
+
354
+ ## Common mistakes
355
+
356
+ 1. **Building a flow without asking what goes in and comes out.** The pack's
357
+ `EchoFlow` proves the runtime works. It isn't a template for the user's
358
+ flow.
359
+ 2. **A second comparison for "otherwise".** On a path that may be missing,
360
+ `eq` is false and `ne` is true, and `lt`/`gt` are both false, so a
361
+ hand-written opposite can miss a case or overlap. Wrap the positive
362
+ condition in `not`: it covers exactly what the first edge doesn't.
363
+ 3. **Reading an agent step's answer at `nodeOutputs.<step>.<field>`.** The
364
+ typed answer is under `.output`: `nodeOutputs.<step>.output.<field>`. An
365
+ agent without an output type has only `text`.
366
+ 4. **A required input component fed by a branch that may not run.** The key
367
+ is left out, the tool's input check fails, and so does the step. Make it
368
+ `@Nullable`.
369
+ 5. **`inputMapping` keys in the wrong spelling.** They're the input's wire
370
+ names: `customer_id` doesn't fill a `customerId` component that has no
371
+ `@JsonProperty("customer_id")`.
372
+ 6. **A `when` given through `set("edges", …)`.** `build()` writes the edges
373
+ you added with `edge(…)`; use `edge(Map.of(…))` for an edge with a
374
+ condition or a policy.
375
+ 7. **A sub-flow node.** A run refuses it (`flow-unbound`) until sub-flows
376
+ are supported.
377
+ 8. **Duplicate node ids inside a loop body.** Ids are unique across the
378
+ whole flow, bodies included.
379
+ 9. **`mutating(false)` on a tool that writes.** A dry run then runs it for
380
+ real, and an approval gate (when it falls back on `mutating`) won't ask
381
+ before it.
382
+ 10. **A read-only tool without `mutating(false)`.** A dry run stops at it,
383
+ and an approval gate asks before it on first use.
384
+
385
+ ## When the framework itself is the problem
386
+
387
+ If the bug is in Kindgi or kindgi-pack (a step's output missing a field, a
388
+ condition that evaluates wrongly, a misleading error) and not in the pack's
389
+ code, load `kindgi-framework-feedback` and file it with
390
+ `./kindgiw feedback write`.