Skip to main content
Version: 0.5.0

Custom Check Dependencies

Custom checks let you write validation scripts for requirements that don't fit the built-in dependency types. Check tool versions, configuration validity, or any other custom requirement.

Basic Usage

depends_on: {
custom_checks: [
{
alternatives: [{
name: "docker-running"
check_script: "docker info > /dev/null 2>&1"
}]
}
]
}

If the check fails:

✗ Dependencies not satisfied

Command 'build' has unmet dependencies:

Failed Custom Checks:
• go-version - check script returned non-zero exit code

Ensure all requirements are met and try again.

Check Properties

PropertyRequiredDescription
nameYesIdentifier for error messages
check_scriptYesScript to execute (using the selected runtime's shell)
expected_codeNoExpected exit code (default: 0)
expected_outputNoRegex pattern to match output
Runtime-Aware Execution

Custom check scripts are executed using the runtime's shell: the host shell for native runtime, the built-in sh interpreter for virtual runtime, or the container's shell for container runtime. Write your check_script accordingly — for example, a native check can rely on host-specific tools, while a container check only sees what's inside the container.

Exit Code Validation

By default, a check passes if the script exits with code 0:

custom_checks: [
{
name: "docker-running"
check_script: "docker info > /dev/null 2>&1"
// Passes if exit code is 0
}
]

Expect a different exit code:

custom_checks: [
{
name: "not-production"
check_script: "test "$ENV" = 'production'"
expected_code: 1 // Should fail (not be production)
}
]

Output Validation

Check that output matches a pattern:

custom_checks: [
{
name: "node-version"
check_script: "node --version"
expected_output: "^v(18|20|22)." // Major version 18, 20, or 22
}
]

Both conditions must pass when used together:

custom_checks: [
{
name: "go-version"
check_script: "go version"
expected_code: 0 // Must succeed
expected_output: "go1.2[6-9]" // Must be Go 1.26+
}
]

Alternatives (OR Semantics)

Provide alternative checks:

custom_checks: [
{
alternatives: [
{
name: "go-1.26"
check_script: "go version | grep -q 'go1.26'"
},
{
name: "go-1.27"
check_script: "go version | grep -q 'go1.27'"
}
]
}
]

The dependency is satisfied if any alternative passes.

Real-World Examples

Tool Version Check

{
name: "build"
depends_on: {
tools: [{alternatives: ["go"]}]
custom_checks: [
{
name: "go-1.26-or-higher"
check_script: """
version=$(go version | grep -oE 'go[0-9]+.[0-9]+' | head -1)
major=$(echo $version | cut -d. -f1 | tr -d 'go')
minor=$(echo $version | cut -d. -f2)
[ "$major" -ge 1 ] && [ "$minor" -ge 26 ]
"""
}
]
}
implementations: [...]
}

Docker Running Check

{
name: "docker-build"
depends_on: {
tools: [{alternatives: ["docker"]}]
custom_checks: [
{
name: "docker-daemon"
check_script: "docker info > /dev/null 2>&1"
}
]
}
implementations: [{
script: "docker build -t myapp ."
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
}

Git Status Check

{
name: "release"
depends_on: {
tools: [{alternatives: ["git"]}]
custom_checks: [
{
name: "clean-working-tree"
check_script: "test -z "$(git status --porcelain)""
},
{
name: "on-main-branch"
check_script: "test "$(git branch --show-current)" = 'main'"
}
]
}
implementations: [{
script: "./scripts/release.sh"
runtimes: [{name: "native"}]
platforms: [{name: "linux"}, {name: "macos"}]
}]
}

Configuration Validation

{
name: "deploy"
depends_on: {
filepaths: [{alternatives: ["config.yaml"]}]
custom_checks: [
{
name: "valid-yaml"
check_script: "python3 -c 'import yaml; yaml.safe_load(open("config.yaml"))'"
},
{
name: "has-required-fields"
check_script: """
grep -q 'database:' config.yaml &&
grep -q 'server:' config.yaml
"""
}
]
}
implementations: [...]
}

Memory/Resource Check

{
name: "build heavy"
depends_on: {
custom_checks: [
{
name: "enough-memory"
check_script: """
# Check for at least 4GB free memory
free_mb=$(free -m | awk '/^Mem:/{print $7}')
[ "$free_mb" -ge 4096 ]
"""
},
{
name: "enough-disk"
check_script: """
# Check for at least 10GB free disk
free_gb=$(df -BG . | awk 'NR==2{print $4}' | tr -d 'G')
[ "$free_gb" -ge 10 ]
"""
}
]
}
implementations: [...]
}

Kubernetes Context

{
name: "deploy"
depends_on: {
tools: [{alternatives: ["kubectl"]}]
custom_checks: [
{
name: "correct-context"
check_script: "kubectl config current-context"
expected_output: "^production-cluster$"
},
{
name: "cluster-reachable"
check_script: "kubectl cluster-info > /dev/null 2>&1"
}
]
}
implementations: [...]
}

Multiple Version Options

{
name: "build"
depends_on: {
custom_checks: [
{
alternatives: [
{
name: "python-3.11"
check_script: "python3 --version"
expected_output: "^Python 3.11"
},
{
name: "python-3.12"
check_script: "python3 --version"
expected_output: "^Python 3.12"
}
]
}
]
}
implementations: [...]
}

Container Context

For container runtime, custom checks run inside the container:

{
name: "build"
implementations: [{
script: "npm run build"
runtimes: [{name: "container", image: "node:20"}]
platforms: [{name: "linux"}]
depends_on: {
custom_checks: [
{
name: "node-version"
// This runs INSIDE the container
check_script: "node --version"
expected_output: "^v20."
}
]
}
}]
}

Script Tips

Keep Scripts Simple

// Good - simple and clear
check_script: "go version | grep -q 'go1.26'"

// Avoid - complex and fragile
check_script: """
set -e
version=$(go version 2>&1)
if [ $? -ne 0 ]; then exit 1; fi
echo "$version" | grep -qE 'go1.(2[6-9]|[3-9][0-9])'
"""

Use Proper Exit Codes

// Script should exit 0 for success, non-zero for failure
check_script: """
if [ -f "required-file" ]; then
exit 0
else
exit 1
fi
"""

Handle Missing Commands

check_script: "command -v mytools > /dev/null && mytool --check"

Best Practices

  1. Name checks clearly: Use descriptive names for error messages
  2. Keep scripts simple: One check, one purpose
  3. Use exit codes: Return 0 for success, non-zero for failure
  4. Add output validation: When version format matters
  5. Consider alternatives: Offer multiple valid configurations

Next Steps