LocalBash plugin
Use LocalBash for an application command, worker or test script that runs on the same machine as your Reflow CLI. Each invocation keeps its output and exit status as evidence. Use DockerUbuntu for commands inside an existing Ubuntu container.
Connect
Section titled “Connect”Select your application collection during onboarding. Use its ID in the target command below.
Install the bundled plugin with reflow init --collection <collection-id>. The plugin
bundles GNU Bash 5.3; your command’s own dependencies must be available on the machine.
Save this private connection as bindings.json, replacing the directory with your
application’s absolute path:
{ "worker": { "provider": "LocalBash", "configuration": {"cwd": "/absolute/path/to/your/app"} }}cwd is required and must exist; it is the only configuration key. Commands run
on the bundled Bash without interactive profile or rc files. Use explicit commands; aliases from your interactive shell are not loaded.
Keep the bindings file out of Git.
chmod 600 /absolute/path/to/bindings.jsonreflow target --group worker-tests --collection <collection-id> --bindings /absolute/path/to/bindings.jsonFor manage_device_jobs runs, select this same application and private bindings
before starting the saved flow. The job checks the application’s plugin lock and
each declared binding, then copies the selected configuration into its private
worker. The binding values stay on the device; shared shell evidence redacts known
private values. reflow init installs plugins; reflow target --bindings selects
their private configuration.
This also applies to explicit Browser aliases such as providers: {site: Browser}:
select a site entry with provider: "Browser" and configuration: {} to use
defaults. Implicit Browser statements without a provider declaration need no
private binding. Device jobs select bindings by application and authenticated
connection.
The owner-only configuration copy stays in the local evidence slot until that slot
is discarded; evidence reads and review exports do not include that file.
Write a flow
Section titled “Write a flow”Copy this into /tmp/worker-output.md, outside your checkout.
This example needs only Bash:
---name: Capture command outputproviders: worker: LocalBash---
### Capture command output
```rflworker.bash command="printf 'worker ready\n'" checkpoint="worker-output"```Create the test in the team’s chosen location, then run it:
reflow flows create --name worker-output --file /tmp/worker-output.mdreflow plan worker-outputreflow apply worker-outputreflow dashboardReplace the printf command with your application’s worker or test command.
The alias worker selects the private connection with the same name. See
plugin setup for aliases and version pins.
Commands
Section titled “Commands”worker.bash accepts:
| Argument | Type | Meaning |
|---|---|---|
command | string, required | Bash source to run in the configured directory. |
files | string, optional | A JSON array of relative file paths to retain after the command. |
checkpoint is a host RFL modifier for the invocation’s retained evidence, not a
LocalBash command argument. RFL removes it before provider argument validation and
dispatch, so it is absent from the bash descriptor returned by list_plugins.
Use a literal label of 1-128 letters, digits, underscores or hyphens. Other unknown
arguments are still rejected. It is not a separate shell command or a screenshot
of a terminal.
For a command that writes a report:
worker.bash command="./bin/check-orders > report.txt" files="[\"report.txt\"]" checkpoint="order-report"That example assumes your application supplies ./bin/check-orders. Selected files
must exist inside cwd; absolute paths and paths that escape it are rejected.
Each captured file is limited to 4 MiB. Stdout and stderr are each limited to 1 MiB and indicate truncation when it
occurs. A truncated result cannot establish full equality during comparison.
Escape shell parameter expansion
Section titled “Escape shell parameter expansion”In a quoted plugin argument, write $${ for a literal ${. RFL consumes the
extra dollar once, then Bash receives the original shell parameter expansion.
This applies to both LocalBash and DockerUbuntu, including ${PIPESTATUS[0]},
${VAR:-default} and ${#arr[@]}. Shell quotes alone do not stop RFL interpolation.
worker.bash command="unset VAR; printf '%s\\n' \"$${VAR:-default}\""worker.bash command="arr=(one two); printf '%s\\n' \"$${#arr[@]}\""worker.bash command="false | true; code=$${PIPESTATUS[0]}; printf '%s\\n' \"$code\"; exit \"$code\""The first two commands print default and 2. The pipeline example prints 1
and deliberately fails with exit status 1, retaining the first command’s failure.
For nested shell expansions, escape each opening: $${VAR:-$${OTHER:-default}}.
An ordinary ${inputs.name} still resolves a Reflow input in the same command.
Use double-quoted RFL strings and JSON escapes for quotes/backslashes. \${ is
not a supported RFL escape; $${ is the literal-opening syntax. This is separate
from shell quoting: to prevent Bash from expanding the resulting ${...}, quote
it appropriately in the shell command too. See the
language reference.
Keep generated reports outside the checkout
Section titled “Keep generated reports outside the checkout”cwd does not have to be your application checkout. For a knowledge-base PoC,
create a private work directory outside the repository and use its absolute path
as the LocalBash cwd. Stdout and stderr are retained automatically without
creating report files in the checkout. If you need a captured report file, run
the application command in a subshell and redirect its output from the private
working directory:
worker.bash command="(cd '/absolute/path/to/your/app' && ./bin/check-orders) > report.txt" files="[\"report.txt\"]" checkpoint="order-report"Replace the path and command with your application’s actual command. The subshell
changes only the command’s working directory; report.txt is written under the
configured private cwd. The command itself can still create application files,
so use its own output-directory option when appropriate. Capture does not follow
symlinks that escape cwd; an external symlink is not a supported workaround.
There is currently no separate evidenceDir configuration.
Evidence and failures
Section titled “Evidence and failures”The snapshot retains stdout, stderr and exit code, plus requested files. A nonzero
exit is a failed result whose output remains available for diagnosis. No additional
snapshot command is needed. Comparing two results uses the retained outputs and
file hashes; a successful exit does not mean their contents are unchanged.
Shared shell evidence redacts known private values from text and withholds affected binary files. Local files remain unchanged.
Use snapshots and review to inspect changes, and repair and rerun when a command or its expected result changes.
Flows using this plugin can be saved in Reflow or in your repository. Read test storage for the team preference, private bindings and the shared plan/apply workflow.