deepclause-sdk 0.0.88 → 0.1.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 (318) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +418 -914
  3. package/dist/agent.d.ts +19 -2
  4. package/dist/agent.d.ts.map +1 -1
  5. package/dist/agent.js +221 -4
  6. package/dist/agent.js.map +1 -1
  7. package/dist/cli/config.d.ts +323 -176
  8. package/dist/cli/config.d.ts.map +1 -1
  9. package/dist/cli/config.js +146 -188
  10. package/dist/cli/config.js.map +1 -1
  11. package/dist/cli/index.d.ts +3 -2
  12. package/dist/cli/index.d.ts.map +1 -1
  13. package/dist/cli/index.js +61 -425
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/cli/login.d.ts +29 -0
  16. package/dist/cli/login.d.ts.map +1 -0
  17. package/dist/cli/login.js +184 -0
  18. package/dist/cli/login.js.map +1 -0
  19. package/dist/cli/readline.d.ts +6 -0
  20. package/dist/cli/readline.d.ts.map +1 -0
  21. package/dist/cli/readline.js +15 -0
  22. package/dist/cli/readline.js.map +1 -0
  23. package/dist/cli/repl-bin.d.ts +9 -0
  24. package/dist/cli/repl-bin.d.ts.map +1 -0
  25. package/dist/cli/repl-bin.js +16 -0
  26. package/dist/cli/repl-bin.js.map +1 -0
  27. package/dist/cli/repl.d.ts +191 -0
  28. package/dist/cli/repl.d.ts.map +1 -0
  29. package/dist/cli/repl.js +1232 -0
  30. package/dist/cli/repl.js.map +1 -0
  31. package/dist/cli/run.d.ts +17 -18
  32. package/dist/cli/run.d.ts.map +1 -1
  33. package/dist/cli/run.js +196 -183
  34. package/dist/cli/run.js.map +1 -1
  35. package/dist/cli/set-backend.d.ts +53 -0
  36. package/dist/cli/set-backend.d.ts.map +1 -0
  37. package/dist/cli/set-backend.js +259 -0
  38. package/dist/cli/set-backend.js.map +1 -0
  39. package/dist/cli/visualize.d.ts +38 -0
  40. package/dist/cli/visualize.d.ts.map +1 -0
  41. package/dist/cli/visualize.js +125 -0
  42. package/dist/cli/visualize.js.map +1 -0
  43. package/dist/compiler.d.ts +5 -52
  44. package/dist/compiler.d.ts.map +1 -1
  45. package/dist/compiler.js +4 -768
  46. package/dist/compiler.js.map +1 -1
  47. package/dist/index.d.ts +29 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +20 -2
  50. package/dist/index.js.map +1 -1
  51. package/dist/judge/index.d.ts +9 -0
  52. package/dist/judge/index.d.ts.map +1 -0
  53. package/dist/judge/index.js +6 -0
  54. package/dist/judge/index.js.map +1 -0
  55. package/dist/judge/jev.d.ts +21 -0
  56. package/dist/judge/jev.d.ts.map +1 -0
  57. package/dist/judge/jev.js +218 -0
  58. package/dist/judge/jev.js.map +1 -0
  59. package/dist/judge/llm.d.ts +23 -0
  60. package/dist/judge/llm.d.ts.map +1 -0
  61. package/dist/judge/llm.js +120 -0
  62. package/dist/judge/llm.js.map +1 -0
  63. package/dist/judge/marshal.d.ts +26 -0
  64. package/dist/judge/marshal.d.ts.map +1 -0
  65. package/dist/judge/marshal.js +266 -0
  66. package/dist/judge/marshal.js.map +1 -0
  67. package/dist/judge/mock.d.ts +28 -0
  68. package/dist/judge/mock.d.ts.map +1 -0
  69. package/dist/judge/mock.js +98 -0
  70. package/dist/judge/mock.js.map +1 -0
  71. package/dist/judge/types.d.ts +95 -0
  72. package/dist/judge/types.d.ts.map +1 -0
  73. package/dist/judge/types.js +23 -0
  74. package/dist/judge/types.js.map +1 -0
  75. package/dist/prolog/bridge.d.ts +5 -1
  76. package/dist/prolog/bridge.d.ts.map +1 -1
  77. package/dist/prolog/bridge.js +29 -1
  78. package/dist/prolog/bridge.js.map +1 -1
  79. package/dist/prolog-src/deepclause_analysis.pl +10 -2
  80. package/dist/prolog-src/deepclause_mi.pl +2522 -118
  81. package/dist/repl/agent.d.ts +72 -0
  82. package/dist/repl/agent.d.ts.map +1 -0
  83. package/dist/repl/agent.js +366 -0
  84. package/dist/repl/agent.js.map +1 -0
  85. package/dist/repl/auth.d.ts +45 -0
  86. package/dist/repl/auth.d.ts.map +1 -0
  87. package/dist/repl/auth.js +116 -0
  88. package/dist/repl/auth.js.map +1 -0
  89. package/dist/repl/backend.d.ts +290 -0
  90. package/dist/repl/backend.d.ts.map +1 -0
  91. package/dist/repl/backend.js +370 -0
  92. package/dist/repl/backend.js.map +1 -0
  93. package/dist/repl/compaction.d.ts +122 -0
  94. package/dist/repl/compaction.d.ts.map +1 -0
  95. package/dist/repl/compaction.js +318 -0
  96. package/dist/repl/compaction.js.map +1 -0
  97. package/dist/repl/export.d.ts +30 -0
  98. package/dist/repl/export.d.ts.map +1 -0
  99. package/dist/repl/export.js +23 -0
  100. package/dist/repl/export.js.map +1 -0
  101. package/dist/repl/frames.d.ts +21 -0
  102. package/dist/repl/frames.d.ts.map +1 -0
  103. package/dist/repl/frames.js +79 -0
  104. package/dist/repl/frames.js.map +1 -0
  105. package/dist/repl/harness-tools.d.ts +74 -0
  106. package/dist/repl/harness-tools.d.ts.map +1 -0
  107. package/dist/repl/harness-tools.js +121 -0
  108. package/dist/repl/harness-tools.js.map +1 -0
  109. package/dist/repl/highlight.d.ts +30 -0
  110. package/dist/repl/highlight.d.ts.map +1 -0
  111. package/dist/repl/highlight.js +285 -0
  112. package/dist/repl/highlight.js.map +1 -0
  113. package/dist/repl/history.d.ts +234 -0
  114. package/dist/repl/history.d.ts.map +1 -0
  115. package/dist/repl/history.js +661 -0
  116. package/dist/repl/history.js.map +1 -0
  117. package/dist/repl/index.d.ts +120 -0
  118. package/dist/repl/index.d.ts.map +1 -0
  119. package/dist/repl/index.js +107 -0
  120. package/dist/repl/index.js.map +1 -0
  121. package/dist/repl/judge.d.ts +51 -0
  122. package/dist/repl/judge.d.ts.map +1 -0
  123. package/dist/repl/judge.js +58 -0
  124. package/dist/repl/judge.js.map +1 -0
  125. package/dist/repl/markdown.d.ts +25 -0
  126. package/dist/repl/markdown.d.ts.map +1 -0
  127. package/dist/repl/markdown.js +103 -0
  128. package/dist/repl/markdown.js.map +1 -0
  129. package/dist/repl/picker.d.ts +34 -0
  130. package/dist/repl/picker.d.ts.map +1 -0
  131. package/dist/repl/picker.js +81 -0
  132. package/dist/repl/picker.js.map +1 -0
  133. package/dist/repl/project-context.d.ts +16 -0
  134. package/dist/repl/project-context.d.ts.map +1 -0
  135. package/dist/repl/project-context.js +23 -0
  136. package/dist/repl/project-context.js.map +1 -0
  137. package/dist/repl/render.d.ts +160 -0
  138. package/dist/repl/render.d.ts.map +1 -0
  139. package/dist/repl/render.js +715 -0
  140. package/dist/repl/render.js.map +1 -0
  141. package/dist/repl/session.d.ts +356 -0
  142. package/dist/repl/session.d.ts.map +1 -0
  143. package/dist/repl/session.js +1275 -0
  144. package/dist/repl/session.js.map +1 -0
  145. package/dist/repl/status.d.ts +100 -0
  146. package/dist/repl/status.d.ts.map +1 -0
  147. package/dist/repl/status.js +218 -0
  148. package/dist/repl/status.js.map +1 -0
  149. package/dist/repl/tools.d.ts +53 -0
  150. package/dist/repl/tools.d.ts.map +1 -0
  151. package/dist/repl/tools.js +307 -0
  152. package/dist/repl/tools.js.map +1 -0
  153. package/dist/repl/toolset.d.ts +32 -0
  154. package/dist/repl/toolset.d.ts.map +1 -0
  155. package/dist/repl/toolset.js +82 -0
  156. package/dist/repl/toolset.js.map +1 -0
  157. package/dist/repl/tui/editor.d.ts +17 -0
  158. package/dist/repl/tui/editor.d.ts.map +1 -0
  159. package/dist/repl/tui/editor.js +39 -0
  160. package/dist/repl/tui/editor.js.map +1 -0
  161. package/dist/repl/tui/status-bar.d.ts +26 -0
  162. package/dist/repl/tui/status-bar.d.ts.map +1 -0
  163. package/dist/repl/tui/status-bar.js +47 -0
  164. package/dist/repl/tui/status-bar.js.map +1 -0
  165. package/dist/repl/tui/theme.d.ts +30 -0
  166. package/dist/repl/tui/theme.d.ts.map +1 -0
  167. package/dist/repl/tui/theme.js +81 -0
  168. package/dist/repl/tui/theme.js.map +1 -0
  169. package/dist/repl/tui/transcript.d.ts +39 -0
  170. package/dist/repl/tui/transcript.d.ts.map +1 -0
  171. package/dist/repl/tui/transcript.js +123 -0
  172. package/dist/repl/tui/transcript.js.map +1 -0
  173. package/dist/runner.d.ts +145 -13
  174. package/dist/runner.d.ts.map +1 -1
  175. package/dist/runner.js +600 -282
  176. package/dist/runner.js.map +1 -1
  177. package/dist/sdk.d.ts.map +1 -1
  178. package/dist/sdk.js +56 -32
  179. package/dist/sdk.js.map +1 -1
  180. package/dist/system/assets/docs/AGENT_PROMPT.md +1373 -0
  181. package/dist/system/assets/docs/DML_AUTHORING.md +195 -0
  182. package/dist/system/assets/docs/DML_REFERENCE.md +393 -72
  183. package/dist/system/assets/docs/HARNESS_EXAMPLES.md +172 -0
  184. package/dist/system/assets/docs/HARNESS_PATTERNS.md +562 -0
  185. package/dist/system/assets/docs/META_PROMPT.md +68 -0
  186. package/dist/system/assets/docs/PROLOG_SNIPPETS.md +117 -0
  187. package/dist/system/assets/index.d.ts +9 -17
  188. package/dist/system/assets/index.d.ts.map +1 -1
  189. package/dist/system/assets/index.js +26 -85
  190. package/dist/system/assets/index.js.map +1 -1
  191. package/dist/system/runtime/agentvm-manager.d.ts +9 -2
  192. package/dist/system/runtime/agentvm-manager.d.ts.map +1 -1
  193. package/dist/system/runtime/agentvm-manager.js +70 -44
  194. package/dist/system/runtime/agentvm-manager.js.map +1 -1
  195. package/dist/system/runtime/media.d.ts +23 -0
  196. package/dist/system/runtime/media.d.ts.map +1 -0
  197. package/dist/system/runtime/media.js +55 -0
  198. package/dist/system/runtime/media.js.map +1 -0
  199. package/dist/system/runtime/shell-limits.d.ts +21 -0
  200. package/dist/system/runtime/shell-limits.d.ts.map +1 -0
  201. package/dist/system/runtime/shell-limits.js +39 -0
  202. package/dist/system/runtime/shell-limits.js.map +1 -0
  203. package/dist/system/runtime/shell-manager.d.ts +8 -3
  204. package/dist/system/runtime/shell-manager.d.ts.map +1 -1
  205. package/dist/system/runtime/shell-manager.js +56 -39
  206. package/dist/system/runtime/shell-manager.js.map +1 -1
  207. package/dist/system/runtime/shell-tool-events.js +5 -0
  208. package/dist/system/runtime/shell-tool-events.js.map +1 -1
  209. package/dist/system/runtime/token-usage.d.ts +2 -0
  210. package/dist/system/runtime/token-usage.d.ts.map +1 -1
  211. package/dist/system/runtime/token-usage.js +7 -0
  212. package/dist/system/runtime/token-usage.js.map +1 -1
  213. package/dist/tools.d.ts +3 -21
  214. package/dist/tools.d.ts.map +1 -1
  215. package/dist/tools.js +14 -168
  216. package/dist/tools.js.map +1 -1
  217. package/dist/types.d.ts +149 -118
  218. package/dist/types.d.ts.map +1 -1
  219. package/dist/validate.d.ts +19 -0
  220. package/dist/validate.d.ts.map +1 -0
  221. package/dist/validate.js +338 -0
  222. package/dist/validate.js.map +1 -0
  223. package/dist/visualize/index.d.ts +52 -0
  224. package/dist/visualize/index.d.ts.map +1 -0
  225. package/dist/visualize/index.js +189 -0
  226. package/dist/visualize/index.js.map +1 -0
  227. package/package.json +17 -15
  228. package/src/prolog-src/deepclause_analysis.pl +10 -2
  229. package/src/prolog-src/deepclause_mi.pl +2522 -118
  230. package/dist/cli/commands.d.ts +0 -42
  231. package/dist/cli/commands.d.ts.map +0 -1
  232. package/dist/cli/commands.js +0 -246
  233. package/dist/cli/commands.js.map +0 -1
  234. package/dist/cli/compile.d.ts +0 -99
  235. package/dist/cli/compile.d.ts.map +0 -1
  236. package/dist/cli/compile.js +0 -363
  237. package/dist/cli/compile.js.map +0 -1
  238. package/dist/cli/default-skills.d.ts +0 -10
  239. package/dist/cli/default-skills.d.ts.map +0 -1
  240. package/dist/cli/default-skills.js +0 -206
  241. package/dist/cli/default-skills.js.map +0 -1
  242. package/dist/cli/interactive.d.ts +0 -2
  243. package/dist/cli/interactive.d.ts.map +0 -1
  244. package/dist/cli/interactive.js +0 -20
  245. package/dist/cli/interactive.js.map +0 -1
  246. package/dist/cli/mcp.d.ts +0 -56
  247. package/dist/cli/mcp.d.ts.map +0 -1
  248. package/dist/cli/mcp.js +0 -138
  249. package/dist/cli/mcp.js.map +0 -1
  250. package/dist/cli/prompt.d.ts +0 -2
  251. package/dist/cli/prompt.d.ts.map +0 -1
  252. package/dist/cli/prompt.js +0 -2
  253. package/dist/cli/prompt.js.map +0 -1
  254. package/dist/cli/search.d.ts +0 -19
  255. package/dist/cli/search.d.ts.map +0 -1
  256. package/dist/cli/search.js +0 -189
  257. package/dist/cli/search.js.map +0 -1
  258. package/dist/cli/tool-args.d.ts +0 -2
  259. package/dist/cli/tool-args.d.ts.map +0 -1
  260. package/dist/cli/tool-args.js +0 -39
  261. package/dist/cli/tool-args.js.map +0 -1
  262. package/dist/cli/tools.d.ts +0 -36
  263. package/dist/cli/tools.d.ts.map +0 -1
  264. package/dist/cli/tools.js +0 -229
  265. package/dist/cli/tools.js.map +0 -1
  266. package/dist/cli/tui/index.d.ts +0 -22
  267. package/dist/cli/tui/index.d.ts.map +0 -1
  268. package/dist/cli/tui/index.js +0 -29
  269. package/dist/cli/tui/index.js.map +0 -1
  270. package/dist/cli/tui.d.ts +0 -167
  271. package/dist/cli/tui.d.ts.map +0 -1
  272. package/dist/cli/tui.js +0 -5228
  273. package/dist/cli/tui.js.map +0 -1
  274. package/dist/compiler_prompt.d.ts +0 -20
  275. package/dist/compiler_prompt.d.ts.map +0 -1
  276. package/dist/compiler_prompt.js +0 -870
  277. package/dist/compiler_prompt.js.map +0 -1
  278. package/dist/deepclause-cli.skill +0 -0
  279. package/dist/prolog-src/deepclause_mi.pl.bak +0 -570
  280. package/dist/system/assets/compactors/default-memory-compactor.dml +0 -6
  281. package/dist/system/assets/docs/CONDUCTOR_PROMPT.md +0 -105
  282. package/dist/system/assets/docs/DML_COMPILER_PROMPT.md +0 -700
  283. package/dist/system/assets/docs/TUI.md +0 -150
  284. package/dist/system/assets/recipes/deepclause-coding-workflow/SKILL.md +0 -100
  285. package/dist/system/assets/skills/conductor.dml +0 -76
  286. package/dist/system/assets/skills/deep-planner.dml +0 -412
  287. package/dist/system/assets/skills/plan.dml +0 -429
  288. package/dist/system/assets/skills/security-planner.dml +0 -337
  289. package/dist/system/assets/skills/skill-creator.dml +0 -187
  290. package/dist/system/runtime/catalog-recipes.d.ts +0 -24
  291. package/dist/system/runtime/catalog-recipes.d.ts.map +0 -1
  292. package/dist/system/runtime/catalog-recipes.js +0 -273
  293. package/dist/system/runtime/catalog-recipes.js.map +0 -1
  294. package/dist/system/runtime/catalog-skills.d.ts +0 -50
  295. package/dist/system/runtime/catalog-skills.d.ts.map +0 -1
  296. package/dist/system/runtime/catalog-skills.js +0 -152
  297. package/dist/system/runtime/catalog-skills.js.map +0 -1
  298. package/dist/system/runtime/conductor.d.ts +0 -105
  299. package/dist/system/runtime/conductor.d.ts.map +0 -1
  300. package/dist/system/runtime/conductor.js +0 -732
  301. package/dist/system/runtime/conductor.js.map +0 -1
  302. package/dist/system/runtime/console-capture.d.ts +0 -9
  303. package/dist/system/runtime/console-capture.d.ts.map +0 -1
  304. package/dist/system/runtime/console-capture.js +0 -67
  305. package/dist/system/runtime/console-capture.js.map +0 -1
  306. package/dist/system/runtime/dml-executor.d.ts +0 -52
  307. package/dist/system/runtime/dml-executor.d.ts.map +0 -1
  308. package/dist/system/runtime/dml-executor.js +0 -203
  309. package/dist/system/runtime/dml-executor.js.map +0 -1
  310. package/dist/system/runtime/runtime-tools.d.ts +0 -31
  311. package/dist/system/runtime/runtime-tools.d.ts.map +0 -1
  312. package/dist/system/runtime/runtime-tools.js +0 -312
  313. package/dist/system/runtime/runtime-tools.js.map +0 -1
  314. package/dist/system/runtime/skill-creator.d.ts +0 -38
  315. package/dist/system/runtime/skill-creator.d.ts.map +0 -1
  316. package/dist/system/runtime/skill-creator.js +0 -763
  317. package/dist/system/runtime/skill-creator.js.map +0 -1
  318. package/src/prolog-src/deepclause_mi.pl.bak +0 -570
