Skip to content

Script Payloads

Script payloads run a script file that lives in a configured storage backend, enabling complex deployment logic with conditionals, loops, and error handling.

A script payload is not a script body you type into a text box. Instead, it references a file by name (and optional relative path) inside a storage backend you have configured. Mantis tells the target to execute that file with the chosen executor.

Use Scripts ForUse Commands Instead
Multi-step workflowsSingle operations
Conditional logicSimple tool invocations
Error handlingAtomic commands
Loops and iterationQuick system commands
Variable manipulationOne-liners

A script payload is made up of:

FieldDescription
Storage backendThe configured storage where the script file is located.
File nameThe name of the script file to execute.
Relative pathOptional path within the storage backend, if the file lives in a subfolder.
ExecutorHow the script is run (see Executor Reference).
ArgumentsOptional arguments passed to the script.

To create a script payload:

  1. Select a configured storage backend.
  2. Reference the script file by its file name (and relative path if it is in a subfolder).
  3. Choose an executor.
  4. Optionally supply arguments.

The script file itself is authored and stored in your storage backend, not edited inline in Mantis.

The following are examples of script files you would place in your storage backend and then reference from a script payload.

#!/bin/bash
set -e # Exit on error
# Your deployment logic
echo "Starting deployment..."
cd /opt/myapp
# Pull latest code
git pull origin main
# Restart service
systemctl restart myapp
echo "Deployment complete!"
Terminal window
$ErrorActionPreference = "Stop"
Write-Host "Starting deployment..."
# Your deployment logic
Set-Location C:\Apps\MyApp
# Copy new files
Copy-Item -Path "\\server\share\release\*" -Destination "." -Recurse -Force
# Restart service
Restart-Service -Name "MyAppService"
Write-Host "Deployment complete!"
#!/usr/bin/env python3
import subprocess
import sys
def main():
print("Starting deployment...")
# Your deployment logic
result = subprocess.run(["docker", "compose", "up", "-d"], check=True)
print("Deployment complete!")
return 0
if __name__ == "__main__":
sys.exit(main())
ExecutorShebangError Handling
DefaultN/A (direct exec)Process exit code
Sh#!/bin/shset -e
Bash#!/bin/bashset -e
Pwsh#!/usr/bin/env pwsh$ErrorActionPreference = "Stop"

Mantis handles runtime values in two distinct ways, and it is important to use the right one.

Placeholders in the File Name and Arguments

Section titled “Placeholders in the File Name and Arguments”

Mantis substitutes placeholders into the script’s file name and arguments before execution. It uses two placeholder forms:

PatternWhere it appliesExample argument valueResult
{{version}}File name, arguments1.2.31.2.3
${version}File name, argumentslatestlatest

For example, an argument of --version={{version}} becomes --version=1.2.3 before the script runs. A file name of deploy-{{environment}}.sh resolves to deploy-staging.sh.

Values Inside the Script Body: MANTIS_* Environment Variables

Section titled “Values Inside the Script Body: MANTIS_* Environment Variables”

To use runtime values inside a script, read them from environment variables. Mantis merges resolved variables into the execution environment as MANTIS_* environment variables (for example, MANTIS_VERSION, MANTIS_ENVIRONMENT). Your script reads these the normal way for its shell, and the shell on the target expands them as usual.

Bash:

#!/bin/bash
set -e
echo "Deploying version $MANTIS_VERSION to $MANTIS_ENVIRONMENT"
docker pull myregistry/myapp:"$MANTIS_VERSION"
docker tag myregistry/myapp:"$MANTIS_VERSION" myregistry/myapp:current

PowerShell:

Terminal window
$ErrorActionPreference = "Stop"
Write-Host "Deploying version $env:MANTIS_VERSION to $env:MANTIS_ENVIRONMENT"

Python:

import os
version = os.environ.get("MANTIS_VERSION")
print(f"Deploying version {version}")

Define environment variables on the action:

NameValueSensitive
DB_HOSTdb.example.comNo
DB_PASSWORD***Yes

These are in addition to the MANTIS_* variables Mantis injects for resolved deployment variables.

Bash:

#!/bin/bash
echo "Connecting to $DB_HOST"
psql -h "$DB_HOST" -U admin -c "SELECT 1"

PowerShell:

Terminal window
Write-Host "Connecting to $env:DB_HOST"
Invoke-Sqlcmd -ServerInstance $env:DB_HOST -Query "SELECT 1"

Python:

import os
db_host = os.environ.get("DB_HOST")
print(f"Connecting to {db_host}")
#!/bin/bash
set -e # Exit on any error
set -o pipefail # Exit on pipe failures
# Or handle errors explicitly
if ! docker pull myimage; then
echo "Failed to pull image"
exit 1
fi
# Cleanup on error
cleanup() {
echo "Cleaning up..."
rm -f /tmp/deploy-*
}
trap cleanup EXIT
Terminal window
$ErrorActionPreference = "Stop"
try {
# Deployment logic
Copy-Item -Path $source -Destination $dest
Restart-Service -Name $serviceName
}
catch {
Write-Error "Deployment failed: $_"
exit 1
}
finally {
# Cleanup
Remove-Item -Path $tempFiles -ErrorAction SilentlyContinue
}
#!/usr/bin/env python3
import subprocess
import sys
try:
subprocess.run(["docker", "compose", "up", "-d"], check=True)
except subprocess.CalledProcessError as e:
print(f"Deployment failed: {e}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Unexpected error: {e}", file=sys.stderr)
sys.exit(1)

