Skip to content

exec component ​

The exec component runs a shell command and returns a structured result: {success, exitCode, stdout, stderr, command, result, timedOut}. It is a kdeps component from the components asset set: call it with a component: resource, no install step. Its call is the kdeps API's exec tool, which runs the native exec executor. A workflow that uses exec: directly - primary or in a before:/after: step - is rejected.

It works in both modes: as a DAG step in workflow mode, and inside any workflow the LLM calls as a tool in agent mode.

component: execPOST /tools/exec/callsh -c command(cmd /C on Windows)command + argsexecuted directly{success, exitCode,stdout, stderr, timedOut}no argsargs given

Configuration ​

yaml
# resources/system-info.yaml
actionId: systemInfo
name: System Information
component:
  name: exec                       # from the components asset set; a components/exec/ of your own wins
  with:
    command: "uname -a && date"    # required; multiline scripts allowed
    timeout: 10s                   # hard stop; the call fails after it, no retry
InputTypeRequiredDefaultDescription
commandstringyes-The shell command to run. Supports multiline scripts
argsarrayno-Arguments for command. When set, command runs directly instead of through a shell
workingDirstringnoprocess working directoryThe directory the command runs in
envobjectno-Extra environment variables for this execution; the process environment is inherited
timeoutstringnoKDEPS_EXEC_TIMEOUT, else the kdeps defaultMaximum time allowed (e.g. 30s, 1m)

Shell or direct execution ​

Without args, the command string runs through sh -c on Unix and cmd /C on Windows, so pipes, &&, globs, and redirections work.

With args, the command is executed directly with an argv array - no shell - which avoids quoting problems and shell injection:

yaml
# resources/grep-logs.yaml
actionId: grepLogs
component:
  name: exec
  with:
    command: grep                       # executed directly, not through sh
    args: ["-c", "ERROR", "/var/log/app.log"]

Output ​

json
{
  "success": true,
  "exitCode": 0,
  "stdout": "Linux kdeps 6.8.0\nWed Oct 21 09:00:00 UTC 2026\n",
  "stderr": "",
  "command": "uname -a && date",
  "result": "Linux kdeps 6.8.0\nWed Oct 21 09:00:00 UTC 2026\n",
  "timedOut": false
}

Read fields with output('systemInfo').stdout, output('systemInfo').exitCode, and so on.

KeyTypeDescription
successbooltrue when the command exited 0
exitCodeintegerProcess exit code; -1 on timeout
stdoutstringCaptured standard output
stderrstringCaptured standard error
commandstringThe full command line that ran, arguments included
resultstringSame as stdout; kept for compatibility with simple consumers
timedOutbooltrue when the timeout killed the command

A non-zero exit does not return this map: the call fails with command failed: ... and onError: on the resource decides what happens next.

Examples ​

Multi-line script:

yaml
# resources/report.yaml
actionId: report
component:
  name: exec
  with:
    command: |
      echo "Starting process..."
      date
      uname -a
      echo "Done!"
    timeout: 30s

Interpolate request data:

yaml
# resources/lookup.yaml
actionId: lookup
component:
  name: exec
  with:
    command: "curl -s https://api.example.com/users/{{ get('user_id') }}"
    timeout: 30s

Structured output - echo JSON, then parse it:

yaml
# resources/git-info.yaml
actionId: gitInfo
component:
  name: exec
  with:
    command: |
      echo "{\"branch\": \"$(git rev-parse --abbrev-ref HEAD)\", \"commit\": \"$(git rev-parse --short HEAD)\"}"
    workingDir: /app
    timeout: 30s

---
actionId: response
requires: [gitInfo]
apiResponse:
  success: true
  response:
    branch: "{{ fromJSON(output('gitInfo').stdout).branch }}"
    commit: "{{ fromJSON(output('gitInfo').stdout).commit }}"

Run with extra environment variables:

yaml
# resources/whoami.yaml
actionId: whoami
component:
  name: exec
  with:
    command: "echo \"$DEPLOY_ENV\""
    env:
      DEPLOY_ENV: "staging"

Environment variables ​

The command inherits the kdeps process environment, so agentSettings.env values are visible:

yaml
# In workflow.yaml
settings:
  agentSettings:
    env:
      API_TOKEN: "secret-token"
      DEBUG: "true"
yaml
# In a resource
component:
  name: exec
  with:
    command: |
      echo "Token: $API_TOKEN"
      if [ "$DEBUG" = "true" ]; then
        echo "Debug mode enabled"
      fi

env: adds or overrides variables for that one execution.

Errors and timeouts ​

ErrorCause
exec: command is requiredcommand is missing or whitespace
command failed: ...The command exited non-zero; the call fails, exitCode and stderr stay in the logs
command timed out after 30stimeout expired; the process was killed
exec stdout exceeds output limit of N bytesOutput crossed KDEPS_EXEC_MAX_OUTPUT_BYTES

Handle a failing command without stopping the workflow with onError::

yaml
# resources/optional-step.yaml
actionId: optionalStep
component:
  name: exec
  with:
    command: "exit 3"
onError:
  action: continue

Security notes ​

When user input reaches a command, prefer args: over string interpolation - it never goes through a shell:

yaml
# Dangerous -- command injection possible
command: "echo {{ get('user_input') }}"

# Safer -- no shell, each value is one argument
command: echo
args: ["{{ get('user_input') }}"]

Validate input as well:

yaml
validations:
  check:
    - get('user_input') matches '^[a-zA-Z0-9_-]+$'

The workflow-side exec tool has no agent guardrails: unlike bash_exec in agent mode, it does not check KDEPS_ALLOW_BASH or the bash command blocklist. A workflow YAML is trusted configuration; treat command: as code you ship.

See also ​

Released under the Apache 2.0 License.