workflow-manager
Workflow manager for batch command execution with conditional logic
File Information
| Property | Value |
|---|---|
| Binary Name | workflow-manager |
| Version | 9.8.4 (build 320) |
| Build Date | Not disclosed |
| Rust Version | 1.82.0 |
| File Size | 8.6MB |
| Author | Warith Al Maawali |
| License | Proprietary |
| Category | Kodachi Binary |
| Description | Workflow manager for batch command execution with conditional logic |
| Git Commit | unknown |
| Metadata Generated | 2026-08-10T13:23:00Z |
| Binary Timestamp | Unknown |
| JSON Data | View Raw JSON |
SHA256 Checksum
c14889d46b98fef8554e0b466e8ed06ebabca812864ea76f07ba9257a87be2a5
Features
| # | Feature |
|---|---|
| 1 | Template-based workflow management |
| 2 | Conditional command execution |
| 3 | Batch processing with retry logic |
| 4 | State tracking and logging |
| 5 | Concurrent execution support |
| 6 | Pause steps with user confirmation |
| 7 | Substring, regex and JSON path conditions |
| 8 | JSON path subset support (dot fields + array indexes) |
| 9 | Prerequisites validation before execution |
| 10 | System state checking and probes |
| 11 | Reusable probe functions for conditions |
Security Features
| Feature | Description |
|---|---|
| Authentication | Not provided by cli-core (see online-auth) |
| Encryption | Not provided by cli-core |
| Input Validation | Argument parsing via clap; per-command validation is the consumer's responsibility |
| Rate Limiting | Not provided by cli-core |
System Requirements
| Requirement | Value |
|---|---|
| OS | Linux (Debian-based) |
| Privileges | root/sudo for system operations |
| Dependencies | OpenSSL, libcurl |
Global Options
| Flag | Description |
|---|---|
-h, --help |
Print help information |
-v, --version |
Print version information |
-n, --info |
Display detailed information |
-e, --examples |
Show usage examples |
--json |
Output in JSON format |
-o, --output-format <FORMAT> |
Force output format (text|json) |
--json-pretty |
Pretty-print JSON output with indentation |
--json-human |
Enhanced JSON output with improved formatting (like jq) |
--json-filter <FIELD1,FIELD2> |
Return only specified JSON fields (comma-separated) |
--fields <FIELD_LIST> |
Select specific fields to include in output (comma-separated) |
--limit <NUMBER> |
Limit number of results returned |
--offset <NUMBER> |
Skip first N results (for pagination) |
--verbose |
Enable verbose output |
--quiet |
Suppress non-essential output |
--no-color |
Disable colored output |
Commands
Diagnostics
prereq
Validate workflow prerequisites
Usage:
workflow-manager prereq <check|validate> <TEMPLATE>
Options:
<SUBCOMMAND>: check, or validate (an alias for check)<TEMPLATE>: Template whose prerequisites block is evaluated
Examples:
workflow-manager prereq check initial_terminal_setup_wireguard_torrify
workflow-manager prereq validate my-workflow
workflow-manager prereq check my-workflow --json
state
Query system state
Usage:
workflow-manager state [FIELD]
Options:
[FIELD]: Single state to query (online, torrify, tor_running, security_score, routing_mode, authenticated, ...). Omit to return all 20--json: Emit the state as a JSON envelope (global flag)
Examples:
workflow-manager state
workflow-manager state online
workflow-manager state security_score --json
Execution
run
Run a workflow template
Usage:
workflow-manager run <TEMPLATE> [OPTIONS]
Options:
<TEMPLATE>: Template to execute--dry-run: List the steps that would run without executing any of them--kill-policy <POLICY>: What to do when a step fails: stop, continue or skip_remaining. Overrides global_settings.kill_policy--max-log-size <BYTES>: Cap the run log size in bytes. Overrides global_settings.max_log_size--param <KEY=VALUE>: Override a declared workflow parameter. Repeat for multiple parameters-y, --yes: Skip ordinary top-level [y/N] prompts in text mode; never approves high-risk or included child steps--param <NAME=VALUE>: Override a workflow parameter; may be repeated--approved-step <JSON>: Carry one exact dashboard-approved child step record; may be repeated
Examples:
workflow-manager run my-workflow --dry-run
workflow-manager run my-workflow
workflow-manager run my-workflow --kill-policy continue
workflow-manager run my-workflow --max-log-size 20971520
workflow-manager run my-workflow --param interface=eth0 --param mode=safe
workflow-manager run my-workflow --yes
workflow-manager run my-workflow --json
Steps
add
Add a step to a workflow template
Usage:
workflow-manager add <TEMPLATE> <COMMAND> [OPTIONS]
Options:
<TEMPLATE>: Template to append the step to<COMMAND>: Command to execute. A comma separated list creates one step per command--description <TEXT>: Step description-c, --condition <TYPE>: Basic condition: always, if_success or if_fail--if-probe <NAME>: Run only if the named probe from the profile's probes block matches--if-probe-expect <JSON>: Value the probe must return (JSON: true, 4, "ok")--if-state <NAME>: Run only if a live system state matches (see `workflow-manager state`)--if-state-expect <JSON>: Value the state must have (JSON: true, false, "wireguard")--if-expression <EXPR>: Boolean expression over probe('NAME') and state.NAME, joined with && and ||--if-contains <TEXT>: Run only if the previous step's output contains TEXT (substring, case sensitive)--if-not-contains <TEXT>: Run only if the previous output does not contain TEXT--if-equals <VALUE>: Run only if the previous output equals VALUE exactly (trimmed)--if-regex <PATTERN>: Run only if the previous output matches the regex--if-not-regex <PATTERN>: Run only if the previous output does not match the regex--if-json-path <EXPR>: Run only if a JSON field matches, e.g. '$.status="connected"' (writes if_json_path_equals)-t, --timeout <SECONDS>: Step timeout. Falls back to global_settings.default_timeout when omitted--confirm: Prompt [y/N] before this step runs (text mode only)-w, --working-dir <PATH>: Directory to run the step from--nice-level <N>: Process priority, -20 (highest) to 19 (lowest). Negative values need root--env <VARS>: Comma separated allowlist of environment variables passed to the step
Examples:
workflow-manager add my-workflow 'echo Hello World'
workflow-manager add my-workflow 'tar czf backup.tar.gz /data' -t 600 --description 'Archive data'
workflow-manager add my-workflow 'cleanup.sh' -c if_success
workflow-manager add my-workflow './notify.sh' --if-contains 'ERROR'
workflow-manager add my-workflow './handle-connected.sh' --if-json-path '$.status="connected"'
workflow-manager add my-workflow './tor-ready.sh' --if-state tor_running --if-state-expect true
workflow-manager add my-workflow './low-score-fix.sh' --if-expression "state.security_score < 60"
workflow-manager add w1 "ip-fetch","online-auth check-login","ip addr show"
pause
Add a pause step to a workflow template
Usage:
workflow-manager pause <TEMPLATE> [OPTIONS]
Options:
<TEMPLATE>: Template to append the pause to-m, --message <TEXT>: Message shown to the user while the workflow waits-c, --condition <TYPE>: Basic condition: always, if_success or if_fail
Examples:
workflow-manager pause my-workflow -m 'Review results before continuing'
workflow-manager pause backup -m 'Verify backup integrity' -c if_success
include
Add an include step to a workflow template (includes another profile)
Usage:
workflow-manager include <TEMPLATE> <PROFILE> [OPTIONS]
Options:
<TEMPLATE>: Template to append the include to<PROFILE>: Existing profile whose steps are expanded in place at run time--description <TEXT>: Step description-c, --condition <TYPE>: Basic condition: always, if_success or if_fail--if-probe <NAME>: Run only if the named probe from the profile's probes block matches--if-probe-expect <JSON>: Value the probe must return (JSON: true, 4, "ok")--if-state <NAME>: Run only if a live system state matches (see `workflow-manager state`)--if-state-expect <JSON>: Value the state must have (JSON: true, false, "wireguard")--if-expression <EXPR>: Boolean expression over probe('NAME') and state.NAME, joined with && and ||
Examples:
workflow-manager include my-workflow shared-prereqs --description 'Reusable setup steps'
workflow-manager include my-workflow tor-recovery -c if_fail
workflow-manager include my-workflow base-recovery-sequence --if-state online --if-state-expect true
update
Update a step in a workflow template
Usage:
workflow-manager update <TEMPLATE> <STEP_ID> [COMMAND] [OPTIONS]
Options:
<TEMPLATE>: Template to edit<STEP_ID>: Step number to update, as shown by `workflow-manager show`[COMMAND]: New command for a command step. Omit it to change only the flags below-m, --message <TEXT>: New message for a pause step--profile <NAME>: New profile for an include step--description <TEXT>: New step description-c, --condition <TYPE>: Basic condition: always, if_success or if_fail--if-probe <NAME>: Run only if the named probe from the profile's probes block matches--if-probe-expect <JSON>: Value the probe must return (JSON: true, 4, "ok")--if-state <NAME>: Run only if a live system state matches (see `workflow-manager state`)--if-state-expect <JSON>: Value the state must have (JSON: true, false, "wireguard")--if-expression <EXPR>: Boolean expression over probe('NAME') and state.NAME, joined with && and ||--if-contains <TEXT>: Run only if the previous step's output contains TEXT (substring, case sensitive)--if-not-contains <TEXT>: Run only if the previous output does not contain TEXT--if-equals <VALUE>: Run only if the previous output equals VALUE exactly (trimmed)--if-regex <PATTERN>: Run only if the previous output matches the regex--if-not-regex <PATTERN>: Run only if the previous output does not match the regex--if-json-path <EXPR>: Run only if a JSON field matches, e.g. '$.status="connected"' (writes if_json_path_equals)--clear-condition: Drop the stored condition payload and reset to the basic type given by -c-t, --timeout <SECONDS>: New step timeout--confirm <BOOL>: Set or clear the confirm flag (true or false)-w, --working-dir <PATH>: New working directory for the step--nice-level <N>: New process priority, -20 (highest) to 19 (lowest)--env <VARS>: New comma separated environment allowlist
Examples:
workflow-manager update my-workflow 1 'echo Updated Command' -t 300
workflow-manager update my-workflow 2 --if-contains 'ERROR' --description 'Alert on error'
workflow-manager update my-workflow 2 --clear-condition -c always
workflow-manager update my-workflow 3 -m 'Verify the archive, then press Enter' --confirm true
workflow-manager update my-workflow 4 --profile base-recovery-sequence
delete-step
Delete a step from a workflow template
Usage:
workflow-manager delete-step <TEMPLATE> <STEP_ID>
Options:
<TEMPLATE>: Template to edit<STEP_ID>: Step number to remove, as shown by `workflow-manager show`
Examples:
workflow-manager delete-step my-workflow 2
workflow-manager show my-workflow && workflow-manager delete-step my-workflow 3
Templates
create
Create a new workflow template
Usage:
workflow-manager create <NAME> [OPTIONS]
Options:
<NAME>: Name of the template, stored as config/profiles/<NAME>.json--description <TEXT>: Human readable description of the workflow--force: Overwrite an existing template with the same name
Examples:
workflow-manager create my-workflow
workflow-manager create backup-workflow --description 'Daily backup routine'
workflow-manager create diagnostics && workflow-manager add diagnostics './health-control net-check'
list
List all workflow templates
Usage:
workflow-manager list
Options:
--json: Emit the template list as a JSON envelope (global flag)
Examples:
workflow-manager list
workflow-manager list --json
show
Show details of a workflow template
Usage:
workflow-manager show <TEMPLATE>
Options:
<TEMPLATE>: Template to display--json: Print the raw profile JSON, which is exactly what the runner deserializes (global flag)
Examples:
workflow-manager show my-workflow
workflow-manager show my-workflow --json
delete
Delete an entire workflow template
Usage:
workflow-manager delete <TEMPLATE>
Options:
<TEMPLATE>: Template to delete. This removes the profile JSON from disk and cannot be undone
Examples:
workflow-manager delete my-workflow
workflow-manager list && workflow-manager delete obsolete-workflow
Operational Scenarios
Scenario-oriented workflows generated from the binary's built-in -e --json examples.
Scenario 1: Quick Start
Create a template, add a step, preview it, then run it. Templates are stored as JSON profiles under the hooks config directory (config/profiles/<NAME>.json).
Step 1: Create an empty workflow template
workflow-manager create my-workflow
Step 2: Append a command step to the template
workflow-manager add my-workflow 'echo Hello World'
Note
`add` requires the template to exist already, so run `create` first.
Step 3: Inspect the steps, their IDs and their conditions
workflow-manager show my-workflow
Step 4: Preview execution without running any command
workflow-manager run my-workflow --dry-run
Note
Always dry-run first: steps run real shell commands.
Step 5: Execute every step in order
workflow-manager run my-workflow
Note
workflow-manager itself does not need root. Individual steps may, if the command inside the step does.
Scenario 2: Template Management
Create, list, view, and delete workflow templates.
Step 1: Create a template with a human readable label
workflow-manager create backup-workflow --description 'Daily backup routine'
Step 2: Show every stored workflow template
workflow-manager list
Step 3: Print the raw profile JSON, which is what the runner deserializes
workflow-manager show backup-workflow --json
Note
Use this to see the exact schema before hand editing config/profiles/backup-workflow.json.
Step 4: Remove an entire workflow template
workflow-manager delete backup-workflow
Note
Destructive and irreversible: the profile JSON is deleted from disk. Use `delete-step` if you only want to remove one step.
Scenario 3: Adding Steps
Add command steps to a template. A comma separated command list creates one step per command.
Step 1: Add a step with a 10 minute timeout and a description
workflow-manager add my-workflow 'tar czf backup.tar.gz /data' --timeout 600 --description 'Archive data'
Note
--timeout (-t) is the STEP timeout. It shadows the cli-core global --timeout inside `add`.
Step 2: Create a template and add three steps in one call using comma separation
workflow-manager create w1 && workflow-manager add w1 "ip-fetch","online-auth check-login","ip addr show"
Note
All steps created in one call share the same timeout and condition settings.
Step 3: Run this step only if the previous step exited 0
workflow-manager add my-workflow 'cleanup.sh' -c if_success
Step 4: Mark a step as requiring an interactive confirmation before it runs
workflow-manager add my-workflow './health-control panic hard' --confirm
Note
confirm=true prompts [y/N] before the step runs, in TEXT mode only. A --json run (what the dashboard uses) proceeds past it without prompting, so confirm is a human speed bump, not a safety gate.
Step 5: Run a background friendly step from a specific working directory
workflow-manager add my-workflow './long-scan.sh' --nice-level 10 -w /opt/kodachi/dashboard/hooks
Note
nice-level range is -20 (highest priority) to 19 (lowest). Negative values need root.
Step 6: Allow only the listed environment variables through to the step
workflow-manager add my-workflow './report.sh' --env 'HOME,PATH,LANG'
Note
Comma separated. Anything not listed is stripped from the step environment.
Scenario 4: Conditional Logic (CLI flags)
Every condition the runner understands, expressed as an `add` flag. One condition per step.
Step 1: Always execute (this is the default)
workflow-manager add my-workflow './check-status.sh' -c always
Step 2: Execute only if the previous step exited 0
workflow-manager add my-workflow './deploy.sh' -c if_success
Note
The most common condition for sequential workflows.
Step 3: Execute only if the previous step exited non-zero
workflow-manager add my-workflow './rollback.sh' -c if_fail
Note
Useful for error recovery and rollback.
Step 4: Execute if the previous step's output CONTAINS the text
workflow-manager add my-workflow './alert-success.sh' --if-contains 'success'
Note
Plain substring match, case sensitive. No wildcards: use --if-regex if you need a pattern.
Step 5: Execute if the previous output does NOT contain the text
workflow-manager add my-workflow './continue.sh' --if-not-contains 'error'
Note
Substring match, case sensitive.
Step 6: Execute if the previous output is exactly this value
workflow-manager add my-workflow './handle-done.sh' --if-equals 'ready'
Note
Exact match, case sensitive. Output is trimmed before comparison.
Step 7: Execute if the previous output matches a regex
workflow-manager add my-workflow './process-result.sh' --if-regex '^status: (ok|success)$'
Step 8: Execute if the previous output does NOT match a regex (here: fewer than 5 active services)
workflow-manager add my-workflow './alert-few-services.sh' --if-not-regex '(service.*active.*){5,}'
Note
Quantifiers such as {5,} let you use a regex as a crude counter.
Step 9: Execute if a field in the previous step's JSON output equals a value
workflow-manager add my-workflow './handle-connected.sh' --if-json-path '$.status="connected"'
Note
The previous output must be valid JSON. The CLI flag is --if-json-path; the serde tag written into the profile is if_json_path_equals.
Step 10: Execute if a nested JSON field, reached through an array index, matches
workflow-manager add my-workflow './finland-detected.sh' --if-json-path '$.data.records[0].country_name="Finland"'
Note
Supported path syntax: $ root, .field, [index]. Recursive descent (..) and wildcards (*) are NOT supported.
Step 11: Execute if a JSON boolean is true
workflow-manager add my-workflow './ip-online.sh' --if-json-path '$.ip_connectivity=true'
Note
Booleans and numbers are written unquoted: =true, =2. Strings need quotes: ="ok".
Step 12: Execute only when a live system state matches (independent of the previous step)
workflow-manager add my-workflow './tor-ready.sh' --if-state tor_running --if-state-expect true
Note
--if-state-expect takes JSON (true, false, 60, "wireguard"). Run `workflow-manager state` to see the state names.
Step 13: Execute based on a probe function defined in the profile
workflow-manager add my-workflow './skip-if-hardened.sh' --if-probe is_hardened --if-probe-expect false
Note
The probe name must exist in the profile's `probes` block, see the Probe Functions category. --if-probe-expect takes JSON.
Step 14: Execute if a boolean expression over states and probes evaluates true
workflow-manager add my-workflow './low-score-fix.sh' --if-expression "state.authenticated == true && state.security_score < 60"
Note
Grammar: atoms are probe('NAME') or state.NAME, operators == != < > <= >=, combined with && and || and negated with !. There is no contains() function and no step_id or workflow_status variable.
Scenario 5: Workflow Execution
Run workflows and control what happens when a step fails.
Step 1: List the steps that would run, without executing anything
workflow-manager run my-workflow --dry-run
Note
Conditions that depend on previous output cannot be fully resolved in a dry run.
Step 2: Execute every step in order, evaluating each condition first
workflow-manager run my-workflow
Note
Steps run real shell commands. Read the template with `show` before running one you did not write.
Step 3: Keep going after a failed step instead of stopping
workflow-manager run my-workflow --kill-policy continue
Note
Values: stop (default and safest), continue, skip_remaining. This overrides global_settings.kill_policy for this run.
Step 4: Raise the per-run log cap for a very chatty workflow
workflow-manager run my-workflow --max-log-size 20971520
Note
Bytes, not megabytes. Default is 10485760 (10 MB). Overrides global_settings.max_log_size.
Step 5: Run unattended in text mode, skipping the [y/N] prompt on confirm:true steps
workflow-manager run my-workflow --yes
Note
--yes (-y) approves EVERY confirm:true step, including destructive ones, with no prompt. It only affects text mode: the [y/N] prompt is text mode only.
Step 6: Run non-interactively and get a machine readable result (this is how the dashboard runs workflows)
workflow-manager run my-workflow --json
Note
--json is non-interactive: confirm:true steps run WITHOUT any prompt and without --yes. Do not rely on confirm as a safety gate for automated runs.
Scenario 6: Managing Individual Steps
Update or delete a single step. Step IDs come from `show`.
Step 1: Find the step IDs before editing
workflow-manager show my-workflow
Step 2: Replace step 1's command and timeout
workflow-manager update my-workflow 1 'echo Updated Command' -t 300
Note
The command positional is optional: pass only the flags you want to change.
Step 3: Change a step's condition and its description in place
workflow-manager update my-workflow 2 --if-contains 'ERROR' --description 'Alert on error'
Note
update accepts the same condition flags as add: -c, --if-contains, --if-not-contains, --if-equals, --if-regex, --if-not-regex, --if-json-path, --if-probe(-expect), --if-state(-expect), --if-expression.
Step 4: Drop a step's condition payload and reset it to a plain condition type
workflow-manager update my-workflow 2 --clear-condition -c always
Note
--clear-condition removes the stored pattern/path/probe value. Without it, switching from if_contains back to always can leave a stale payload.
Step 5: Update a pause step's message and require confirmation
workflow-manager update my-workflow 3 -m 'Verify the archive, then press Enter' --confirm true
Note
-m/--message applies to pause steps, --profile applies to include steps, the command positional applies to command steps.
Step 6: Remove step 2 from the workflow
workflow-manager delete-step my-workflow 2
Note
Steps are renumbered after a delete, so re-run `show` before deleting another one.
Scenario 7: Pause and Include Steps
Two non-command step types: a pause that waits for the user, and an include that expands another profile inline.
Step 1: Add an interactive pause point
workflow-manager pause my-workflow -m 'Review results before continuing'
Note
The run blocks until the user presses Enter, so a paused workflow is not suitable for unattended or --json runs.
Step 2: Pause only when the previous step succeeded
workflow-manager pause backup -m 'Verify backup integrity' -c if_success
Step 3: Compose another profile into this template
workflow-manager include my-workflow shared-prereqs --description 'Reusable setup steps'
Note
The named profile must exist. Its steps are expanded in place when the workflow runs.
Step 4: Pull in a recovery profile only when the previous step failed
workflow-manager include my-workflow tor-recovery -c if_fail
Note
include accepts -c/--condition plus --if-probe(-expect), --if-state(-expect) and --if-expression.
Scenario 8: Efficient Batch Building
Build a complete workflow in one shell line by chaining create and add with &&.
Step 1: Create a template and add three conditional steps in one chain
workflow-manager create tor-recovery && workflow-manager add tor-recovery './routing-switch recover internet' -t 60 && workflow-manager add tor-recovery './health-control net-check' -c if_success && workflow-manager add tor-recovery './tor-switch start' -c if_success -t 120
Note
`create` must come first: `add` refuses to run against a template that does not exist.
Step 2: Build a 4 step diagnostics workflow
workflow-manager create diagnostics && workflow-manager add diagnostics './health-control net-check' -t 30 && workflow-manager add diagnostics './tor-switch tor-status' -c if_success && workflow-manager add diagnostics './dns-leak test' -c if_success && workflow-manager add diagnostics './integrity-check check-all' -c if_success
Step 3: Mix command steps and a pause to build an interactive backup workflow
workflow-manager create backup && workflow-manager add backup 'tar czf backup.tar.gz /data' && workflow-manager pause backup -m 'Check backup size' -c if_success && workflow-manager add backup 'rsync backup.tar.gz remote:/backups' -c if_success && workflow-manager add backup 'rm backup.tar.gz' -c if_success
Scenario 9: Real-World Kodachi Workflows
End to end workflows built from real Kodachi hook commands.
Step 1: Fetch the public IP and branch on the geolocated country
workflow-manager create ip-verify && workflow-manager add ip-verify 'ip-fetch --json' -t 60 && workflow-manager add ip-verify 'echo Finland detected' --if-json-path '$.data.records[0].country_name="Finland"' && workflow-manager run ip-verify
Note
Needs network access. ip-fetch does not need root.
Step 2: Confirm there is a valid authenticated session
workflow-manager create auth-check && workflow-manager add auth-check 'online-auth check-login --json' -t 30 && workflow-manager add auth-check 'echo Session valid' --if-contains 'valid' && workflow-manager run auth-check
Note
Many hook commands refuse to run without an authenticated session, so this is a useful first step in a longer workflow.
Step 3: Chain a network check into a routing status check
workflow-manager create health-audit && workflow-manager add health-audit 'sudo health-control net-check --json' -t 60 && workflow-manager add health-audit 'echo Network online' --if-json-path '$.ip_connectivity=true' && workflow-manager add health-audit 'sudo routing-switch status --json' -c if_success -t 30 && workflow-manager run health-audit
Note
The steps themselves need root here (health-control and routing-switch do), workflow-manager does not.
Step 4: Verify the Tor daemon is up and answering
workflow-manager create tor-verify && workflow-manager add tor-verify 'sudo tor-switch get-tor-status --json' -t 30 && workflow-manager add tor-verify 'echo Tor responding' --if-json-path '$.data.is_responding=true' && workflow-manager run tor-verify
Note
Requires Tor to be installed and its control port reachable.
Scenario 10: Prerequisites
A profile can declare system state that must hold before any step runs. The block is `prerequisites` and it has exactly three fields: `required` (array), `optional` (array, warnings only) and `on_failure`. There is no flat form: keys such as "authenticated": true at the top of the block do not deserialize.
Step 1: Validate a profile's prerequisites without running the workflow
workflow-manager prereq check initial_terminal_setup_wireguard_torrify
Note
`prereq validate <TEMPLATE>` is accepted as an alias for `prereq check`.
Step 2: Read the exact prerequisites shape the runner expects
workflow-manager show initial_terminal_setup_wireguard_torrify --json
Note
The shape is: "prerequisites": {"required": [{"check": "state.online", "expect": true, "error": "Internet connection required"}, {"check": "state.torrify", "expect": false, "error": "System must not be torrified"}], "on_failure": "abort"}. Each entry needs `check` and `error`; `expect` is optional and defaults to a truthy check.
Step 3: List the state names usable as a prerequisite `check` value
workflow-manager state
Note
A check is written as "state.<NAME>" (the bare "<NAME>" form is also accepted). Optional checks go in the `optional` array: they warn but never block.
Step 4: See how on_failure behaves before committing to a real run
workflow-manager run initial_terminal_setup_wireguard_torrify --dry-run
Note
on_failure accepts "abort" (default) and "warn". Only "abort" stops the run: any other value, including a typo, lets the workflow continue. If the profile has no prerequisites block, no checks are performed.
Scenario 11: System State Checking
Query the live system state that conditions, probes and prerequisites read from.
Step 1: Show every system state as JSON
workflow-manager state
Step 2: Query a single state field (cheaper: only that field is probed)
workflow-manager state online
Note
20 states are available: online, routing_mode, vpn_connected, dnscrypt, ipv6_disabled, dns_kodachi_managed, firewall_active, kill_switch_armed, network_hardened, disk_encrypted, security_score, torrify, tor_running, tor_dns_active, tor_verified, mac_spoofing, bluetooth_enabled, wifi_enabled, authenticated, tor_instances_count.
Step 3: Read a numeric state, for use with --if-expression comparisons
workflow-manager state security_score --json
Note
Numeric states support < > <= >= inside --if-expression, for example "state.security_score < 60".
Scenario 12: Probe Functions (profile JSON)
A probe is a named, reusable check declared in the profile's `probes` block and referenced by --if-probe. A ProbeDefinition has exactly three fields: `probe_type` ("builtin", "expression" or "count"), `expression` (required for all three types) and an optional `description`. There is no `check` field.
Step 1: Reference a probe from a step condition
workflow-manager add my-workflow 'echo Already hardened, skipping' --if-probe is_hardened --if-probe-expect true
Note
Add the probes block to config/profiles/my-workflow.json first: "probes": {"harden_count": {"probe_type": "count", "expression": "count('harden', previous_output)", "description": "Count 'harden' occurrences"}, "is_hardened": {"probe_type": "expression", "expression": "probe('harden_count') >= 4"}}
Step 2: Use the one builtin probe: a live Tor connection check
workflow-manager add my-workflow './use-tor-path.sh' --if-probe tor_up --if-probe-expect true
Note
Declare it as "tor_up": {"probe_type": "builtin", "expression": "tor_connection_check"}. tor_connection_check is the ONLY builtin: any other expression under probe_type "builtin" fails at run time with 'Unknown builtin probe'. It shells out to ip-fetch check-tor, so it needs network access, and its result is cached for the run.
Step 3: Confirm the probes block deserializes the way the runner expects
workflow-manager show my-workflow --json
Note
probe_type "count" evaluates count('<TEXT>', previous_output) and returns a number. probe_type "expression" evaluates the same grammar as --if-expression, so it can reference other probes with probe('NAME') and states with state.NAME.
Scenario 13: Global Settings (profile JSON)
The `global_settings` block sets workflow wide defaults: kill_policy ("stop" by default), continue_policy (false by default), max_log_size (10485760 bytes), default_timeout (seconds) and working_dir. Step level values override them.
Step 1: Read the global_settings block of an existing profile
workflow-manager show policy-demo --json
Note
continue_policy is the master override: when true the workflow always continues and kill_policy is ignored. When false, kill_policy decides: "stop" ends the run, "continue" carries on, "skip_remaining" skips the rest without failing.
Step 2: Force the safest failure policy for one run, whatever the profile says
workflow-manager run policy-demo --kill-policy stop
Note
For security critical workflows use kill_policy "stop" with continue_policy false. For recovery workflows, "continue" is usually what you want.
Step 3: Give one step its own timeout, overriding default_timeout
workflow-manager add slow-scan './deep-scan.sh' -t 60
Note
A step with no timeout inherits global_settings.default_timeout. A timed out command is sent SIGTERM, then SIGKILL if it does not exit.
Scenario 14: Condition Reference (profile JSON)
The 12 condition tags the runner accepts, exactly as they are written in the profile's `condition` object. Anything else fails to deserialize: always, if_success, if_fail, if_contains, if_not_contains, if_equals, if_regex, if_not_regex, if_json_path_equals, if_probe, if_state, if_expression.
Step 1: See the condition object the CLI flags actually write
workflow-manager show my-workflow --json
Note
Field per tag: always / if_success / if_fail take none. if_contains, if_not_contains, if_regex, if_not_regex take `pattern`. if_equals takes `value`. if_json_path_equals takes `path` and `value`. if_probe takes `probe` and `expect`. if_state takes `state` and `expect`. if_expression takes `expression`.
Step 2: Substring matching, written as if_contains / if_not_contains
workflow-manager add my-workflow './alert.sh' --if-contains 'SUCCESS'
Note
This is a plain substring test, case sensitive. It is NOT glob: * and ? are literal characters here. For wildcards use if_regex.
Step 3: JSON path equality, written as if_json_path_equals
workflow-manager add my-workflow './connected.sh' --if-json-path '$.status.connected=true'
Note
The stored field is `value`, not `expect`. Path syntax is a strict subset: $ root, .field, [index]. Recursive descent (..) and wildcards are not supported.
Step 4: Boolean expression, written as if_expression
workflow-manager add my-workflow './score-fix.sh' --if-expression "probe('harden_count') >= 4 || state.security_score < 60"
Note
Atoms: probe('NAME') and state.NAME. Operators: == != < > <= >=, joined with && and ||, negated with a leading !. Comparisons on booleans and strings support only == and !=.
Scenario 15: Step Reference (profile JSON)
A step object has two required fields, `id` and `type` ("command", "pause" or "include"), plus `condition` (defaults to always if absent). Everything else is optional: cmd, description, timeout, confirm, env_allowlist, working_dir, nice_level, message, profile, parameters, and the ColonyOps hints cell_store, score_impact and colonyops_safety.
Step 1: Read a complete step object as the runner stores it
workflow-manager show my-workflow --json
Note
`description` is optional, not required. A command step needs `cmd`, a pause step needs `message`, an include step needs `profile` (and may carry `parameters`).
Step 2: Write the confirm and nice_level step fields from the CLI
workflow-manager add my-workflow './panic.sh' --confirm --nice-level -10
Note
confirm:true prompts [y/N] in text mode only, and `run --yes` skips that prompt. A --json run never prompts. nice_level goes from -20 to 19; negative values need root.
Step 3: Write the working_dir and env_allowlist step fields
workflow-manager add my-workflow './report.sh' -w /opt/kodachi/dashboard/hooks --env 'HOME,PATH'
Note
A step without working_dir inherits global_settings.working_dir. env_allowlist is a whitelist: variables not listed are not passed to the step.
Step 4: Write an include step, which expands another profile at run time
workflow-manager include my-workflow base-recovery-sequence
Note
Include lets you keep a library of small reusable profiles and compose them. The included profile must already exist.
Environment Variables
| Variable | Description | Default | Values |
|---|---|---|---|
NO_COLOR |
Disable all colored output when set | unset | 1|true|yes (any value disables color) |
Exit Codes
| Code | Description |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Invalid arguments |
| 3 | Permission denied |
| 4 | Network error |
| 5 | File not found |