These scripts live in your storage backend. Runtime values are read from MANTIS_* environment variables.

#!/bin/bash
set -e
CURRENT=$(readlink /opt/app/current || echo "blue")
NEW=$([ "$CURRENT" = "blue" ] && echo "green" || echo "blue")
echo "Current: $CURRENT, Deploying to: $NEW"
# Deploy to new slot
cd /opt/app/$NEW
docker compose pull
docker compose up -d
# Health check
for i in {1..30}; do
if curl -sf http://localhost:808${NEW: -1}/health; then
echo "Health check passed"
break
fi
sleep 2
done
# Switch traffic
ln -sfn /opt/app/$NEW /opt/app/current
nginx -s reload
# Stop old
cd /opt/app/$CURRENT
docker compose down
#!/bin/bash
set -e
BACKUP_FILE="/backups/pre-migration-$(date +%Y%m%d-%H%M%S).sql"
echo "Creating backup..."
pg_dump "$DATABASE_URL" > "$BACKUP_FILE"
echo "Running migrations..."
if ! alembic upgrade head; then
echo "Migration failed, restoring backup..."
psql "$DATABASE_URL" < "$BACKUP_FILE"
exit 1
fi
echo "Migrations complete!"
#!/bin/bash
set -e
SERVICES=(web-1 web-2 web-3)
VERSION="$MANTIS_VERSION"
for service in "${SERVICES[@]}"; do
echo "Updating $service..."
# Remove from load balancer
curl -X POST "http://lb/api/remove?host=$service"
# Update service
ssh "$service" "docker pull myapp:$VERSION && docker compose up -d"
# Wait for health
until curl -sf "http://$service/health"; do
sleep 5
done
# Add back to load balancer
curl -X POST "http://lb/api/add?host=$service"
echo "$service updated"
done
echo "Rolling update complete!"
#!/bin/bash
set -e
ARTIFACT_URL="$MANTIS_ARTIFACT_URL"
DEST_DIR="/opt/app"
# Download artifact
curl -fSL "$ARTIFACT_URL" -o /tmp/release.tar.gz
# Extract
tar -xzf /tmp/release.tar.gz -C "$DEST_DIR"
# Cleanup
rm /tmp/release.tar.gz
#!/bin/bash
set -e
# Generate config from template using injected MANTIS_* values
cat > /opt/app/config.yml << EOF
server:
host: 0.0.0.0
port: ${MANTIS_PORT}
database:
host: ${DB_HOST}
name: ${MANTIS_DB_NAME}
logging:
level: ${MANTIS_LOG_LEVEL}
EOF
echo "Configuration written"
#!/bin/bash
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1"
}
log "Starting deployment"
log "Version: $MANTIS_VERSION"
log "Environment: $MANTIS_ENVIRONMENT"
# ... deployment steps ...
log "Deployment complete"
#!/bin/bash
echo "Step 1/4: Pulling images..."
docker pull myapp:"$MANTIS_VERSION"
echo "Step 2/4: Stopping services..."
docker compose down
echo "Step 3/4: Starting services..."
docker compose up -d
echo "Step 4/4: Running health checks..."
./health-check.sh
echo "Deployment successful"

Bad:

Terminal window
echo "Using password: $DB_PASSWORD"

Good:

Terminal window
echo "Connecting to database..."
# Password is in environment, not logged
#!/bin/bash
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT
# Use $TEMP_DIR for temporary files
#!/bin/bash
set -e
VERSION="$MANTIS_VERSION"
# Validate version format
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid version format: $VERSION"
exit 1
fi
  1. Minimize network calls - Batch operations where possible
  2. Use parallel execution - When operations are independent
  3. Cache dependencies - Avoid re-downloading unchanged files
  4. Clean up - Remove temporary files to free disk space

Cause: set -e with a failing command

Solution: Handle expected failures explicitly:

Terminal window
set -e
some_command || true # Ignore failure

Cause: Using single quotes, which prevent the shell from expanding variables.

Fix:

Terminal window
# Wrong
echo 'Version: $MANTIS_VERSION'
# Right
echo "Version: $MANTIS_VERSION"

Placeholders Not Substituted Inside the Script

Section titled “Placeholders Not Substituted Inside the Script”

Cause: Using {{...}} or ${...} placeholders inside the script body. Mantis only substitutes placeholders into the file name and arguments, not into script contents.

Fix: Read runtime values from MANTIS_* environment variables inside the script instead.

Cause: A script file created on Windows may use CRLF (\r\n) line endings.

Fix: Convert the file to Unix (LF) line endings before storing it in your storage backend.