Skip to content
Crystal CodeDocs
ENEnglish

Exec tool sets

The host starts the process with ProcessStartInfo.ArgumentList (no bash -lc, no one-line command string). Working directory is the workspace root. The child environment inherits the host process and also receives five variables, rewritten for that process only:

Variable Value
CRYSTAL_WORKSPACE Absolute workspace root
CRYSTAL_SESSION Current session id
CRYSTAL_APPROVAL Current approval mode (plan, default, edit, review, audit, or full)
CRYSTAL_TOOL_DATA Absolute global data directory for this set, {home}/data/tools/<directory>
CRYSTAL_PROJECT_DATA Absolute per-workspace data directory for this set, <workspace>/.crystal/data/tools/<directory>

Secrets are not added. CRYSTAL_HOME is not set for the tool. The two data directories are host-resolved and created lazily the first time the tool runs. A directory that cannot be created is not reported, so create it when it is missing. They are separate from the set install directory; keep them free of secrets.

A bare executable name is resolved inside the set directory when that file exists; otherwise it may PATH-search. A relative path that contains a directory separator must stay inside the set directory. An absolute path is used as given.

Final argv is: set command + this tool’s command + mapped flags from this tool’s argv map. For shorthand, there is no extra suffix.

Stdin JSON (stdin: true, default): write the fenced argument object as UTF-8 JSON without a BOM, then close stdin. Same body for a one-tool or many-tool set. The child already knows which subcommand it is from argv.

Argv (argv map): for each listed property that is present, append flag, then the scalar string form. Allowed JSON kinds: string, number, boolean. A string array appends flag value for each element. Objects, nulls, and mixed arrays refuse the call with a model-visible English error. Property order follows the argv object order in the file.

Both: stdin gets the full fenced object and argv gets prefix, suffix, and mapped scalars.

Stdin off: stdin is still redirected and closed so the child does not block.

Content output ("output": "content", default text): stdout must be one UTF-8 JSON object. text is an optional string. images is an optional array of at most 8 objects. Each image sets mimeType (image/png, image/jpeg, image/gif, or image/webp) and exactly one of base64 or path. base64 may contain whitespace. path must be a regular file inside the workspace; credential paths, directories, and pipes are rejected. Bytes must match the declared type and the 20 MiB host limit. The host opens a path only when the image will be attached, and that read observes cancellation. Stderr is appended to text. A non-zero exit fails the call and does not attach images. On a text-only turn, a result that contains images fails with “This model cannot accept tool images.” On an image-capable turn the same tool is also registered as a multimodal tool, and accepted images follow the existing marker path. Invalid JSON fails the call and keeps a preview of stdout. Large images should use path, because stdout is still truncated to the tool output limit before parsing.

Non-zero exit is ToolResultStatus.Failure. The timeout starts when the process starts and covers stdin writing, process exit, and stdout/stderr reading. Image files named by content JSON are not part of that process timeout. "timeoutSeconds": "unlimited" disables this per-call timeout; user and turn cancellation still apply. Timeout, cancellation, and stdin failure kill the process tree when the OS allows it. For output: text, stdout then stderr are concatenated, truncated, and returned as ToolOutput text.

Several exec tools should live in one set when they share a binary. That is the same unit as a multi-ITool assembly: one install, one ALC or one executable, many catalog entries.