CLI runtime integration
CLI runtime integration
Auto-start the aasm CLI runtime sidecar from a Go agent workflow, and fall back
gracefully to offline governance when the binary isn’t installed. This is the
example that touches the aasm binary directly.
What this example demonstrates
- Using
assembly.InitAssemblyto probe for and auto-start theaasmsidecar. - Handling
assembly.ErrBinaryNotFoundgracefully whenaasmisn’t installed. - Falling back to offline mock governance when the sidecar is unavailable.
- Using
scripts/run-with-aasm.shto orchestrate sidecar startup before running. - The relationship between the
aasmbinary, the SDK, and the governance layer.
The framework / library
No agent framework — the moving part here is the aasm CLI runtime, the
sidecar process from the
agent-assembly core repo.
The example uses the SDK’s
assembly.InitAssembly
and assembly.ErrBinaryNotFound
to manage that sidecar.
How it works
main.gocallsassembly.InitAssembly("cli-runtime-demo")— this probes127.0.0.1:7878(assembly.DefaultRuntimeHost/assembly.DefaultPort) and, if the sidecar isn’t already running, finds and spawns theaasmbinary.- If
assembly.ErrBinaryNotFoundis returned (detected witherrors.Is), the example logs an install hint and falls back to the offline mock client — a non-fatal condition. - If the sidecar is reachable,
buildGovernanceClientlogs the sidecar address. For this example it still returns the offline mock client; in production you would swap that for a real transport-backedGovernanceClient. - A governed
echoToolcall runs throughassembly.WrapTools. scripts/run-with-aasm.shhandles sidecar startup orchestration for CI: it runsaasm serve --port, waits for the port to open, then runs the example.
Prerequisites & running it
Complete Preparing the runtime environment
first — including the optional aasm install if you want the full sidecar path.
Then:
cd agent-assembly-examples/go/cli-runtime-integration
go mod downloadFallback mode (always works, no aasm needed):
go run .Full sidecar mode (requires aasm on PATH):
bash scripts/run-with-aasm.shThe script honours AASM_PORT (default 7878) and WAIT_SECONDS (default 5).
Code walkthrough
startSidecar calls InitAssembly and treats a missing binary as recoverable:
func startSidecar() bool {
fmt.Println("[runtime] probing for aasm sidecar...")
err := assembly.InitAssembly("cli-runtime-demo")
if err != nil {
if errors.Is(err, assembly.ErrBinaryNotFound) {
fmt.Println("[runtime] aasm binary not found — continuing in offline fallback mode")
fmt.Println("[runtime] install aasm: brew install agent-assembly/tap/aasm")
return false
}
log.Printf("[runtime] sidecar init warning: %v", err)
return false
}
fmt.Printf("[runtime] sidecar ready at %s:%d\n", assembly.DefaultRuntimeHost, assembly.DefaultPort)
return true
}buildGovernanceClient logs which path was taken, then returns the mock client
the example wraps its tool with:
func buildGovernanceClient(sidecarRunning bool) assembly.GovernanceClient {
if sidecarRunning {
fmt.Printf("[runtime] sidecar is running — governance calls will reach %s:%d\n",
assembly.DefaultRuntimeHost, assembly.DefaultPort)
fmt.Println("[runtime] using offline mock client for this example (swap for real transport in production)")
} else {
fmt.Println("[runtime] using offline mock governance client")
}
return &mockClient{}
}The scripts/run-with-aasm.sh helper starts the sidecar, waits for the port,
runs the example, and stops the sidecar on exit:
aasm serve --port "$AASM_PORT" >>"$AASM_LOG" 2>&1 &
AASM_PID=$!
# wait for 127.0.0.1:$AASM_PORT to open, then:
go run .Notes & caveats
The
aasmbinary is not bundled with the Go SDK. It must be installed separately (Homebrew, the curl installer, orgo install). See Preparing the runtime environment for the install commands.
Even in full sidecar mode, this example uses the mock client for the actual governance calls — it demonstrates starting the sidecar, not speaking a real transport to it. Swap
mockClientfor a transport-backedGovernanceClientto route decisions through the running sidecar in production.
Troubleshooting: if
sidecar failed to start, check.aasm-runtime.login the working directory. If port7878is already in use, anotheraasminstance is running and the example connects to it.
Expected behavior
Fallback mode (no aasm binary):
[runtime] probing for aasm sidecar...
[runtime] aasm binary not found — continuing in offline fallback mode
[runtime] install aasm: brew install agent-assembly/tap/aasm
[runtime] using offline mock governance client
[assembly] governance: ALLOWED tool=echo input="Hello from the CLI runtime!"
[assembly] tool result: Hello from the CLI runtime!With aasm installed:
[runtime] probing for aasm sidecar...
[runtime] sidecar ready at 127.0.0.1:7878
[runtime] sidecar is running — governance calls will reach 127.0.0.1:7878
[runtime] using offline mock client for this example (swap for real transport in production)
[assembly] governance: ALLOWED tool=echo input="Hello from the CLI runtime!"
[assembly] tool result: Hello from the CLI runtime!go test ./... verifies the ErrBinaryNotFound fallback path offline, without
needing aasm installed.
Links
- Example directory:
go/cli-runtime-integration README.mdassembly.InitAssembly·assembly.ErrBinaryNotFound- Related: Troubleshooting