/SKILL.md
Use when writing or reviewing Shellflow playbooks, especially when mixing
npx skillsauth add longcipher/shellflow shellflowInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Shellflow playbooks are normal shell scripts with comment markers. The script remains valid shell for humans, while Shellflow uses markers to split execution into isolated local and remote blocks, pass explicit context between blocks, and emit structured results for agents.
Generate ordinary shell first. Then apply Shellflow rules for block boundaries, prelude freezing, remote host resolution, dynamic options, task selection, lifecycle hooks, and agent-safe output.
Use this skill when:
# @LOCAL and # @REMOTE blocks.shellflow run --json, --jsonl, or agent-run.Do not use this skill for:
# @REMOTE marker..sh file.#!/bin/bash.set -euo pipefail in the prelude only if every block should inherit them.Top-level markers:
# @LOCAL# @REMOTE <ssh-host># @SERVER <name># @option <name>[=<default>]# @TASK <name># @MACRO <name> ... / # @ENDMACRO# @HELPER <name> / # @ENDHELPER# @HOOK <type> / # @ENDHOOKBlock directives must appear immediately after # @LOCAL or # @REMOTE <host>, before command lines:
# @TIMEOUT <seconds># @RETRY <count># @EXPORT NAME=stdout|stderr|output|exit_code# @SHELL bash|zsh|sh# @PARALLEL [group]Write marker names uppercase even though the parser accepts them case-insensitively.
Good:
# @LOCAL
echo "build locally"
# @REMOTE staging
uname -a
Bad:
echo "# @LOCAL"
# marker text inside an echo is just shell output, not a block marker
# @REMOTE <ssh-host> takes one host alias. Do not write # @REMOTE web-1,web-2; create separate remote blocks and mark them # @PARALLEL if they should run together.
Each block is isolated. Do not rely on these persisting across blocks:
cdexport valuesUse SHELLFLOW_LAST_OUTPUT or # @EXPORT for explicit handoff.
Good:
# @LOCAL
# @EXPORT ARTIFACT=stdout
mktemp
# @LOCAL
test -n "$ARTIFACT"
printf 'ready\n' > "$ARTIFACT"
Bad:
# @LOCAL
artifact=$(mktemp)
# @LOCAL
printf 'ready\n' > "$artifact"
Lines before the first block marker are the shared prelude. Shellflow prepends non-assignment prelude lines to every executable block.
Uppercase assignments in the prelude are special: Shellflow evaluates them once locally and exports the frozen values into every block.
Good:
#!/bin/bash
set -euo pipefail
BUILD_ID=$(date +%s)
log() {
printf '[deploy] %s\n' "$*"
}
# @LOCAL
echo "$BUILD_ID"
# @REMOTE staging
echo "$BUILD_ID"
Both blocks receive the same BUILD_ID.
Avoid one-time side effects in the prelude, especially if uppercase assignments are present and prelude evaluation will run locally:
cd /srv/app # bad in prelude
rm -rf tmp/cache # bad in prelude
Put one-time operations in explicit blocks instead.
Use # @option to declare parameters a human or agent must fill.
# @option staging
# @option branch=main
# @option release-name=
Semantics:
# @option staging is boolean. --staging sets STAGING=1; absent means the variable is unset.# @option branch=main has a default. --branch develop sets BRANCH=develop.# @option release-name= is required. Provide --release-name v1 or environment variable RELEASE_NAME.CLI:
shellflow run deploy.sh --branch develop --release-name v2026.05.01 --staging
Agent input:
{
"script": "# @option release-name=\n# @LOCAL\necho \"$RELEASE_NAME\"\n",
"options": {"release-name": "v2026.05.01"},
"dry_run": false
}
Use # @TASK <name> to label the following block.
# @TASK build
# @LOCAL
echo "build"
# @TASK deploy
# @REMOTE staging
echo "deploy"
Run one task:
shellflow run deploy.sh --task build
Use a single-line macro to define a task flow:
# @MACRO release build deploy smoke-test
Then run:
shellflow run deploy.sh --task release
Rules:
--task target can be either a task name or a macro name.Macros can also expand command snippets inside blocks:
# @MACRO print_env
# env | sort
# @ENDMACRO
# @LOCAL
print_env
Helpers are reusable command snippets. They expand when a block line is exactly the helper name.
# @HELPER backup_db
# pg_dump "$DATABASE_URL" > backup.sql
# @ENDHELPER
# @LOCAL
backup_db
Use helpers for local command reuse. Keep them simple and predictable.
Hooks run locally and share Shellflow context:
PRE runs once before main blocks.BEFORE runs before each main block.AFTER runs after each main block.SUCCESS runs after all main blocks succeed.ERROR runs after a hook or main block fails.FINISHED runs at the end for success or failure.Aliases:
POST means AFTER.FINALLY means FINISHED.Example:
# @HOOK PRE
# echo "prepare"
# @ENDHOOK
# @HOOK ERROR
# echo "collect diagnostics"
# @ENDHOOK
# @HOOK FINISHED
# echo "cleanup"
# @ENDHOOK
Use hooks for setup, cleanup, and diagnostics. Do not hide primary deployment logic in hooks.
# @PARALLEL applies only to the next block, or to the current block when used as a block directive.
Mark every block that should be in the parallel group:
# @PARALLEL web
# @REMOTE web-1
systemctl restart nginx
# @PARALLEL web
# @REMOTE web-2
systemctl restart nginx
# @LOCAL
echo "after the parallel group"
Run with:
shellflow run restart.sh --mode parallel
Without --mode parallel, annotated blocks still run sequentially. Consecutive parallel blocks form one group. A non-parallel block ends the group.
Parallel blocks receive a copied context. Do not rely on exports produced by one parallel block being available to another parallel block in the same group.
Remote hosts can come from inline # @SERVER definitions:
# @SERVER staging
# host: 192.168.1.100
# user: deploy
# port: 22
# key: ~/.ssh/id_ed25519
# @REMOTE staging
hostname
Or from SSH config:
Host staging
HostName 192.168.1.100
User deploy
Port 22
IdentityFile ~/.ssh/id_ed25519
Rules:
@SERVER requires a host field.key maps to SSH identity file.# @REMOTE <host> must resolve before execution.--ssh-config <path> to override ~/.ssh/config.Use # @SHELL zsh or # @SHELL bash immediately after a remote block marker when the target needs a specific shell.
# @REMOTE zsh-server
# @SHELL zsh
reload
compdef
Shellflow starts remote shells in login mode and quietly bootstraps ~/.zshrc or ~/.bashrc for zsh/bash blocks.
Remote command tracing uses a shell DEBUG trap and executes the whole block as one native script. This preserves multi-line shell structures:
# @REMOTE staging
if test -f /srv/app/current; then
echo "exists"
else
echo "missing"
fi
Do not split multi-line shell syntax into separate blocks.
Useful commands:
shellflow run script.sh
shellflow run script.sh --json
shellflow run script.sh --jsonl
shellflow run script.sh --no-input
shellflow run script.sh --dry-run
shellflow run script.sh --mode parallel
shellflow run script.sh --task release
shellflow run script.sh --audit-log audit.jsonl --jsonl
shellflow agent-run --json-input '{"script":"# @LOCAL\necho hi\n"}'
shellflow doctor script.sh
Use:
--json for one final report.--jsonl for ordered run/block events.--no-input for CI and agent runs.--dry-run to inspect the execution plan.--audit-log to write redacted JSONL events.doctor [script] to check install/config status and parse an optional script.Exit codes:
0: success1: execution failure2: parse failure3: SSH config failure4: timeout failureBefore returning a Shellflow playbook, verify:
# @option name= values are provided by CLI, env, or agent input.SHELLFLOW_LAST_OUTPUT or # @EXPORT.# @SERVER or SSH config.--mode parallel.--json, --jsonl, or agent-run instead of scraping human output.#!/bin/bash
set -euo pipefail
# @option release-name=
# @option branch=main
BUILD_ID=$(date +%Y%m%d%H%M%S)
log() {
printf '[deploy] %s\n' "$*"
}
# @SERVER staging
# host: staging.example.com
# user: deploy
# @HOOK ERROR
# log "deployment failed for $RELEASE_NAME"
# @ENDHOOK
# @HOOK FINISHED
# log "finished $RELEASE_NAME"
# @ENDHOOK
# @MACRO release build deploy smoke
# @TASK build
# @LOCAL
# @EXPORT ARTIFACT=stdout
log "building $RELEASE_NAME from $BRANCH"
printf '/tmp/%s-%s.tar.gz\n' "$RELEASE_NAME" "$BUILD_ID"
# @TASK deploy
# @REMOTE staging
# @TIMEOUT 120
log "deploying $ARTIFACT"
test -n "$ARTIFACT"
# @TASK smoke
# @LOCAL
log "smoke test complete for $RELEASE_NAME"
Run it:
shellflow run deploy.sh --task release --release-name v2026.05.01 --branch main --jsonl --no-input
cd, rm, or deployment commands in the prelude.# @PARALLEL once and expecting it to apply to every later block.--mode parallel.# @REMOTE web-1,web-2 instead of separate remote blocks.@TIMEOUT, @RETRY, @EXPORT, @SHELL, or @PARALLEL after commands."$SHELLFLOW_LAST_OUTPUT" and exported variables.testing
Create, edit, improve, or audit AgentSkills. Use when creating a new skill from scratch or when asked to improve, review, audit, tidy up, or clean up an existing skill or SKILL.md file. Also use when editing or restructuring a skill directory (moving files to references/ or scripts/, removing stale content, validating against the AgentSkills spec). Triggers on phrases like "create a skill", "author a skill", "tidy up a skill", "improve this skill", "review the skill", "clean up the skill", "audit the skill".
testing
Host security hardening and risk-tolerance configuration for OpenClaw deployments. Use when a user asks for security audits, firewall/SSH/update hardening, risk posture, exposure review, OpenClaw cron scheduling for periodic checks, or version status checks on a machine running OpenClaw (laptop, workstation, Pi, VPS).
testing
Create, edit, improve, or audit AgentSkills. Use when creating a new skill from scratch or when asked to improve, review, audit, tidy up, or clean up an existing skill or SKILL.md file. Also use when editing or restructuring a skill directory (moving files to references/ or scripts/, removing stale content, validating against the AgentSkills spec). Triggers on phrases like "create a skill", "author a skill", "tidy up a skill", "improve this skill", "review the skill", "clean up the skill", "audit the skill".
testing
Host security hardening and risk-tolerance configuration for OpenClaw deployments. Use when a user asks for security audits, firewall/SSH/update hardening, risk posture, exposure review, OpenClaw cron scheduling for periodic checks, or version status checks on a machine running OpenClaw (laptop, workstation, Pi, VPS).