@@ -14,7 +14,6 @@
14
14
  - [system/1, user/1](#memory-predicates)
15
15
  - [output/1, yield/1, log/1](#output-predicates)
16
16
  - [answer/1](#answer1)
17
- - [param/3](#param3)
18
17
  - [Control Flow](#control-flow)
19
18
  - [String Interpolation](#string-interpolation)
20
19
  - [Backtracking](#backtracking)
@@ -58,7 +57,7 @@ agent_main :-
58
57
  ```
59
58
 
60
59
  ### agent_main/1
61
- Receives the first parameter:
60
+ Receives the first argument:
62
61
  ```prolog
63
62
  agent_main(Name) :-
64
63
  format(string(Msg), "Hello, ~w!", [Name]),
@@ -66,7 +65,7 @@ agent_main(Name) :-
66
65
  ```
67
66
 
68
67
  ### agent_main/2
69
- Receives first two parameters:
68
+ Receives the first two arguments:
70
69
  ```prolog
71
70
  agent_main(Name, Task) :-
72
71
  system("You are a helpful assistant."),
@@ -142,6 +141,23 @@ agent_main :-
142
141
 
143
142
  Bind up to three variables.
144
143
 
144
+ > **Note — `task/N` is load-time sugar.** `task/1,2,3,4` and `prompt/2,3,4` are
145
+ > rewritten by the DML loader into `task_named/3` / `prompt_named/3` with typed
146
+ > output variables. The rewrite runs whenever code is loaded (`deepclause run`,
147
+ > the REPL `-l` and commit paths, `consult`, and the REPL `assert`/`assert_many`
148
+ > tools). The untransformed form has no runtime handler,
149
+ > so code that somehow reaches the runtime without the rewrite raises
150
+ > `domain_error(unrewritten_task_form, Goal)` instead of failing silently.
151
+ > `task/1`/`prompt/1` are handled directly and are unaffected.
152
+
153
+ > **Internal note.** At load time `task/N`/`prompt/N` are rewritten to
154
+ > `task_named/3`/`prompt_named/3` (which carry the output-variable names) and
155
+ > `{Var}` descriptions are hoisted into a `format/3`. That is why a description
156
+ > like `task("Answer: {Question}", Answer)` sometimes *appears* as
157
+ > `format(string(C), "Answer: ~w", [Question]), task_named(C, [Answer], ...)`.
158
+ > `listing` and `export` reverse this, so you always read/write `task/N` and
159
+ > `prompt/N` — never author `task_named/3` yourself.
160
+
145
161
  ### Type-Safe Output Variables
146
162
 
147
163
  You can wrap output variables with type specifiers to enforce strict validation on the LLM's output. The runtime will ensure the value matches the specified type.
@@ -200,38 +216,66 @@ Or positional if the tool supports it:
200
216
  exec(get_time, CurrentTime)
201
217
  ```
202
218
 
219
+ The `bash` tool accepts an optional wall-clock `timeoutMs` and always returns the
220
+ wall-clock duration as `timeMs`:
221
+
222
+ ```prolog
223
+ exec(bash(command: "sleep 30", timeoutMs: 5000), R),
224
+ get_dict(timeMs, R, Took),
225
+ ( get_dict(exitCode, R, 124)
226
+ -> format(string(Msg), "timed out after ~w ms", [Took])
227
+ ; format(string(Msg), "finished in ~w ms", [Took])
228
+ ).
229
+ ```
230
+
231
+ A command is also killed when it produces no output for `DC_HOST_SHELL_IDLE_TIMEOUT_MS`
232
+ (default 180 000 ms); `DC_HOST_SHELL_TIMEOUT_MS` sets a default wall-clock cap
233
+ (0 = disabled). Exit code `124` means a timeout.
234
+
203
235
  ---
204
236
 
205
237
  ### Tool Definitions
206
238
 
207
- Define tools in DML that the LLM can call during `task()`. Tools use the `tool/2` predicate with a description:
239
+ `tool/2` is an **annotation**, not an implementation. It exposes an existing
240
+ harness predicate to the nested agent that runs inside `task/N`. Define the
241
+ predicate normally, then add a `tool/2` clause that delegates to it:
208
242
 
209
243
  ```prolog
210
- % Define a tool - makes it available to the LLM with description
211
- tool(calculate(Expression, Result), "Calculate a mathematical expression") :-
212
- exec(calculator(expression: Expression), Result).
244
+ % 1. The capability: a normal predicate, callable from `execute` and `/goal`.
245
+ count_words(File, Count) :-
246
+ script_file(count_words, Script),
247
+ format(atom(Cmd), "python3 '~w' '~w'", [Script, File]),
248
+ exec(bash(command: Cmd), Result),
249
+ get_dict(stdout, Result, Count).
213
250
 
214
- agent_main :-
215
- system("You have a calculate tool."),
216
- task("What is the square root of 144?"),
217
- answer("Done").
251
+ % 2. The annotation: exposes it to the nested agent. Thin body only.
252
+ tool(count_words(File, Count), "Count words in a workspace file.") :-
253
+ count_words(File, Count).
218
254
  ```
219
255
 
220
- Tool definitions have the form:
256
+ A predicate defined *only* inside a `tool/2` clause is invisible to
257
+ `execute` / `/goal` — the loader asserts it as `tool(Head)`, never as `Head`. Split
258
+ the two so one implementation is reachable from both surfaces:
259
+
221
260
  ```prolog
222
- tool(name(Arg1, Arg2, ..., Result), "Description") :- Body.
261
+ /goal count_words("report.txt", C). % authoring agent
262
+ task("Count the words in report.txt.", N). % nested agent calls the tool
223
263
  ```
224
264
 
225
- The last argument is typically the output. The description is shown to the LLM.
226
- ```
265
+ The tool head's **last argument is the output**; the description is shown to the
266
+ nested agent. Keep the `tool/2` body a single delegation — put no logic in it.
267
+
268
+ Logic lives in the predicate, not the annotation:
227
269
 
228
- You can add Prolog logic in tool implementations:
229
270
  ```prolog
230
- tool(safe_divide(A, B, Result), "Safely divide two numbers") :-
271
+ safe_divide(A, B, Result) :-
231
272
  ( B =:= 0
232
273
  -> Result = error("Division by zero")
233
- ; exec(calculator(expression: A/B), Result)
274
+ ; Result is A / B
234
275
  ).
276
+
277
+ tool(safe_divide(A, B, Result), "Safely divide two numbers.") :-
278
+ safe_divide(A, B, Result).
235
279
  ```
236
280
 
237
281
  #### Using `task()` Inside Tools
@@ -239,20 +283,22 @@ tool(safe_divide(A, B, Result), "Safely divide two numbers") :-
239
283
  Tools can use `task()` and `prompt()` internally to combine Prolog logic with LLM reasoning:
240
284
 
241
285
  ```prolog
242
- % A tool that computes then explains
243
- :- tool(explain_calculation(A, B), "Calculate and explain the result").
244
-
245
- tool(explain_calculation(A, B, Explanation)) :-
286
+ % A predicate that computes then explains.
287
+ explain_calculation(A, B, Explanation) :-
246
288
  Sum is A + B, % Prolog computation
247
289
  format(string(Desc), "Explain ~w + ~w = ~w to a child", [A, B, Sum]),
248
290
  task(Desc, Explanation). % LLM explanation
249
291
 
250
- % A tool that uses LLM for formatting
251
- :- tool(format_data(Data), "Format data nicely using LLM").
292
+ tool(explain_calculation(A, B, Explanation), "Calculate and explain the result.") :-
293
+ explain_calculation(A, B, Explanation).
252
294
 
253
- tool(format_data(Data, FormattedOutput)) :-
295
+ % A predicate that uses the LLM for formatting.
296
+ format_data(Data, FormattedOutput) :-
254
297
  format(string(Desc), "Format this data nicely: ~w", [Data]),
255
298
  task(Desc, FormattedOutput).
299
+
300
+ tool(format_data(Data, FormattedOutput), "Format data nicely using LLM.") :-
301
+ format_data(Data, FormattedOutput).
256
302
  ```
257
303
 
258
304
  **Memory Isolation:** When `task()` or `prompt()` runs inside a tool, the nested agent starts with **fresh memory**. It does NOT inherit the parent's accumulated memory from `system()`, `user()`, or previous `task()` calls. If you need context in a nested task, pass it explicitly as a tool argument or add it with `system()` inside the tool body.
@@ -260,12 +306,16 @@ tool(format_data(Data, FormattedOutput)) :-
260
306
  **Tool Access:** The nested agent has access to all DML tools **except** the tool that is currently executing (automatic call stack exclusion to prevent infinite recursion). You can further control tool access using `with_tools/2` and `without_tools/2`.
261
307
 
262
308
  ```prolog
263
- % Example: Passing context explicitly
264
- tool(smart_search(Context, Query, Summary), "Search with context") :-
265
- system(Context), % Add context to nested task's memory
266
- exec(web_search(query: Query), Results),
267
- format(string(Desc), "Summarize: ~w", [Results]),
309
+ % Example: passing context explicitly.
310
+ smart_grep(BuildContext, Pattern, Summary) :-
311
+ system(BuildContext), % add context to the nested task's memory
312
+ format(atom(Cmd), "grep -rn '~w' .", [Pattern]),
313
+ exec(bash(command: Cmd), Results),
314
+ format(string(Desc), "Summarize these matches: ~w", [Results]),
268
315
  task(Desc, Summary).
316
+
317
+ tool(smart_grep(BuildContext, Pattern, Summary), "Grep with context.") :-
318
+ smart_grep(BuildContext, Pattern, Summary).
269
319
  ```
270
320
 
271
321
  ---
@@ -309,7 +359,7 @@ agent_main :-
309
359
  system("You are a safe assistant."),
310
360
 
311
361
  % Run task with only safe tools
312
- with_tools([read_file, list_files], (
362
+ with_tools([search, fetch_page], (
313
363
  task("Analyze the files in the workspace.", Analysis)
314
364
  )),
315
365
 
@@ -351,6 +401,68 @@ agent_main :-
351
401
 
352
402
  ---
353
403
 
404
+ ### Media Predicates
405
+
406
+ Images are **workspace files**; DML carries only a reference. See
407
+ `docs/DML_MEDIA.md`.
408
+
409
+ #### `read_media(+Path, -Media)`
410
+
411
+ Bind `Media = media(Path, Mime)` for a workspace-relative image (PNG, JPEG, GIF,
412
+ WebP). The bytes are not read into Prolog.
413
+
414
+ #### `attach_media(+Media)`
415
+
416
+ Append the image to conversation memory (reference only), so the next `task/N`
417
+ call sends it to the model as an image block:
418
+
419
+ ```prolog
420
+ agent_main :-
421
+ read_media("photos/fox.png", Img),
422
+ attach_media(Img),
423
+ task("Describe the image in one sentence.", Description),
424
+ answer(Description).
425
+ ```
426
+
427
+ Memory stores `media{path, mime}` — never the image bytes. Judgments
428
+ (`choose`/`rate`/`verify`/`probability`) stay text-only.
429
+
430
+ ---
431
+
432
+ ### File I/O and paths — prefer the shell
433
+
434
+ **Prefer `exec(bash(...))` for file operations.**
435
+ Reading, writing, copying, or converting files is usually clearer and more
436
+ robust as a shell command; reach for the DML predicates below only when the
437
+ content must be bound and reasoned over inside Prolog. Pulling a file into DML
438
+ just to hand it back to the shell is a smell (`DML_AUTHORING.md` §2).
439
+
440
+ If you do use them: every path in DML is **workspace-relative** and confined to
441
+ the workspace. The
442
+ engine mounts the workspace at `/workspace`, but you must not write
443
+ `/workspace/...` in DML — passing an absolute path is rejected, as is `..`. File
444
+ predicates all take a relative path:
445
+
446
+ ```prolog
447
+ read_file("images/a.png", Bytes),
448
+ write_file("out/report.txt", Text),
449
+ make_directory_path("out/nested"), % create a directory (and parents)
450
+ append_file("out/log.txt", Line),
451
+ delete_file("out/report.txt"),
452
+ directory_files("images", Names), % bare entry names: ["a.png", ...]
453
+ exists_file("images/a.png"),
454
+ size_file("images/a.png", Size),
455
+ time_file("images/a.png", Modified).
456
+ ```
457
+
458
+ `write_file/2` does **not** create parent directories — call
459
+ `make_directory_path/1` first. `directory_files/2` returns bare entry names (no
460
+ directory), so build a path with `atom_concat('images/', Name, Path)` when you
461
+ need one. `bash` runs with a wider view of the sandbox than DML has; convert
462
+ anything from the shell to a workspace-relative path before handing it to DML.
463
+
464
+ ---
465
+
354
466
  ### Output Predicates
355
467
 
356
468
  #### `output(+Text)`
@@ -397,25 +509,6 @@ agent_main :-
397
509
 
398
510
  ---
399
511
 
400
- ### `param(+Key, +Description, -Value)`
401
-
402
- Access parameters passed from the caller:
403
-
404
- ```prolog
405
- agent_main :-
406
- param(name, "User's name", Name),
407
- param(age, "User's age", Age),
408
- format(string(Msg), "Hello ~w, you are ~w years old!", [Name, Age]),
409
- answer(Msg).
410
- ```
411
-
412
- Called from TypeScript:
413
- ```typescript
414
- dc.runDML(code, { params: { name: 'Alice', age: 30 } });
415
- ```
416
-
417
- ---
418
-
419
512
  ## Control Flow
420
513
 
421
514
  DML supports standard Prolog control flow:
@@ -460,14 +553,13 @@ throw(Error)
460
553
 
461
554
  ## String Interpolation
462
555
 
463
- Text arguments support `{variable}` interpolation with parameters:
556
+ Text arguments support `{variable}` interpolation with bound variables:
464
557
 
465
558
  ```prolog
466
- agent_main :-
467
- param(topic, "Research topic", Topic),
559
+ agent_main(Topic) :-
468
560
  system("You are a research assistant."),
469
- task("Research the topic: {topic}"), % Topic is interpolated
470
- answer("Research on {topic} complete!").
561
+ task("Research the topic: {Topic}"), % Topic is interpolated
562
+ answer("Research on {Topic} complete!").
471
563
  ```
472
564
 
473
565
  ---
@@ -524,7 +616,12 @@ agent_main :-
524
616
 
525
617
  ## Full Prolog Support
526
618
 
527
- DML is built on SWI-Prolog, so you have access to the full Prolog language:
619
+ DML is built on SWI-Prolog, so you have access to the full Prolog language — and
620
+ to the constraint libraries (`clpfd`, `clpq`, `clpr`). Many questions are best
621
+ answered by a plain Prolog or CLP goal run with `execute`, with no model call at
622
+ all: arithmetic, counting, ordering, membership, `findall/3`, `aggregate_all/3`,
623
+ list/set operations, and constraint or optimisation problems. Reach for `task/N`
624
+ only when the step genuinely needs language understanding.
528
625
 
529
626
  ### Lists
530
627
  ```prolog
@@ -568,6 +665,44 @@ agent_main :-
568
665
  answer(Msg).
569
666
  ```
570
667
 
668
+ ### Bounding a goal (inference limit)
669
+
670
+ The interpreter has **no wall-clock timeout for a single builtin call** — the
671
+ session `gas` budget counts meta-interpreter steps, and a runaway `findall/3`,
672
+ `aggregate_all/3`, or `label/1` runs inside one step. Wrap such a call in
673
+ `call_with_inference_limit/3` (core SWI-Prolog; available in this runtime, which
674
+ has no threads) to bound it by inference count:
675
+
676
+ ```prolog
677
+ bounded_findall(Goal, Xs) :-
678
+ call_with_inference_limit(findall(X, call(Goal, X), Xs), 1000000, Result),
679
+ ( Result == inference_limit_exceeded
680
+ -> throw(error(inference_limit_exceeded, context(bounded_findall/2, Goal)))
681
+ ; true
682
+ ).
683
+ ```
684
+
685
+ `Result` is `inference_limit_exceeded` when the limit is hit (otherwise the
686
+ normal call result). Use it for `findall/3`, `aggregate_all/3`, and CLP
687
+ `label/1` over a large or under-specified domain:
688
+
689
+ ```prolog
690
+ sudoku_solve(Puzzle, Solution) :-
691
+ ...
692
+ call_with_inference_limit(label(Solution), 500000, Result),
693
+ ( Result == inference_limit_exceeded
694
+ -> throw(error(inference_limit_exceeded, context(sudoku_solve/2, label)))
695
+ ; true
696
+ ).
697
+ ```
698
+
699
+ System libraries imported with `:- use_module(library(...)).` (e.g. `clpfd`) are
700
+ also visible inside meta-calls, so `label/1`, `all_distinct/1`, and `ins/2` work
701
+ unqualified through the wrapper. If a library predicate is somehow not found
702
+ inside a wrapper (`existence_error`), qualify it: `clpfd:label(Xs)`.
703
+
704
+ For shell commands, pass `exec(bash(command: Cmd, timeoutMs: N), R)` instead.
705
+
571
706
  ### Assert/Retract (within session)
572
707
  ```prolog
573
708
  agent_main :-
@@ -577,24 +712,97 @@ agent_main :-
577
712
  answer(Msg).
578
713
  ```
579
714
 
580
- ### Constraint Logic Programming (CLP)
715
+ ### Constraint Logic Programming (CLP) — advanced, use sparingly
716
+
717
+ Use CLP only for a **genuine constraint problem** (scheduling, assignment,
718
+ puzzles, exact search). It is the wrong tool for ordinary arithmetic and
719
+ transformations — prefer a `task/N`/`prompt/N` step when the numbers or the
720
+ operation are open-ended (`DML_AUTHORING.md` §0). CLP also regresses easily: an
721
+ under-specified model, or one that is simply **unsatisfiable**, can search
722
+ essentially forever, so a buggy skill hangs the turn instead of failing fast.
723
+ If you use it:
581
724
 
582
- DML supports Prolog's CLP libraries for solving optimization and logic problems without needing Python:
725
+ - **Bound every domain first.** For one variable use `X in 0..100`; for a list use
726
+ `[X,Y,Z] ins 0..100`. (`X ins 0..100` on a bare variable is an
727
+ `instantiation_error` — use `in` for a single variable.)
728
+ - `all_distinct/1` / `all_different/1` over the list constrains it pairwise.
729
+ - Call `label/1` (or `labeling/2` with options such as `ff`) only when you need
730
+ concrete values; wrap it in `once/1` when a single witness is enough.
731
+ - To bound a search that can run away, wrap it in `call_with_inference_limit/3`
732
+ (see *Bounding a goal* above):
733
+ `call_with_inference_limit(label(Xs), 500000, R)` — `R == inference_limit_exceeded`
734
+ when it gave up. This works for CLP(FD) predicates in this runtime.
735
+ - Keep the model small; a big model is a sign the step belongs in a `task/N`.
583
736
 
584
- - **CLP(FD)**: Finite domains (integers). Use `:- use_module(library(clpfd)).`
585
- - **CLP(Q)**: Rational numbers. Use `:- use_module(library(clpq)).`
586
- - **CLP(R)**: Real numbers. Use `:- use_module(library(clpr)).`
737
+ - **CLP(FD)**: finite domains (integers). `:- use_module(library(clpfd)).`
738
+ - **CLP(Q)**: rationals. `:- use_module(library(clpq)).`
739
+ - **CLP(R)**: reals. `:- use_module(library(clpr)).`
587
740
 
588
741
  ```prolog
589
742
  :- use_module(library(clpfd)).
590
743
 
591
- agent_main(Total) :-
592
- [X,Y] ins 0..100,
744
+ % Small, fully bounded search; one witness.
745
+ solve_sum_product(Total, X, Y) :-
746
+ [X, Y] ins 0..100, % bound the domains; never leave them open
593
747
  X + Y #= Total,
594
748
  X * Y #= 2400,
595
- label([X,Y]),
596
- format(string(Msg), "X=~w, Y=~w", [X, Y]),
597
- answer(Msg).
749
+ once(label([X, Y])).
750
+
751
+ % A search bounded by inference count instead of by the domain.
752
+ bounded_label(Xs, Result) :-
753
+ call_with_inference_limit(label(Xs), 500000, Result).
754
+ ```
755
+
756
+ #### Optimisation (LP / MIP)
757
+
758
+ The CLP family here is **CLP(FD)** (integers), **CLP(Q)** (exact rationals) and
759
+ **CLP(R)** (reals) — there is no `clpfq`. `library(simplex)` loads but returns
760
+ unreliable answers in this runtime (its minimum/maximum come back wrong); do not
761
+ build on it.
762
+
763
+ **Continuous LP** — `clpr` (reals) / `clpq` (rationals), same interface. `{...}`
764
+ posts the constraints; `maximize/1` / `minimize/1` find the optimum:
765
+
766
+ ```prolog
767
+ :- use_module(library(clpr)).
768
+
769
+ lp(X, Y) :-
770
+ {X >= 0, Y >= 0, X =< 10, Y =< 10, X + 2*Y =< 14},
771
+ maximize(X + Y). % X = 10.0, Y = 2.0
772
+ ```
773
+
774
+ > **Caveat:** `maximize/1` / `minimize/1` bind the variables only when the optimum
775
+ > is a *unique vertex*. If the optimum is a face (a family of optima), they succeed
776
+ > and bind nothing. Use `sup/2` / `inf/2` to get the optimum **value** reliably —
777
+ > `{X >= 0, Y >= 0, X + Y =< 10, 2*X + Y =< 15}, sup(X + Y, S)` → `S = 10.0`.
778
+ > (`inf/3` / `sup/3` do not exist in this build.)
779
+
780
+ **Integer optimum** — negate the objective and use `bb_inf/5`; the 4th argument
781
+ comes back as the integer vertex:
782
+
783
+ ```prolog
784
+ :- use_module(library(clpr)).
785
+
786
+ mip(Inf, Vertex) :-
787
+ {X >= 0, Y >= 0, X + Y =< 4, X + 3*Y =< 6},
788
+ bb_inf([X, Y], -(3*X + 2*Y), Inf, Vertex, 0.001).
789
+ % Inf = -12.0, Vertex = [4,0] (negate the objective to maximise)
790
+ ```
791
+
792
+ **Exact integer optimum** — CLP(FD) with a `max(Expr)` label option. Prefer this
793
+ when the problem is genuinely integer: it is exact, bounded, and well-tested.
794
+ Bound every domain first and keep `label`/`labeling` inside
795
+ `call_with_inference_limit/3`:
796
+
797
+ ```prolog
798
+ :- use_module(library(clpfd)).
799
+
800
+ exact_max(X, Y) :-
801
+ [X, Y] ins 0..10,
802
+ X + Y #=< 4,
803
+ X + 3*Y #=< 6,
804
+ call_with_inference_limit(labeling([max(3*X + 2*Y), down], [X, Y]), 500000, _).
805
+ % X = 4, Y = 0
598
806
  ```
599
807
 
600
808
  ### Dictionaries (SWI-Prolog)
@@ -619,10 +827,8 @@ step(N, Desc) :-
619
827
  format(string(Msg), "Step ~w: ~w", [N, Desc]),
620
828
  output(Msg).
621
829
 
622
- % Main entry point
623
- agent_main :-
624
- param(topic, "Research topic", Topic),
625
-
830
+ % Main entry point; the topic is an argument.
831
+ agent_main(Topic) :-
626
832
  % Set up the assistant
627
833
  system("You are a thorough research assistant."),
628
834
  system("Provide detailed, accurate information."),
@@ -649,8 +855,123 @@ agent_main :-
649
855
  Run with:
650
856
  ```typescript
651
857
  for await (const event of dc.runDML(code, {
652
- params: { topic: 'quantum computing' }
858
+ args: ['quantum computing']
653
859
  })) {
654
860
  console.log(event.type, event.content);
655
861
  }
656
- ```
862
+ ```
863
+
864
+ ---
865
+
866
+ ## Semantic Judgment Predicates
867
+
868
+ Semantic judgments answer bounded, typed questions about an explicit state.
869
+ They are not generative: a `choose` picks one of your options, a `rate` picks
870
+ one of your levels, and a `verify` returns a probability / yes-no answer. They
871
+ never read or write DML memory (`system/1`, `user/1`, `task/N`), and one `judge/2`
872
+ call sends every question in a single request.
873
+
874
+ ### `judge(+State, +Specs)`
875
+
876
+ Each element of `Specs` is `Question - Output`. The output variable is bound
877
+ when the batch completes.
878
+
879
+ ```prolog
880
+ agent_main(Message) :-
881
+ judge(Message, [
882
+ choose("Which team should handle this?",
883
+ [billing-"Charges and refunds", orders-"Delivery and returns",
884
+ account-"Login and security"]) - Team,
885
+ rate("How frustrated is the customer?", [calm, frustrated, angry]) - Frustration,
886
+ verify("Does the message ask for a refund?") - Refund,
887
+ probability("Is this urgent?") - Urgency
888
+ ]),
889
+ ( Refund == yes
890
+ -> answer("Escalating to the refund queue.")
891
+ ; format(string(R), "Routing to ~w (frustration ~w, urgency ~w)", [Team, Frustration, Urgency]),
892
+ answer(R)
893
+ ).
894
+ ```
895
+
896
+ Question forms:
897
+
898
+ - `choose(Instruction, Options)` - options are atoms or `Option-"description"`.
899
+ - `rate(Instruction, Levels)` - an ordered list of level descriptions.
900
+ - `verify(Instruction)` / `verify(Instruction, criteria(True, False))`.
901
+ - `probability(Instruction)`.
902
+
903
+ ### One-off predicates
904
+
905
+ Each is a single request for a single judgment:
906
+
907
+ ```prolog
908
+ choose(State, Question, Options, Choice)
909
+ rate(State, Question, Levels, Level)
910
+ verify(State, Question, Truth) % yes | no | unknown
911
+ probability(State, Question, P) % number
912
+ holds(State, Question) % semidet: succeeds when verify == yes
913
+ holds(State, Question, Threshold) % semidet: probability >= Threshold
914
+ ```
915
+
916
+ ### Backends and capabilities
917
+
918
+ Judgments are backend-agnostic. Backends are registered on the SDK
919
+ (`createDeepClause({ judgeBackends, defaultJudge })`) and can be selected per
920
+ run or per scope:
921
+
922
+ ```prolog
923
+ with_judgment(jev, choose("state", "Which team?", [billing, orders], Team)).
924
+ require_judgment(calibrated, verify("state", "Is this urgent?", Truth)).
925
+ ```
926
+
927
+ > **In the DML REPL**, an `llm` backend is always registered (it reuses the
928
+ > active model), and `jev` is registered when `judgment.jev.enabled` is set in
929
+ > `.deepclause/config.json` and its API key is available. `with_judgment(jev,
930
+ > ...)` fails if `jev` is not registered.
931
+
932
+ `require_judgment/2` fails the wrapped goal before it runs when the active
933
+ backend does not provide the capability, so a skill that depends on calibrated
934
+ probabilities cannot silently run on an uncalibrated backend. Available
935
+ capabilities include `calibrated`, `probability`, `confidence`, and
936
+ `independentQuestions`.
937
+
938
+ Observations are memoized per run by backend, model, state, and questions, so
939
+ backtracking reuses an answer instead of re-querying the model.
940
+
941
+ ### Notes
942
+
943
+ - `verify` is three-valued: `yes`, `no`, or `unknown`. Never read `\+` as
944
+ "the model said no"; use the returned truth value.
945
+ - Values are constrained to the options/levels you supply. A `choose` answer is
946
+ always one of your option atoms.
947
+ - Prefer one `judge/2` batch over several one-off calls when you need more than
948
+ one or two judgments.
949
+ ## The DML REPL (`deepclause repl`)
950
+
951
+ DML skills can also be grown interactively in a persistent **living module**.
952
+
953
+ - `/goal <dml>` runs a goal and enumerates its solutions (the legacy dotted
954
+ `goal: <dml>.` form still works).
955
+ - Plain English builds the module: the **authoring agent** inspects and edits it
956
+ through tools (`listing`, `begin_turn`, `define`/`assert`/`assert_many`,
957
+ `retract`/`delete`, `execute`, `end_turn`/`rollback`). Edits are transactions:
958
+ `begin_turn` is required before any edit, `end_turn` commits a version.
959
+ Nothing is auto-run; the agent uses `execute` to test during a turn.
960
+ - There is **no implicit `agent_main` requirement** in the REPL. Run any
961
+ predicate with `/goal <name>(…)`. Define `agent_main` in the module when it
962
+ should also run with `deepclause run` / `/dc-run`.
963
+ - `freeze.` makes the module read-only; `export <file>.` serializes it.
964
+ `export harness.zip` bundles the module with its linked script files;
965
+ `export harness.dml` inlines them into one portable file.
966
+ - `input/2` / `exec(ask_user(...))` (module) ask the human. They never block in
967
+ non-interactive runs (`-g`, piped stdin, CI).
968
+
969
+ **Self-containment.** The harness is the `.dml` **plus the files it links**.
970
+ Materialize each program with a DML goal (`make_directory_path(...)`,
971
+ `write_file(...)`), link it with `script_file(Name, Path)`, and run it with
972
+ `exec(bash(...))`. The
973
+ exporter bundles the linked files, so they travel with the harness. Pass
974
+ untrusted data through files or stdin, never interpolated into the shell
975
+ command.
976
+
977
+ See [`docs/REPL.md`](../../../../docs/REPL.md) for the full guide.