@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,209 @@
1
+ ---
2
+ name: kindgi-java-authoring-guardrails
3
+ description: >
4
+ Covers writing guardrails (safety checks on an agent's turn) for a Kindgi
5
+ pack in Java (`com.kindgi:kindgi-pack`): `Guardrail.define(id)` as a
6
+ `public static final` field, a `(config, trace)` check returning a
7
+ `CheckResult`, `RunTrace`, config records and the values a check runs
8
+ with, actions (halt / retry / escalate / log-only / compensate), severity
9
+ and scope, unit tests with `evaluate`, and wiring a guardrail onto an
10
+ agent. Load this whenever you are authoring or editing code in a Java
11
+ pack's guardrails packages (a pack whose `kindgi.config.json` says
12
+ `"language": "java"`), defining a check, or wiring a guardrail onto an
13
+ agent. Java agents are covered by kindgi-java-authoring-agents, Java tools
14
+ by kindgi-java-authoring-tools.
15
+ type: core
16
+ library: "kindgi-pack (Java)"
17
+ version: "0.1.0"
18
+ sdk_version: "0.1.5-rc.0"
19
+ pack_languages: [java]
20
+ sources:
21
+ - sdks/java/kindgi-pack/README.md
22
+ - sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/Guardrail.java
23
+ - sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/RunTrace.java
24
+ ---
25
+
26
+ # Authoring Kindgi guardrails in Java
27
+
28
+ > **Running `kindgi`:** the pack pins its CLI (`"cli"` in
29
+ > `kindgi.config.json`), and `./kindgiw` runs that version, so every
30
+ > `kindgi <command>` below runs as `./kindgiw <command>`. Maven runs as
31
+ > `./mvnw`.
32
+ >
33
+ > Java support is in preview: tested and supported, but the API may still
34
+ > change in 0.1.6 without the usual deprecation period.
35
+
36
+ A **guardrail** is a rule an agent's turn must satisfy: a **check** (a
37
+ function over the turn's trace) plus an **action** (what happens when it
38
+ fails). In a Java pack it is a `public static final Guardrail<C>` field of a
39
+ class in a `guardrails` package. For an agent turn, the runtime evaluates
40
+ every guardrail the agent lists once, on the final answer, before it is
41
+ stored.
42
+
43
+ Ask what the rule should catch before writing one. The sample
44
+ `response-not-empty` guardrail is a demonstration, not a template.
45
+
46
+ ## A guardrail
47
+
48
+ ```java
49
+ // src/main/java/acme/guardrails/Citations.java
50
+ package acme.guardrails;
51
+
52
+ import com.fasterxml.jackson.annotation.JsonProperty;
53
+ import com.kindgi.pack.CheckResult;
54
+ import com.kindgi.pack.Guardrail;
55
+ import jakarta.validation.constraints.Min;
56
+ import java.util.Map;
57
+
58
+ /** acme.no-fabricated-quotes: an answer that quotes case law looked the citations up. */
59
+ public final class Citations {
60
+ public record Config(@JsonProperty(defaultValue = "1") @Min(0) int minLookups) {}
61
+
62
+ public static final Guardrail<Config> NO_FABRICATED_QUOTES = Guardrail.define("acme.no-fabricated-quotes")
63
+ .name("No fabricated quotations")
64
+ .onViolation("halt")
65
+ .severity("critical")
66
+ .config(Config.class)
67
+ // What the check runs with, keyed as on the wire.
68
+ .set("config", Map.of("minLookups", 2))
69
+ .check((config, trace) -> {
70
+ long lookups = trace.toolCalls().stream()
71
+ .map(call -> (Map<?, ?>) call)
72
+ .filter(call -> "acme.verify-citation".equals(call.get("toolName")))
73
+ .count();
74
+ return lookups >= config.minLookups()
75
+ ? CheckResult.pass()
76
+ : CheckResult.fail("Only " + lookups + " citation lookups (need " + config.minLookups() + "+).");
77
+ });
78
+
79
+ private Citations() {}
80
+ }
81
+ ```
82
+
83
+ - **The check** is `(config, trace) -> CheckResult`: `CheckResult.pass()`
84
+ or `CheckResult.fail(reason)`. A failed result's reason is what the
85
+ violation reports, so make it say what was wrong. A check built on futures
86
+ uses `asyncCheck` and returns a `CompletionStage<CheckResult>`.
87
+ - **`trace`** is a `RunTrace`:
88
+ - `output()`: the final answer's text;
89
+ - `userInput()`;
90
+ - `toolCalls()`: each a map with `toolId`, `toolName`, `arguments`;
91
+ - `toolResults()`: each with `toolCallId`, `output`;
92
+ - `modelCalls()`;
93
+ - `mode()`: `runtime` or `ci`;
94
+ - `runId()`, `tenantId()`;
95
+ - `raw()`: the trace as sent, with any field a newer runtime adds.
96
+ - **`config(Type.class)`** is the config's type. Its schema is derived as a
97
+ tool input's is, and the service binds the values to it. A
98
+ `@JsonProperty(defaultValue = …)` is the value when none is given.
99
+ `configSchema(Map)` gives a schema instead; the config is then a `Map`.
100
+ - **`set("config", Map.of(…))`** holds the values the check runs with,
101
+ keyed as on the wire. They go into the index, and the service checks them
102
+ against the schema before every evaluation. Without them the check runs
103
+ with `{}` and the defaults. So give every field a default: a required
104
+ field with no value fails every evaluation (`input-validation-failed`).
105
+ - An exception thrown from the check fails the evaluation (`handler-throw`).
106
+ For a rule that isn't met, return `CheckResult.fail(…)`.
107
+ - A check gets no model and no provider: it can't call an LLM. Keep it a
108
+ pure function of the trace (fast, deterministic, free).
109
+
110
+ ## `Guardrail.define(id)`
111
+
112
+ - **`id`:** `<pack-id>.<guardrail-name>`, kebab-case. Name the rule as a
113
+ positive assertion: `no-fabricated-quotes`, `response-not-empty`.
114
+ - **`onViolation(action)`:** `halt`, `retry`, `escalate`, `log-only` or
115
+ `compensate`. For one that needs settings, pass the whole object instead,
116
+ with `action(Map.of("on-violation", "retry", "retry", Map.of("maxAttempts", 2)))`.
117
+ The same goes for `escalateTo` and `compensateWith` (a tool id). The
118
+ builder refuses a check with neither.
119
+ - In an agent turn, a failed `halt` guardrail fails the turn
120
+ (`guardrail-violation`), and the answer is not stored.
121
+ - Any other action reports the failure in the turn result's `violations`,
122
+ and the turn completes.
123
+ - In 0.1 the runtime acts only on `halt`: `retry`, `escalate` and
124
+ `compensate` are recorded on the violation, with no second attempt,
125
+ escalation or compensating call.
126
+ - **`severity`:** `info`, `warn`, `error` (default) or `critical`. It's
127
+ independent of the action: dashboards group by severity, and execution
128
+ follows the action.
129
+ - **`set("scope", Map.of("when", "runtime-only"))`:** when the guardrail
130
+ applies: `always`, `ci-only` or `runtime-only`, narrowed by `agents`,
131
+ `flows` and `tenants` lists.
132
+ - **`name`:** a display name. **`checkId`:** defaults to the id.
133
+ - **`kind`:** `zero-llm`, the default: a check over the trace, which is what
134
+ a pack writes.
135
+ - `set("sandbox" | "limits" | "network", …)` are recorded in the index.
136
+
137
+ ## Testing
138
+
139
+ `evaluate` runs the check with the config as given, with no schema check
140
+ and no defaults. An async check is awaited.
141
+
142
+ ```java
143
+ // src/test/java/acme/CitationsTest.java
144
+ package acme;
145
+
146
+ import static org.junit.jupiter.api.Assertions.assertFalse;
147
+ import static org.junit.jupiter.api.Assertions.assertTrue;
148
+
149
+ import acme.guardrails.Citations;
150
+ import com.kindgi.pack.RunTrace;
151
+ import java.util.List;
152
+ import java.util.Map;
153
+ import org.junit.jupiter.api.Test;
154
+
155
+ class CitationsTest {
156
+ @Test
157
+ void noLookupsFails() throws Exception {
158
+ RunTrace trace = new RunTrace(Map.of("output", "As held in Smith v. Jones…"));
159
+ assertFalse(Citations.NO_FABRICATED_QUOTES.evaluate(new Citations.Config(1), trace).passed());
160
+ }
161
+
162
+ @Test
163
+ void enoughLookupsPass() throws Exception {
164
+ Map<String, Object> lookup = Map.of("toolName", "acme.verify-citation", "arguments", Map.of());
165
+ RunTrace trace = new RunTrace(Map.of("toolCalls", List.of(lookup, lookup)));
166
+ assertTrue(Citations.NO_FABRICATED_QUOTES.evaluate(new Citations.Config(2), trace).passed());
167
+ }
168
+ }
169
+ ```
170
+
171
+ `new RunTrace(Map)` takes the trace as the runtime sends it, camelCase keys
172
+ included.
173
+
174
+ ## Wiring onto an agent
175
+
176
+ ```java
177
+ Agent.define("acme.brief-writer")
178
+ // …
179
+ .guardrail(Citations.NO_FABRICATED_QUOTES)
180
+ ```
181
+
182
+ Pass the `Guardrail`, or its id (`.guardrail("acme.no-fabricated-quotes")`).
183
+ `kindgi dev` registers the pack's guardrails. An agent that names an id with
184
+ no registered guardrail fails the turn before the model is called
185
+ (`Agent "…" references guardrails not in the registry: <id>`).
186
+
187
+ ## Common mistakes
188
+
189
+ 1. **A required config field with no value.** Without `set("config", …)`,
190
+ the check runs with `{}`. Give the field a default
191
+ (`@JsonProperty(defaultValue = "1")`), or the guardrail its values.
192
+ 2. **`set("config", …)` keyed by Java names.** It's keyed like the wire: the
193
+ record's Jackson names.
194
+ 3. **No `onViolation` or `action`.** The builder refuses the check.
195
+ 4. **Expecting another attempt.** `halt` stops the turn, and in 0.1 `retry`
196
+ doesn't run the turn again: it's only recorded.
197
+ 5. **Calling a model from the check.** That isn't available: keep checks
198
+ pure.
199
+ 6. **Throwing for a broken rule.** Return `CheckResult.fail(…)`. An
200
+ exception is an evaluation error, not a violation.
201
+ 7. **A guardrail that isn't a `static final` field**, or a public class in
202
+ a `guardrails` package that defines none (a file error). A helper there
203
+ is package-private, or a record, an enum or an interface.
204
+
205
+ ## When the framework itself is the problem
206
+
207
+ If the bug is in Kindgi or kindgi-pack (a trace field missing, a misleading
208
+ error) and not in the check, load `kindgi-framework-feedback` and file it
209
+ with `./kindgiw feedback write`.
@@ -0,0 +1,334 @@
1
+ ---
2
+ name: kindgi-java-authoring-tools
3
+ description: >
4
+ Covers writing tools for a Kindgi pack in Java (`com.kindgi:kindgi-pack`):
5
+ `Tool.define(id)` as a `public static final` field, input and output
6
+ schemas from records (Jakarta Validation constraints become keywords) or
7
+ a JSON Schema map, `handler` and `asyncHandler`, `ToolContext` and
8
+ cancellation, secrets (`needsSpec`) and configuration, errors,
9
+ `mutating(false)` and effects, unit tests with `Tool.call`, and wiring a
10
+ tool onto an agent. Load this whenever you are authoring or editing code
11
+ in a Java pack's tools packages (a pack whose `kindgi.config.json` says
12
+ `"language": "java"`), defining a tool, or wiring one onto an agent.
13
+ Java agents are covered by kindgi-java-authoring-agents, getting started
14
+ by kindgi-java-getting-started.
15
+ type: core
16
+ library: "kindgi-pack (Java)"
17
+ version: "0.1.0"
18
+ sdk_version: "0.1.5-rc.0"
19
+ pack_languages: [java]
20
+ sources:
21
+ - sdks/java/kindgi-pack/README.md
22
+ - sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/Tool.java
23
+ - sdks/java/kindgi-pack/src/main/java/com/kindgi/pack/ToolContext.java
24
+ ---
25
+
26
+ # Authoring Kindgi tools in Java
27
+
28
+ > **Running `kindgi`:** the pack pins its CLI (`"cli"` in
29
+ > `kindgi.config.json`), and `./kindgiw` runs that version, so every
30
+ > `kindgi <command>` below runs as `./kindgiw <command>` (`kindgiw.cmd` on
31
+ > Windows). Maven runs as `./mvnw` (or the app's own `mvn`).
32
+ >
33
+ > Java support is in preview: tested and supported, but the API may still
34
+ > change in 0.1.6 without the usual deprecation period.
35
+
36
+ A **tool** is a unit of work an agent (or a flow step) calls: typed input,
37
+ typed output, your code in between. In a Java pack it is a
38
+ `public static final Tool<I, O>` field of a class in a `tools` package
39
+ (`src/main/java/**/tools/**/*.java`; in an app, `**/kindgi/tools/**`). Kindgi
40
+ runs it in the pack's own JVM (the pack service) and calls it over HTTP; the
41
+ model sees its id, description and input schema.
42
+
43
+ Before writing one, establish what it should **do**: what it computes or
44
+ fetches, what the caller provides, what it returns. "Add a tool" is a
45
+ conversation opener. The pack's sample tools prove the runtime works; they
46
+ are not the shape to copy unless the user asks.
47
+
48
+ ## A tool
49
+
50
+ ```java
51
+ // src/main/java/acme/tools/VerifyCitation.java
52
+ package acme.tools;
53
+
54
+ import com.kindgi.pack.Tool;
55
+ import jakarta.validation.constraints.Pattern;
56
+ import jakarta.validation.constraints.Size;
57
+ import java.io.IOException;
58
+ import java.util.Map;
59
+ import org.jspecify.annotations.Nullable;
60
+
61
+ /** acme.verify-citation: checks a legal citation against the citator. */
62
+ public final class VerifyCitation {
63
+ public record Input(
64
+ @Size(min = 1) String citation,
65
+ @Pattern(regexp = "^(US|UK|EU)$") String jurisdiction) {}
66
+
67
+ public record Output(boolean found, @Nullable String canonicalCite) {}
68
+
69
+ public static final Tool<Input, Output> TOOL = Tool.define("acme.verify-citation")
70
+ .description("Verifies a legal citation against the citator; returns whether it resolves and its canonical form.")
71
+ .input(Input.class)
72
+ .output(Output.class)
73
+ .mutating(false)
74
+ .set("needsSpec", Map.of("secrets", Map.of("CITATOR_KEY", Map.of("type", "string", "minLength", 20))))
75
+ .handler((input, ctx) ->
76
+ verify(input, (String) ctx.secrets().get("CITATOR_KEY"), System.getenv("CITATOR_URL")));
77
+
78
+ /** The tool's work, with what it reads from its context and the environment passed in: a test calls it. */
79
+ public static Output verify(Input input, String key, String citatorUrl) throws IOException, InterruptedException {
80
+ String hit = Citator.lookup(citatorUrl, key, input.citation(), input.jurisdiction());
81
+ return new Output(hit != null, hit);
82
+ }
83
+
84
+ private VerifyCitation() {}
85
+ }
86
+ ```
87
+
88
+ ```java
89
+ // src/main/java/acme/tools/Citator.java
90
+ package acme.tools;
91
+
92
+ import java.io.IOException;
93
+ import java.net.URI;
94
+ import java.net.URLEncoder;
95
+ import java.net.http.HttpClient;
96
+ import java.net.http.HttpRequest;
97
+ import java.net.http.HttpResponse;
98
+ import java.nio.charset.StandardCharsets;
99
+ import org.jspecify.annotations.Nullable;
100
+
101
+ /** The citator's API. Package-private: a helper, not a primitive. */
102
+ final class Citator {
103
+ private static final HttpClient HTTP = HttpClient.newHttpClient();
104
+
105
+ static @Nullable String lookup(String baseUrl, String key, String citation, String jurisdiction)
106
+ throws IOException, InterruptedException {
107
+ String query = "q=" + URLEncoder.encode(citation, StandardCharsets.UTF_8) + "&j=" + jurisdiction;
108
+ HttpRequest request = HttpRequest.newBuilder(URI.create(baseUrl + "/lookup?" + query))
109
+ .header("Authorization", "Bearer " + key)
110
+ .build();
111
+ HttpResponse<String> response = HTTP.send(request, HttpResponse.BodyHandlers.ofString());
112
+ return response.statusCode() == 200 ? response.body() : null;
113
+ }
114
+
115
+ private Citator() {}
116
+ }
117
+ ```
118
+
119
+ - **Where it lives:** a `public static final` field of a class in a `tools`
120
+ package. The indexer loads the class and takes the tools its static fields
121
+ hold. A tool built in a method, or held by an instance field, is never
122
+ found.
123
+ - **Id:** `<pack-id>.<tool-name>`, kebab-case, dot-namespaced.
124
+ - **Description:** what it does and returns. The model reads it to decide
125
+ when to call the tool. It isn't enforced, so never leave it out.
126
+ - **Version:** the pack's (`pack.version`), or `.version("1.2.0")` (an exact
127
+ semver).
128
+ - **Schemas:** from the records `input(…)` and `output(…)` name. A record's
129
+ components are the object's properties, by their Jackson names
130
+ (`@JsonProperty("canonicalCite")` renames one). Unknown properties are
131
+ refused unless the type says `@JsonIgnoreProperties(ignoreUnknown = true)`.
132
+ The input must be an **object**: a model calls a tool with an object of
133
+ arguments.
134
+
135
+ | In Java | In the schema |
136
+ |---|---|
137
+ | `String`, `int`/`long`, `double`/`BigDecimal`, `boolean` | `string`, `integer`, `number`, `boolean` |
138
+ | `@Nullable T`, `Optional<T>` | not required; `null` allowed |
139
+ | `@JsonProperty(defaultValue = "1")` | `default: 1`, not required; the service fills it in |
140
+ | `List<T>`, `Set<T>`, `T[]`; `Map<String, T>` | `array`; `object` with `additionalProperties` |
141
+ | an enum; `UUID`, `Instant`, `LocalDate`, `URI` | `enum`; `string` with its `format` |
142
+ | `@JsonPropertyDescription` | `description` |
143
+ | `@Size`, `@Min`, `@Max`, `@Pattern`, `@Email`, `@NotBlank`, `@Positive`, … | the matching keywords |
144
+
145
+ A type that can't be a schema (a recursive record, a map with non-string
146
+ keys) is a file error naming the property. When a type can't say it, pass
147
+ the schema itself, `input(Map.of("type", "object", …))`, and the handler
148
+ gets a `Map`.
149
+ - **Handler:** `(input, ctx) -> output`. It may throw. It runs on a thread of
150
+ its own, so blocking I/O is fine. A handler built on futures uses
151
+ `asyncHandler((input, ctx) -> stage)` and returns a `CompletionStage`; the
152
+ service awaits it.
153
+ - **Validation:** before the handler runs, the input is checked against the
154
+ schema (its defaults filled in). Then what the handler returns is checked
155
+ against the output schema. A bad input comes back as
156
+ `input-validation-failed`, naming the field (a bad output as
157
+ `output-validation-failed`). The agent's `toolErrors` policy decides
158
+ whether the model gets to fix the call.
159
+
160
+ ## `ToolContext`
161
+
162
+ - `ctx.tenantId()`: the tenant the call is for. Key per-tenant state by it.
163
+ - `ctx.runId()`: the run (an agent turn or a flow step) the call belongs to.
164
+ - `ctx.requestId()`: this call, such as the model's tool-call id. Useful for
165
+ logs and idempotency keys.
166
+ - `ctx.projectId()`, `ctx.orgId()`: the run's project, and its org (`null`
167
+ when it has none). The runtime sets them from the run, never from the
168
+ input. To check an id the input names, compare it with these.
169
+ - `ctx.cancellation()` fires when the call's deadline passes (120 s by
170
+ default) or the caller goes away. The handler's thread is interrupted too,
171
+ so a blocking wait ends. A loop checks `isCancelled()` or calls
172
+ `throwIfCancelled()`. Work started elsewhere (a request, a job) stops with
173
+ `onCancel(action)`.
174
+ - `ctx.secrets()`: the secrets the tool declares (below). Printing the
175
+ context shows their names, never their values.
176
+ - `ctx.env()`, `ctx.config()`: **reserved, empty today**.
177
+
178
+ ## Configuration and secrets
179
+
180
+ A secret that belongs to the tenant, such as an API key a customer gives
181
+ you, is declared with `set("needsSpec", …)` and read from `ctx.secrets()`, as
182
+ above. The runtime resolves every declared secret on every call, for the
183
+ call's tenant, in its env (`KINDGI_ENV`; under `kindgi dev`, `local`: the
184
+ pack's `.env` and `.env.local`). It checks each against its schema, and fails
185
+ the call, naming the secret, when one is missing or doesn't match. Every
186
+ declared secret is required.
187
+
188
+ Everything else comes from the process environment: `System.getenv("CITATOR_URL")`.
189
+ Under `kindgi dev`, the pack service gets the pack's `.env` and `.env.local`,
190
+ and restarts when they change. Nothing else from your shell reaches it
191
+ except `PATH`, `HOME` and `TMPDIR`; `MAVEN_ARGS` and `MAVEN_OPTS` reach Maven
192
+ only. Put a secret there by hand, or with
193
+ `./kindgiw secrets set NAME --env=local --scope=tenant` (a no-echo prompt),
194
+ and keep the env files out of git. A deployed service names the variables
195
+ it needs in `kindgi.config.json`: `"env": {"required": ["DATABASE_URL"],
196
+ "optional": ["SENTRY_DSN"]}`. Without a required one it isn't ready.
197
+ `KINDGI_*` names are Kindgi's own and never reach pack code.
198
+
199
+ ## Errors and output
200
+
201
+ - Throw for a failure: the call fails with `handler-throw` and the
202
+ exception's message. In an agent turn, the model sees the failure only
203
+ when the agent's `toolErrors` policy includes `tool-error`, so retrying
204
+ must be safe for that tool.
205
+ - What the handler logs (your app's logger, `System.err`) goes to the pack
206
+ service's output (`kindgi dev` shows it as `[pack] …`), never into a
207
+ result.
208
+
209
+ ## Other declarations
210
+
211
+ **`mutating(false)`** declares a tool read-only: it changes nothing outside
212
+ itself (a lookup, a search, a calculation). A dry run
213
+ (`./kindgiw runs start --dry-run`) runs it. Leave it unset for anything that
214
+ writes, sends, charges or deletes: such a tool stops a dry run. It's also
215
+ the tool's approval default: an agent that turns approval gates on
216
+ (`conversationPolicy.hitl`) asks before any tool that isn't read-only on its
217
+ first use.
218
+
219
+ `effect(kind, resource)` declares a side effect, such as
220
+ `.effect("writes", "db:ledger")`. A dry run also stops at a tool with a
221
+ `writes`, `deletes`, `spawns-run`, `emits-event` or `external-side-effect`
222
+ effect. `set(field, value)` sets the index entry's other fields: `needs`,
223
+ `needsSpec`, `sandbox`, `limits`, `network`. They are recorded for policy and
224
+ review, so declare what the tool really does.
225
+
226
+ Java has no HTTP-tool form (TypeScript's `kind: 'http'`). A tool that calls
227
+ an HTTP API is a handler with `java.net.http.HttpClient`, as above.
228
+
229
+ ## Testing
230
+
231
+ `Tool.call(input, ctx)` runs the handler with the input as given (no schema
232
+ check). `ToolContext.forTest()` is a context with a test tenant and run and
233
+ nothing else; `new ToolContext(…)` builds one with secrets:
234
+
235
+ ```java
236
+ ToolContext ctx = new ToolContext("t-test", "run-test", null, null, null,
237
+ Map.of(), Map.of("CITATOR_KEY", "test-key-of-twenty-chars"), Map.of(), Map.of(), new Cancellation());
238
+ Greet.Output out = Greet.TOOL.call(new Greet.Input("Ada", "Hi"), ctx);
239
+ ```
240
+
241
+ A Java test can't set an environment variable, so a handler that reads one
242
+ (`CITATOR_URL`) and calls a service is tested through the method it calls,
243
+ with a stub server:
244
+
245
+ ```java
246
+ // src/test/java/acme/VerifyCitationTest.java
247
+ package acme;
248
+
249
+ import static org.junit.jupiter.api.Assertions.assertFalse;
250
+
251
+ import acme.tools.VerifyCitation;
252
+ import com.sun.net.httpserver.HttpServer;
253
+ import java.net.InetSocketAddress;
254
+ import org.junit.jupiter.api.Test;
255
+
256
+ class VerifyCitationTest {
257
+ @Test
258
+ void anUnknownCitationIsNotFound() throws Exception {
259
+ HttpServer citator = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
260
+ citator.createContext("/lookup", exchange -> {
261
+ exchange.sendResponseHeaders(404, -1);
262
+ exchange.close();
263
+ });
264
+ citator.start();
265
+ try {
266
+ String url = "http://127.0.0.1:" + citator.getAddress().getPort();
267
+ assertFalse(VerifyCitation.verify(new VerifyCitation.Input("1 U.S. 1", "US"), "test-key", url).found());
268
+ } finally {
269
+ citator.stop(0);
270
+ }
271
+ }
272
+ }
273
+ ```
274
+
275
+ `./mvnw test` runs the tests (`*Test.java`, `*IT.java` and anything under
276
+ `src/test/` are never indexed). To see the schemas Kindgi derives:
277
+
278
+ ```sh
279
+ ./mvnw -q compile dependency:build-classpath -Dmdep.outputFile=target/classpath.txt
280
+ java -cp "target/classes:$(cat target/classpath.txt)" com.kindgi.pack.Main index --pack-dir .
281
+ ```
282
+
283
+ ## Wiring the tool onto an agent
284
+
285
+ Pass the `Tool`, which pins that tool's version:
286
+
287
+ ```java
288
+ Agent.define("acme.brief-writer")
289
+ // …
290
+ .tool(VerifyCitation.TOOL)
291
+ ```
292
+
293
+ A tool of another pack is `.tool("other.lookup", "^1.0.0")`: its id and a
294
+ semver **range**, and the highest active version matching it is picked at
295
+ turn start. In a flow, `toolNode("verify", VerifyCitation.TOOL)` runs it.
296
+
297
+ ## Iterating
298
+
299
+ Save the file. `kindgi dev` recompiles with Maven, and the next call runs the
300
+ new code. A compile error is reported as `file:line:col`, and the last good
301
+ code keeps serving. Bump the version when callers' contract changes (a
302
+ removed field, a narrower type), not on every save.
303
+
304
+ ## Common mistakes
305
+
306
+ 1. **Copying the sample tool's shape without asking what the tool should do.**
307
+ 2. **A tool that isn't a `static final` field.** An instance field, a local
308
+ variable or a method's return value is never indexed.
309
+ 3. **A public class in a `tools` package that defines no tool.** It's a file
310
+ error, so a forgotten `static` can't drop a tool silently. Make a helper
311
+ package-private, or a record, an enum or an interface.
312
+ 4. **No description.** The model can't tell when to call the tool.
313
+ 5. **Reading `ctx.env()` or `ctx.config()`, or an undeclared secret.** The
314
+ first two are empty, and `ctx.secrets()` holds only what `needsSpec`
315
+ declares. Use `System.getenv` for the rest.
316
+ 6. **A non-object input** (`input(String.class)`). The input is a record, a
317
+ bean, or an object schema.
318
+ 7. **A class the tool uses with `test` or `provided` scope.** It works under
319
+ `kindgi dev` and fails in the image, which copies the runtime classpath
320
+ only. Use `compile` or `runtime` scope.
321
+ 8. **A read-only tool without `mutating(false)`.** A dry run stops at it, and
322
+ an approval gate asks before it on first use.
323
+ 9. **`mutating(false)` on a tool that writes.** A dry run then runs it for
324
+ real.
325
+ 10. **A Jackson module registered only in code, on your own `ObjectMapper`.**
326
+ kindgi-pack finds modules as `findAndRegisterModules()` does, through
327
+ `META-INF/services`. Declare it there, or the tool's input and schema
328
+ won't see it.
329
+
330
+ ## When the framework itself is the problem
331
+
332
+ If the bug is in Kindgi or kindgi-pack (a schema derived wrong, a misleading
333
+ error, the pack service misbehaving) and not in the tool's code, load
334
+ `kindgi-framework-feedback` and file it with `./kindgiw feedback write`.