Skip to main content
Version: v4 (current)

CLI Provider Protocol

Write orchestrator providers in any language - Go, Python, Rust, shell, or anything that can read stdin and write stdout. The CLI provider protocol uses JSON messages over stdin/stdout with the subcommand as the first argument.

Quick Start

Set providerExecutable to the path of your executable:

- uses: game-ci/unity-builder@v4
with:
providerExecutable: ./my-provider
targetPlatform: StandaloneLinux64

The CLI provider takes precedence over providerStrategy when set.

Protocol

Invocation

<executable> <subcommand>

Orchestrator spawns your executable once per operation, passing the subcommand as argv[1].

Input

A single JSON object written to stdin, then stdin is closed:

{
"command": "run-task",
"params": {
"buildGuid": "abc-123",
"image": "unityci/editor:2022.3.0f1-linux-il2cpp-3",
"commands": "/bin/sh -c 'unity-editor -batchmode ...'",
"mountdir": "/workspace",
"workingdir": "/workspace",
"environment": [{ "name": "UNITY_LICENSE", "value": "..." }],
"secrets": []
}
}

Output

Write a single JSON object to stdout when the operation completes:

{
"success": true,
"result": "Build completed successfully"
}

On failure:

{
"success": false,
"error": "Container exited with code 1"
}

Streaming Output

During run-task and watch-workflow, non-JSON lines on stdout are treated as real-time build output and forwarded to the orchestrator logs. Only the final JSON line is parsed as the response.

This means your provider can freely print build logs:

Pulling image...
Starting build...
[Build] Compiling scripts...
[Build] Build succeeded
{"success": true, "result": "Build completed"}

stderr

Everything written to stderr is forwarded to the orchestrator logger. Use stderr for diagnostic messages, warnings, and debug output.

Subcommands

SubcommandPurposeTimeout
setup-workflowInitialize infrastructure300s
run-taskExecute the buildNo limit
cleanup-workflowTear down infrastructure300s
garbage-collectRemove old resources300s
list-resourcesList active resources300s
list-workflowList active workflows300s
watch-workflowWatch a workflow until completionNo limit

run-task and watch-workflow have no timeout because builds can run for hours.

Example: Shell Provider

A minimal provider that runs builds via Docker:

#!/bin/bash
case "$1" in
setup-workflow)
read request
echo '{"success": true, "result": "ready"}'
;;
run-task)
read request
image=$(echo "$request" | jq -r '.params.image')
commands=$(echo "$request" | jq -r '.params.commands')
# Stream build output, then send JSON result
docker run --rm "$image" /bin/sh -c "$commands" 2>&1
echo '{"success": true, "result": "done"}'
;;
cleanup-workflow)
read request
echo '{"success": true, "result": "cleaned"}'
;;
garbage-collect)
read request
docker system prune -f >&2
echo '{"success": true, "result": "pruned"}'
;;
list-resources)
read request
echo '{"success": true, "result": []}'
;;
list-workflow)
read request
echo '{"success": true, "result": []}'
;;
watch-workflow)
read request
echo '{"success": true, "result": ""}'
;;
*)
echo '{"success": false, "error": "Unknown command: '"$1"'"}' >&2
exit 1
;;
esac

Make it executable and point providerExecutable at it:

- uses: game-ci/unity-builder@v4
with:
providerExecutable: ./my-provider.sh
targetPlatform: StandaloneLinux64

CLI Provider vs TypeScript Provider

FeatureCLI ProviderTypeScript Provider
LanguageAnyTypeScript/JavaScript
SetupproviderExecutableproviderStrategy
CommunicationJSON stdin/stdoutDirect function calls
Streamingstdout linesNative logging
DistributionAny executableGitHub, NPM, local path
DependenciesNone (self-contained)Node.js runtime

Use CLI providers when you want to write in a non-TypeScript language, need to wrap an existing tool, or want a self-contained executable with no Node.js dependency.

Use TypeScript custom providers when you want direct access to the BuildParameters object and orchestrator internals.