Skip to content

Command Payloads

Command payloads execute a single binary with a structured list of arguments on the target machine. They are ideal for simple, atomic operations.

A Command is not a freeform terminal line. It is structured:

  • bin — the binary or program to run (e.g. docker).
  • arguments — an ordered list of plain string values passed to the binary (e.g. pull, myregistry/myapp:latest).
  • working_directory — an optional absolute path the binary runs in.

Each argument is delivered to the binary as a separate, literal string. There is no shell parsing a single command line, so shell metacharacters, command chaining, pipes, and shell variable expansion are not available. For anything more complex, use a Script Payload or multiple actions/sequence steps.

Use Commands ForUse Scripts Instead
Single binary invocationsMulti-step workflows
Simple tool invocationsConditional logic
Quick system commandsError handling complexity
Docker/container commandsPiping or redirection

Instead of typing a terminal line, you specify the binary and each argument separately.

To run docker pull myregistry/myapp:latest:

  • bin: docker
  • arguments: pull, myregistry/myapp:latest

Arguments and the working directory support variable placeholders. To pull a parameterized image:

  • bin: docker
  • arguments: pull, {{registry}}/{{image}}:{{tag}}

Variable substitution is not permitted in the bin (binary path) for security reasons — the binary path must be a literal value.

Resolved variables are also injected into the executed process as MANTIS_* environment variables. Variable names are uppercased before the prefix is applied, so a variable named image is available to the process as MANTIS_IMAGE, and a variable named tag is available as MANTIS_TAG. This is how you provide values (including sensitive ones) to a binary without using shell expansion.

For the shell executors (Sh, Bash, Pwsh, Zsh), arguments are validated and any argument containing a shell metacharacter is rejected. The forbidden characters are:

; | & $ ` ( ) { } < > ' " \ ! * ? [ ] # ~

newlines and carriage returns are also forbidden.

This means you cannot:

  • Chain commands with &&, ||, or ;
  • Pipe with |
  • Expand shell variables with $VAR
  • Use command substitution with backticks or $(...)
  • Use globs such as * or ?
  • Use redirection with < or >

For the Default executor, arguments are passed directly to the underlying process and shell metacharacters are not interpreted (and not expanded either) — so there is still no chaining, since no shell is involved.

To run multiple commands, use a Script Payload or split the work across multiple actions / sequence steps.

Choose the appropriate executor for command execution:

ExecutorCommand InterpretationPlatform
DefaultDirect execution (no shell)Cross-platform
Shsh -cLinux/macOS (WSL on Windows)
Bashbash -cLinux/macOS (WSL/Git Bash on Windows)
PwshPowerShellCross-platform
Zshzsh -f -c (no user startup files)Linux/macOS (WSL/MSYS2 on Windows)

Each example lists the binary and its ordered argument strings.

Pull an image:

  • bin: docker
  • arguments: pull, {{image}}:{{tag}}

Start a container:

  • bin: docker
  • arguments: run, -d, --name, {{container_name}}, -p, {{port}}:80, {{image}}

Stopping and removing a container requires two separate operations — run them as two actions or two sequence steps (one docker stop, one docker rm), since you cannot chain them in a single command.

APT (Debian/Ubuntu):

  • bin: apt-get
  • arguments: install, -y, {{package}}

(Run apt-get update as a separate step rather than chaining it.)

YUM (RHEL/CentOS):

  • bin: yum
  • arguments: install, -y, {{package}}

Chocolatey (Windows):

  • bin: choco
  • arguments: install, {{package}}, -y

Systemd:

  • bin: systemctl
  • arguments: restart, {{service_name}}

Windows Services:

  • bin: pwsh (Pwsh executor)
  • arguments: Restart-Service, -Name, {{service_name}}

Download file:

  • bin: curl
  • arguments: -o, {{destination}}, {{url}}

Extract archive:

  • bin: tar
  • arguments: -xzf, {{archive}}, -C, {{destination}}

Two placeholder syntaxes are supported in argument strings and in working_directory:

PatternDescription
{{version}}Mustache-style — replaced with the version variable value
${version}Shell-style — replaced with the version variable value

Both forms resolve from the same set of deployment variables. The bin field does not support substitution.

Arguments are plain ordered strings — there is no type, default, or required metadata attached to an individual argument. Provide the values you need as ordered argument strings.

In addition to placeholder substitution, every resolved variable is injected into the executed process as a MANTIS_* environment variable. Variable names are uppercased before the prefix is applied — for example, the variable tag is available as MANTIS_TAG. This is the supported way to pass values to a binary that reads configuration from the environment.

Commands report success or failure via exit codes:

Exit CodeMeaningMantis Behavior
0SuccessStep marked complete
Non-zeroFailureStep marked failed

The exit code of the invoked binary is used directly. There is no shell, so there is no chaining to influence the reported result — the binary either exits 0 (success) or non-zero (failure).

A Command runs in the Tarsus agent’s default working directory unless you set the working_directory field. Set it to an absolute path:

  • bin: docker
  • arguments: compose, up, -d
  • working_directory: /opt/myapp

The working_directory field supports variable substitution (e.g. /opt/{{app_name}}). Because there is no shell, you cannot change directories with cd && ... — use working_directory or absolute paths instead.

Commands have a configurable timeout (default: 300 seconds). If exceeded:

  • The command is terminated
  • The step is marked as failed
  • The error message indicates a timeout

Set appropriate timeouts for long-running commands:

OperationSuggested Timeout
Docker pull600s (10 min)
Package install300s (5 min)
Service restart60s (1 min)
File downloadVariable by size

Do not embed secret literals in argument strings, and do not attempt $API_KEY-style shell expansion — $ is a forbidden character for shell executors and is never expanded.

Instead, define the secret as a sensitive variable. Resolved variables are injected into the executed process as MANTIS_* environment variables, with the name uppercased, so a sensitive variable named api_key is available to the binary as the MANTIS_API_KEY environment variable. The binary reads it from the environment; the value never appears as a literal in the command definition.

Arguments are passed as literal strings, and shell executors reject shell metacharacters (including *, ?, ;, |, &, and quotes). This prevents command-injection through argument values. Still, validate the variable values you supply — an argument such as {{path}} is substituted verbatim into a single argument string, so ensure it contains the value you intend.

Error: command not found: docker

Solutions:

  • Set bin to an absolute path, e.g. /usr/bin/docker
  • Ensure the binary is in the agent’s PATH
  • Check that the executor selection matches the target OS
Error: permission denied

Solutions:

  • Check file permissions
  • Verify the agent runs with the correct user
Error: argument contains a forbidden character

Solutions:

  • Remove shell metacharacters (;, |, &, $, quotes, globs, etc.) from the argument
  • Split chained operations into separate actions or a script
  • Provide dynamic values as variables ({{name}} / ${name}) rather than shell expansion

If you see {{variable}} (or ${variable}) in the output:

  • Verify the variable is defined for the deployment
  • Check that the name matches exactly (case-sensitive)
  • Ensure the placeholder is in an argument or working_directory, not in bin
  1. Keep commands simple — one binary invocation per command
  2. Use absolute paths — for bin and for working_directory
  3. Use variables{{name}} / ${name} for dynamic argument values
  4. Provide secrets as variables — they surface as MANTIS_* environment variables
  5. Reach for scripts — when you need chaining, pipes, conditionals, or redirection