tool-schemas.expected.json 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. {
  2. "initial": [
  3. {
  4. "name": "bash",
  5. "description": "Execute a bash command (`bash -c`) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass `workdir` instead of using `cd`. Non-zero exits are reported as `[exit code: N]`. Current harness environment facts are exposed through managed `$DSH_*` variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as `[sandbox: file access denied under <mode> mode]` — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set `run_in_background: true` for long-running commands: the call returns a task id immediately; read its output with `task_output` and stop it with `task_kill`. Attempting a command the sandbox may deny is safe and expected: run it and read the marker rather than assuming the denial. When a command is denied and a wider mode would let it succeed, escalate immediately in the same turn — the one sanctioned exception to a denial: retry the exact same command once with `sandbox_permissions` (the narrowest wider mode that suffices) plus a one-sentence `justification`. Do not detour through chat to ask permission first — the approval prompt raised by that retry is how the user consents. If the session states approval prompts are disabled, there is no exception: a denial is final — do not set `sandbox_permissions`. Never escalate speculatively: ground the request in a real denial — normally the one this command just hit; escalating up front is fine only when this session already denied the same access. A rejected escalation is final for that command — stop and explain, never work around it — but it does not forbid attempting or escalating other commands later.",
  6. "parameters": {
  7. "type": "object",
  8. "properties": {
  9. "command": {
  10. "type": "string",
  11. "description": "The bash command to execute."
  12. },
  13. "description": {
  14. "type": "string",
  15. "description": "Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: \"ls\" → \"List files in current directory\"; \"git status\" → \"Show working tree status\"; \"npm install\" → \"Install package dependencies\"."
  16. },
  17. "timeoutMs": {
  18. "type": "number",
  19. "description": "Timeout in milliseconds. The executor applies its configured default and cap, and kills the command on expiry."
  20. },
  21. "workdir": {
  22. "type": "string",
  23. "description": "Working directory for this command. Defaults to the session workspace; a relative path is resolved against it."
  24. },
  25. "run_in_background": {
  26. "type": "boolean",
  27. "description": "Run in the background and return a task id immediately (collect with task_output, stop with task_kill). No timeout applies."
  28. },
  29. "sandbox_permissions": {
  30. "type": "string",
  31. "description": "The wider sandbox mode this command needs. Only valid as a one-shot retry of a command the sandbox just denied; requires justification and user approval.",
  32. "enum": [
  33. "workspace-write",
  34. "danger-full-access"
  35. ]
  36. },
  37. "justification": {
  38. "type": "string",
  39. "description": "Required with sandbox_permissions: one sentence for the user explaining why this exact command needs the wider access."
  40. }
  41. },
  42. "required": [
  43. "command",
  44. "description"
  45. ]
  46. }
  47. },
  48. {
  49. "name": "create_goal",
  50. "description": "Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say \"create a goal\". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority.",
  51. "parameters": {
  52. "type": "object",
  53. "properties": {
  54. "objective": {
  55. "type": "string",
  56. "description": "The concrete completion objective inferred from the direct human request."
  57. },
  58. "max_goal_rounds": {
  59. "type": "number",
  60. "description": "Optional positive safe-integer limit on automatic continuation rounds."
  61. }
  62. },
  63. "required": [
  64. "objective"
  65. ]
  66. }
  67. },
  68. {
  69. "name": "edit",
  70. "description": "Edit an existing UTF-8 text file by replacing literal text.",
  71. "parameters": {
  72. "type": "object",
  73. "properties": {
  74. "file_path": {
  75. "type": "string",
  76. "description": "Path to edit, resolved by the filesystem backend."
  77. },
  78. "old_string": {
  79. "type": "string",
  80. "description": "Literal text to replace. Must match exactly."
  81. },
  82. "new_string": {
  83. "type": "string",
  84. "description": "Literal replacement text. Use an empty string to delete the match."
  85. },
  86. "replace_all": {
  87. "type": "boolean",
  88. "description": "Replace all matches. Defaults to false; when false, old_string must appear exactly once."
  89. },
  90. "sandbox_permissions": {
  91. "type": "string",
  92. "description": "The wider sandbox mode this file operation needs. Only valid as a one-shot retry of an operation the sandbox just denied; requires justification and user approval.",
  93. "enum": [
  94. "workspace-write",
  95. "danger-full-access"
  96. ]
  97. },
  98. "justification": {
  99. "type": "string",
  100. "description": "Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access."
  101. }
  102. },
  103. "required": [
  104. "file_path",
  105. "old_string",
  106. "new_string"
  107. ]
  108. }
  109. },
  110. {
  111. "name": "get_goal",
  112. "description": "Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal.",
  113. "parameters": {
  114. "type": "object",
  115. "properties": {}
  116. }
  117. },
  118. {
  119. "name": "list_agents",
  120. "description": "List your continuable background subagents by durable id and label. Status is a snapshot of the stored record: running means the subagent session is currently live in this process, complete means it exists only in storage and a `send_message` starts a new turn on the same conversation. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped.",
  121. "parameters": {
  122. "type": "object",
  123. "properties": {}
  124. }
  125. },
  126. {
  127. "name": "ralph",
  128. "description": "Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools.",
  129. "parameters": {
  130. "type": "object",
  131. "properties": {
  132. "objective": {
  133. "type": "string",
  134. "description": "The immutable completion objective for every fresh Ralph round."
  135. },
  136. "maxRounds": {
  137. "type": "number",
  138. "description": "Optional positive safe-integer round cap, bounded by the deployment ceiling."
  139. }
  140. },
  141. "required": [
  142. "objective"
  143. ]
  144. }
  145. },
  146. {
  147. "name": "read",
  148. "description": "Read a UTF-8 text file and return line-numbered content.",
  149. "parameters": {
  150. "type": "object",
  151. "properties": {
  152. "file_path": {
  153. "type": "string",
  154. "description": "Path to read, resolved by the filesystem backend."
  155. },
  156. "offset": {
  157. "type": "number",
  158. "description": "1-based first line to return. Defaults to 1."
  159. },
  160. "limit": {
  161. "type": "number",
  162. "description": "Maximum number of lines to return. Defaults to 2000."
  163. }
  164. },
  165. "required": [
  166. "file_path"
  167. ]
  168. }
  169. },
  170. {
  171. "name": "send_message",
  172. "description": "Send a message to a background subagent by its subagent id, continuing the same conversation. It becomes the subagent's next turn: if it is still working, the message waits until its current turn finishes, so it cannot redirect work already underway. This call returns no answer from the subagent — only confirmation that the message was delivered — so use it to give it more work. A failure means the message was NOT delivered.",
  173. "parameters": {
  174. "type": "object",
  175. "properties": {
  176. "subagent_id": {
  177. "type": "string",
  178. "description": "The subagent id returned when the background subagent was started."
  179. },
  180. "message": {
  181. "type": "string",
  182. "description": "The message to deliver to the subagent."
  183. }
  184. },
  185. "required": [
  186. "subagent_id",
  187. "message"
  188. ]
  189. }
  190. },
  191. {
  192. "name": "session_event_read",
  193. "description": "Read one full unabridged event and optional neighboring raw-event summaries from an authorized session.",
  194. "parameters": {
  195. "type": "object",
  196. "properties": {
  197. "session_id": {
  198. "type": "string",
  199. "description": "Target session id. Omit for the current session."
  200. },
  201. "seq": {
  202. "type": "integer",
  203. "description": "Target event sequence number."
  204. },
  205. "before": {
  206. "type": "integer",
  207. "description": "Number of preceding raw events to summarize. Omit for none."
  208. },
  209. "after": {
  210. "type": "integer",
  211. "description": "Number of following raw events to summarize. Omit for none."
  212. }
  213. },
  214. "required": [
  215. "seq"
  216. ]
  217. }
  218. },
  219. {
  220. "name": "session_event_search",
  221. "description": "Search prior events in one authorized session; the current session excludes the step performing this call.",
  222. "parameters": {
  223. "type": "object",
  224. "properties": {
  225. "session_id": {
  226. "type": "string",
  227. "description": "Target session id. Omit for the current session."
  228. },
  229. "query": {
  230. "type": "string",
  231. "description": "Literal full-text query over the target session."
  232. },
  233. "seq_from": {
  234. "type": "integer",
  235. "description": "Inclusive event sequence lower bound."
  236. },
  237. "seq_to": {
  238. "type": "integer",
  239. "description": "Inclusive event sequence upper bound."
  240. },
  241. "time_from": {
  242. "type": "string",
  243. "description": "Inclusive timezone-qualified ISO 8601 event-time lower bound."
  244. },
  245. "time_to": {
  246. "type": "string",
  247. "description": "Inclusive timezone-qualified ISO 8601 event-time upper bound."
  248. },
  249. "event_types": {
  250. "type": "array",
  251. "description": "Event types to include.",
  252. "items": {
  253. "type": "string"
  254. }
  255. },
  256. "surfaces": {
  257. "type": "array",
  258. "description": "Event surfaces to include.",
  259. "items": {
  260. "type": "string",
  261. "enum": [
  262. "current",
  263. "shadowed",
  264. "log-only"
  265. ]
  266. }
  267. }
  268. },
  269. "required": [
  270. "query"
  271. ]
  272. }
  273. },
  274. {
  275. "name": "session_event_trace",
  276. "description": "Read every direct replacement and provenance relationship for one event in an authorized session.",
  277. "parameters": {
  278. "type": "object",
  279. "properties": {
  280. "session_id": {
  281. "type": "string",
  282. "description": "Target session id. Omit for the current session."
  283. },
  284. "seq": {
  285. "type": "integer",
  286. "description": "Target event sequence number."
  287. }
  288. },
  289. "required": [
  290. "seq"
  291. ]
  292. }
  293. },
  294. {
  295. "name": "session_search",
  296. "description": "Search prior sessions in the caller workspace and return the strongest matching event from each session.",
  297. "parameters": {
  298. "type": "object",
  299. "properties": {
  300. "query": {
  301. "type": "string",
  302. "description": "Literal full-text query over prior session history."
  303. },
  304. "session_ids": {
  305. "type": "array",
  306. "description": "Optional session ids to include.",
  307. "items": {
  308. "type": "string"
  309. }
  310. },
  311. "created_at_from": {
  312. "type": "string",
  313. "description": "Inclusive timezone-qualified ISO 8601 creation-time lower bound."
  314. },
  315. "created_at_to": {
  316. "type": "string",
  317. "description": "Inclusive timezone-qualified ISO 8601 creation-time upper bound."
  318. },
  319. "parent_session_ids": {
  320. "type": "array",
  321. "description": "Optional direct parent session ids.",
  322. "items": {
  323. "type": "string"
  324. }
  325. },
  326. "include_root_sessions": {
  327. "type": "boolean",
  328. "description": "Include sessions with no parent in the parent filter."
  329. },
  330. "availability": {
  331. "type": "array",
  332. "description": "Require at least one selected source availability.",
  333. "items": {
  334. "type": "string",
  335. "enum": [
  336. "live",
  337. "persisted"
  338. ]
  339. }
  340. },
  341. "event_seq_from": {
  342. "type": "integer",
  343. "description": "Inclusive event sequence lower bound."
  344. },
  345. "event_seq_to": {
  346. "type": "integer",
  347. "description": "Inclusive event sequence upper bound."
  348. },
  349. "event_time_from": {
  350. "type": "string",
  351. "description": "Inclusive timezone-qualified ISO 8601 event-time lower bound."
  352. },
  353. "event_time_to": {
  354. "type": "string",
  355. "description": "Inclusive timezone-qualified ISO 8601 event-time upper bound."
  356. },
  357. "event_types": {
  358. "type": "array",
  359. "description": "Event types to include.",
  360. "items": {
  361. "type": "string"
  362. }
  363. },
  364. "event_surfaces": {
  365. "type": "array",
  366. "description": "Event surfaces to include.",
  367. "items": {
  368. "type": "string",
  369. "enum": [
  370. "current",
  371. "shadowed",
  372. "log-only"
  373. ]
  374. }
  375. }
  376. },
  377. "required": [
  378. "query"
  379. ]
  380. }
  381. },
  382. {
  383. "name": "session_trace",
  384. "description": "Read the authorized session lineage around one session, including complete visible ancestor and descendant relationships.",
  385. "parameters": {
  386. "type": "object",
  387. "properties": {
  388. "session_id": {
  389. "type": "string",
  390. "description": "Target session id. Omit for the current session."
  391. }
  392. }
  393. }
  394. },
  395. {
  396. "name": "skill",
  397. "description": "Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill.",
  398. "parameters": {
  399. "type": "object",
  400. "properties": {
  401. "name": {
  402. "type": "string",
  403. "description": "The exact skill name from the available skills list."
  404. }
  405. },
  406. "required": [
  407. "name"
  408. ]
  409. }
  410. },
  411. {
  412. "name": "subagent",
  413. "description": "Delegate a self-contained task to a subagent (a separate agent that works in its own context) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to start a background subagent that keeps its conversation: you receive only its subagent id, never its result, and it works on its own. Use this for work whose result you do not need returned by this call; `send_message` sends it more work.",
  414. "parameters": {
  415. "type": "object",
  416. "properties": {
  417. "description": {
  418. "type": "string",
  419. "description": "A short (3-5 word) description of the delegated task, for display."
  420. },
  421. "prompt": {
  422. "type": "string",
  423. "description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
  424. },
  425. "run_in_background": {
  426. "type": "boolean",
  427. "description": "Run as a background subagent that keeps its conversation and return only its subagent id. This call never returns its result; send it more work with send_message."
  428. }
  429. },
  430. "required": [
  431. "description",
  432. "prompt"
  433. ]
  434. }
  435. },
  436. {
  437. "name": "subagent_fork",
  438. "description": "Delegate a task to a subagent that inherits this conversation: a child agent seeded with all completed turns so far (it does not see the current in-flight turn), returning only its final result. Use this when the subtask builds on this conversation's context — a follow-up analysis, a review, a continuation — without consuming this conversation's context for the work itself. You receive only its final answer, not its intermediate steps. Set `run_in_background: true` to start a background subagent that keeps its conversation: you receive only its subagent id, never its result, and it works on its own. Use this for work whose result you do not need returned by this call; `send_message` sends it more work.",
  439. "parameters": {
  440. "type": "object",
  441. "properties": {
  442. "description": {
  443. "type": "string",
  444. "description": "A short (3-5 word) description of the delegated task, for display."
  445. },
  446. "prompt": {
  447. "type": "string",
  448. "description": "The task for the subagent. It already sees this conversation's completed turns, so build on them freely and state only what is new."
  449. },
  450. "run_in_background": {
  451. "type": "boolean",
  452. "description": "Run as a background subagent that keeps its conversation and return only its subagent id. This call never returns its result; send it more work with send_message."
  453. }
  454. },
  455. "required": [
  456. "description",
  457. "prompt"
  458. ]
  459. }
  460. },
  461. {
  462. "name": "task_kill",
  463. "description": "Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops.",
  464. "parameters": {
  465. "type": "object",
  466. "properties": {
  467. "task_id": {
  468. "type": "string",
  469. "description": "Task id returned by the tool that started the background work."
  470. },
  471. "reason": {
  472. "type": "string",
  473. "description": "Optional short reason, recorded in the log and forwarded to the task."
  474. }
  475. },
  476. "required": [
  477. "task_id"
  478. ]
  479. }
  480. },
  481. {
  482. "name": "task_list",
  483. "description": "List your background tasks (running and finished) with their ids, kinds, and statuses.",
  484. "parameters": {
  485. "type": "object",
  486. "properties": {}
  487. }
  488. },
  489. {
  490. "name": "task_output",
  491. "description": "Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap.",
  492. "parameters": {
  493. "type": "object",
  494. "properties": {
  495. "task_id": {
  496. "type": "string",
  497. "description": "Task id returned by the tool that started the background work."
  498. },
  499. "wait": {
  500. "type": "boolean",
  501. "description": "Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task alive."
  502. },
  503. "timeout_ms": {
  504. "type": "number",
  505. "description": "Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum."
  506. }
  507. },
  508. "required": [
  509. "task_id"
  510. ]
  511. }
  512. },
  513. {
  514. "name": "todo_write",
  515. "description": "Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Keep AT MOST ONE todo `in_progress` at a time; while work remains, exactly one active task should be `in_progress`. Mark a todo `completed` the moment it is done (do not batch completions), and allow no `in_progress` item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: `pending` (not started), `in_progress` (being worked on now), `completed` (finished).",
  516. "parameters": {
  517. "type": "object",
  518. "properties": {
  519. "todos": {
  520. "type": "array",
  521. "description": "The COMPLETE task list, replacing any previous list.",
  522. "items": {
  523. "type": "object",
  524. "additionalProperties": false,
  525. "properties": {
  526. "content": {
  527. "type": "string",
  528. "description": "What the task is — a short imperative line."
  529. },
  530. "status": {
  531. "type": "string",
  532. "description": "pending (not started) | in_progress (now) | completed (done).",
  533. "enum": [
  534. "pending",
  535. "in_progress",
  536. "completed"
  537. ]
  538. }
  539. },
  540. "required": [
  541. "content",
  542. "status"
  543. ]
  544. }
  545. }
  546. },
  547. "required": [
  548. "todos"
  549. ]
  550. }
  551. },
  552. {
  553. "name": "update_goal",
  554. "description": "Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason.",
  555. "parameters": {
  556. "type": "object",
  557. "properties": {
  558. "goal_id": {
  559. "type": "string",
  560. "description": "Exact id returned by get_goal."
  561. },
  562. "revision": {
  563. "type": "number",
  564. "description": "Exact positive revision returned by get_goal."
  565. },
  566. "action": {
  567. "type": "string",
  568. "description": "edit | pause | resume | complete | blocked",
  569. "enum": [
  570. "edit",
  571. "pause",
  572. "resume",
  573. "complete",
  574. "blocked"
  575. ]
  576. },
  577. "objective": {
  578. "type": "string",
  579. "description": "Replacement objective; valid only with action edit."
  580. },
  581. "max_goal_rounds": {
  582. "type": "number",
  583. "description": "Replacement cap; valid only with action edit."
  584. },
  585. "blocked_reason": {
  586. "type": "string",
  587. "description": "Concrete blocking condition; required only with action blocked."
  588. }
  589. },
  590. "required": [
  591. "goal_id",
  592. "revision",
  593. "action"
  594. ]
  595. }
  596. },
  597. {
  598. "name": "workflow",
  599. "description": "Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.\n\nThe workflow's identity rides the `meta` parameter as JSON: required `name` (short kebab-case) and `description` strings, optional `whenToUse` string and `phases` array (`{title, detail?, provider?, model?}`). The `script` parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO `export const meta` statement — meta is a parameter, not code), running with top-level await; end with `return <value>` — the value must be JSON-serializable and is this tool's result.\n\nScript-body hooks:\n- `agent(prompt, opts?): Promise<any>` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.schema` (an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly.\n- `pipeline(items, ...stages): Promise<any[]>` — run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives `(prev, item, index)`. An ordinary stage throw drops that ITEM to `null` and skips its remaining stages.\n- `parallel(thunks): Promise<any[]>` — run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves to `null`.\n- `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, verbatim.\n\nMisused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item `null`.\n\nConstraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.",
  600. "parameters": {
  601. "type": "object",
  602. "properties": {
  603. "script": {
  604. "type": "string",
  605. "description": "The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`)."
  606. },
  607. "meta": {
  608. "type": "object",
  609. "description": "The workflow identity block (plain JSON — never code).",
  610. "additionalProperties": true,
  611. "properties": {
  612. "name": {
  613. "type": "string",
  614. "description": "Short kebab-case workflow name."
  615. },
  616. "description": {
  617. "type": "string",
  618. "description": "One-line description of what the workflow does."
  619. },
  620. "whenToUse": {
  621. "type": "string",
  622. "description": "Optional guidance on when this workflow applies."
  623. },
  624. "phases": {
  625. "type": "array",
  626. "description": "Optional phase declarations matched by phase() calls.",
  627. "items": {
  628. "type": "object",
  629. "additionalProperties": true,
  630. "properties": {
  631. "title": {
  632. "type": "string",
  633. "description": "The phase title phase() calls match by exact string."
  634. },
  635. "detail": {
  636. "type": "string",
  637. "description": "Optional one-line description of the phase."
  638. },
  639. "provider": {
  640. "type": "string",
  641. "description": "Optional provider override this phase is expected to use."
  642. },
  643. "model": {
  644. "type": "string",
  645. "description": "Optional model override this phase is expected to use."
  646. }
  647. },
  648. "required": [
  649. "title"
  650. ]
  651. }
  652. }
  653. },
  654. "required": [
  655. "name",
  656. "description"
  657. ]
  658. },
  659. "args": {
  660. "type": "object",
  661. "description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).",
  662. "additionalProperties": true
  663. }
  664. },
  665. "required": [
  666. "script",
  667. "meta"
  668. ]
  669. }
  670. },
  671. {
  672. "name": "write",
  673. "description": "Create or fully replace a UTF-8 text file.",
  674. "parameters": {
  675. "type": "object",
  676. "properties": {
  677. "file_path": {
  678. "type": "string",
  679. "description": "Path to write, resolved by the filesystem backend."
  680. },
  681. "content": {
  682. "type": "string",
  683. "description": "Full UTF-8 text content to write."
  684. },
  685. "sandbox_permissions": {
  686. "type": "string",
  687. "description": "The wider sandbox mode this file operation needs. Only valid as a one-shot retry of an operation the sandbox just denied; requires justification and user approval.",
  688. "enum": [
  689. "workspace-write",
  690. "danger-full-access"
  691. ]
  692. },
  693. "justification": {
  694. "type": "string",
  695. "description": "Required with sandbox_permissions: one sentence for the user explaining why this exact file operation needs the wider access."
  696. }
  697. },
  698. "required": [
  699. "file_path",
  700. "content"
  701. ]
  702. }
  703. }
  704. ],
  705. "changes": []
  706. }