shellflow 0.1.1__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. {shellflow-0.1.1 → shellflow-0.2.0}/.gitignore +2 -0
  2. shellflow-0.2.0/CHANGELOG.md +8 -0
  3. {shellflow-0.1.1 → shellflow-0.2.0}/PKG-INFO +61 -1
  4. {shellflow-0.1.1 → shellflow-0.2.0}/README.md +60 -0
  5. {shellflow-0.1.1 → shellflow-0.2.0}/SKILL.md +130 -16
  6. shellflow-0.2.0/features/execution_contract.feature +29 -0
  7. shellflow-0.2.0/features/resilience_and_context.feature +24 -0
  8. shellflow-0.2.0/features/safety_controls.feature +24 -0
  9. shellflow-0.2.0/features/steps/shellflow_steps.py +958 -0
  10. shellflow-0.2.0/playbooks/hello.sh +89 -0
  11. {shellflow-0.1.1 → shellflow-0.2.0}/pyproject.toml +1 -1
  12. shellflow-0.2.0/specs/2026-03-15-01-agent-native-runner/design.md +458 -0
  13. shellflow-0.2.0/specs/2026-03-15-01-agent-native-runner/features/execution_contract.feature +29 -0
  14. shellflow-0.2.0/specs/2026-03-15-01-agent-native-runner/features/resilience_and_context.feature +24 -0
  15. shellflow-0.2.0/specs/2026-03-15-01-agent-native-runner/features/safety_controls.feature +24 -0
  16. shellflow-0.2.0/specs/2026-03-15-01-agent-native-runner/tasks.md +208 -0
  17. shellflow-0.2.0/src/shellflow.py +1524 -0
  18. {shellflow-0.1.1 → shellflow-0.2.0}/tests/test_shellflow.py +592 -0
  19. {shellflow-0.1.1 → shellflow-0.2.0}/uv.lock +1 -1
  20. shellflow-0.1.1/CHANGELOG.md +0 -12
  21. shellflow-0.1.1/features/steps/shellflow_steps.py +0 -237
  22. shellflow-0.1.1/playbooks/hello.sh +0 -8
  23. shellflow-0.1.1/src/shellflow.py +0 -802
  24. {shellflow-0.1.1 → shellflow-0.2.0}/.github/workflows/ci.yml +0 -0
  25. {shellflow-0.1.1 → shellflow-0.2.0}/.github/workflows/release.yml +0 -0
  26. {shellflow-0.1.1 → shellflow-0.2.0}/.python-version +0 -0
  27. {shellflow-0.1.1 → shellflow-0.2.0}/.rumdl.toml +0 -0
  28. {shellflow-0.1.1 → shellflow-0.2.0}/AGENTS.md +0 -0
  29. {shellflow-0.1.1 → shellflow-0.2.0}/CLAUDE.md +0 -0
  30. {shellflow-0.1.1 → shellflow-0.2.0}/Justfile +0 -0
  31. {shellflow-0.1.1 → shellflow-0.2.0}/assets/shellflow-run.png +0 -0
  32. {shellflow-0.1.1 → shellflow-0.2.0}/behave_runner.py +0 -0
  33. {shellflow-0.1.1 → shellflow-0.2.0}/cliff.toml +0 -0
  34. {shellflow-0.1.1 → shellflow-0.2.0}/context7.json +0 -0
  35. {shellflow-0.1.1 → shellflow-0.2.0}/features/__init__.py +0 -0
  36. {shellflow-0.1.1 → shellflow-0.2.0}/features/environment.py +0 -0
  37. {shellflow-0.1.1 → shellflow-0.2.0}/features/parser.feature +0 -0
  38. {shellflow-0.1.1 → shellflow-0.2.0}/features/runner.feature +0 -0
  39. {shellflow-0.1.1 → shellflow-0.2.0}/features/steps/__init__.py +0 -0
  40. {shellflow-0.1.1 → shellflow-0.2.0}/ruff.toml +0 -0
  41. {shellflow-0.1.1 → shellflow-0.2.0}/specs/2026-03-13-01-shellflow-runner/REFINEMENT_SUMMARY.md +0 -0
  42. {shellflow-0.1.1 → shellflow-0.2.0}/specs/2026-03-13-01-shellflow-runner/design.md +0 -0
  43. {shellflow-0.1.1 → shellflow-0.2.0}/specs/2026-03-13-01-shellflow-runner/features/config.feature +0 -0
  44. {shellflow-0.1.1 → shellflow-0.2.0}/specs/2026-03-13-01-shellflow-runner/features/parser.feature +0 -0
  45. {shellflow-0.1.1 → shellflow-0.2.0}/specs/2026-03-13-01-shellflow-runner/features/runner.feature +0 -0
  46. {shellflow-0.1.1 → shellflow-0.2.0}/specs/2026-03-13-01-shellflow-runner/features/steps/shellflow_steps.py +0 -0
  47. {shellflow-0.1.1 → shellflow-0.2.0}/specs/2026-03-13-01-shellflow-runner/tasks.md +0 -0
  48. {shellflow-0.1.1 → shellflow-0.2.0}/tests/__init__.py +0 -0
  49. {shellflow-0.1.1 → shellflow-0.2.0}/tests/fixtures/local_only.sh +0 -0
@@ -41,3 +41,5 @@ Thumbs.db
41
41
  .env
42
42
  .env.local
43
43
  .rumdl_cache/
44
+ .benchmarks/
45
+ .hypothesis/
@@ -0,0 +1,8 @@
1
+ ## [0.2.0] - 2026-03-15
2
+
3
+ ### Features
4
+
5
+ - Introduce agent-native execution contract and resilience features
6
+ - Update SKILL.md with changes to block directives and execution behavior guidelines
7
+
8
+ <!-- generated by git-cliff -->
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shellflow
3
- Version: 0.1.1
3
+ Version: 0.2.0
4
4
  Summary: A minimal shell script orchestrator with SSH support
5
5
  Project-URL: Homepage, https://github.com/longcipher/shellflow
6
6
  Project-URL: Repository, https://github.com/longcipher/shellflow
@@ -22,6 +22,8 @@ Description-Content-Type: text/markdown
22
22
 
23
23
  # ShellFlow
24
24
 
25
+ > AI agent native DevOps bash script orchestrator.
26
+
25
27
  [![DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/longcipher/shellflow)
26
28
  [![Context7](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com/longcipher/shellflow)
27
29
  [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/downloads/)
@@ -40,6 +42,10 @@ ShellFlow is a minimal shell script orchestrator for mixed local and remote exec
40
42
  - Run each block fail-fast, in order.
41
43
  - Reuse the shared prelude before the first marker for every block.
42
44
  - Pass the previous block output forward as `SHELLFLOW_LAST_OUTPUT`.
45
+ - Export named scalar values from a block into later block environments.
46
+ - Emit either a final JSON report or streaming JSON Lines events for agents.
47
+ - Support bounded `@TIMEOUT` and `@RETRY` directives without embedding workflow logic.
48
+ - Provide non-interactive, dry-run, and audit-log modes for automated execution.
43
49
  - Resolve remote targets from `~/.ssh/config` or a custom SSH config path.
44
50
 
45
51
  ## Quick Start
@@ -102,6 +108,12 @@ Shellflow recognizes two markers:
102
108
  - `# @LOCAL`
103
109
  - `# @REMOTE <ssh-host>`
104
110
 
111
+ Shellflow also recognizes bounded block directives at the top of a block body:
112
+
113
+ - `# @TIMEOUT <seconds>`
114
+ - `# @RETRY <count>`
115
+ - `# @EXPORT NAME=stdout|stderr|output|exit_code`
116
+
105
117
  `<ssh-host>` must match a `Host` entry in your SSH config. Shellflow then connects using that SSH host definition, which means the actual machine can be resolved through the configured `HostName`, `User`, `Port`, and `IdentityFile` values.
106
118
 
107
119
  Example:
@@ -111,6 +123,7 @@ Example:
111
123
  set -euo pipefail
112
124
 
113
125
  # @LOCAL
126
+ # @EXPORT VERSION=stdout
114
127
  echo "runs locally"
115
128
 
116
129
  # @REMOTE sui
@@ -118,6 +131,7 @@ uname -a
118
131
 
119
132
  # @LOCAL
120
133
  echo "remote output: $SHELLFLOW_LAST_OUTPUT"
134
+ echo "version = $VERSION"
121
135
  ```
122
136
 
123
137
  ## SSH Configuration
@@ -163,6 +177,18 @@ echo "build-123"
163
177
  echo "last output = $SHELLFLOW_LAST_OUTPUT"
164
178
  ```
165
179
 
180
+ Named exports are additive to `SHELLFLOW_LAST_OUTPUT`:
181
+
182
+ ```bash
183
+ # @LOCAL
184
+ # @EXPORT VERSION=stdout
185
+ echo "2026.03.15"
186
+
187
+ # @REMOTE sui
188
+ echo "deploying $VERSION"
189
+ echo "last output = $SHELLFLOW_LAST_OUTPUT"
190
+ ```
191
+
166
192
  Lines before the first marker are treated as a shared prelude and prepended to every executable block:
167
193
 
168
194
  ```bash
@@ -176,11 +202,41 @@ echo "prelude is active"
176
202
  echo "prelude is also active here"
177
203
  ```
178
204
 
205
+ ## Agent-Native Usage
206
+
207
+ Shellflow is designed to be the execution substrate for an outer agent, not an embedded planner.
208
+
209
+ - Use `--json` when you want one final machine-readable run report.
210
+ - Use `--jsonl` when you want ordered event records while the script runs.
211
+ - Use `--no-input` for CI or agent runs where interactive prompts must fail deterministically.
212
+ - Use `--dry-run` to preview planned execution without running commands.
213
+ - Use `--audit-log <path>` to mirror the structured event stream into a redacted JSONL file.
214
+
215
+ Recommended agent flow:
216
+
217
+ 1. Generate or select a plain shell script with `@LOCAL` and `@REMOTE` markers.
218
+ 2. Add bounded directives only where needed: `@TIMEOUT`, `@RETRY`, and `@EXPORT`.
219
+ 3. Run with `--json` or `--jsonl`.
220
+ 4. Let the outer agent decide whether to retry, branch, or stop based on Shellflow's structured result.
221
+
222
+ Shellflow intentionally does not provide:
223
+
224
+ - Conditional directives such as `@IF stdout_contains=...`
225
+ - A workflow DSL or embedded ReAct loop
226
+ - Heuristic destructive-command detection
227
+
228
+ Those decisions belong in the outer agent or automation layer.
229
+
179
230
  ## CLI
180
231
 
181
232
  ```text
182
233
  shellflow run <script>
183
234
  shellflow run <script> --verbose
235
+ shellflow run <script> --json
236
+ shellflow run <script> --jsonl
237
+ shellflow run <script> --no-input
238
+ shellflow run <script> --dry-run
239
+ shellflow run <script> --audit-log ./audit.jsonl --jsonl
184
240
  shellflow run <script> --ssh-config ./ssh_config
185
241
  shellflow --version
186
242
  ```
@@ -190,6 +246,10 @@ Examples:
190
246
  ```bash
191
247
  shellflow run playbooks/hello.sh
192
248
  shellflow run playbooks/hello.sh -v
249
+ shellflow run playbooks/hello.sh --json
250
+ shellflow run playbooks/hello.sh --jsonl --no-input
251
+ shellflow run playbooks/hello.sh --dry-run --jsonl
252
+ shellflow run playbooks/hello.sh --audit-log ./audit.jsonl --jsonl
193
253
  shellflow run playbooks/hello.sh --ssh-config ~/.ssh/config.work
194
254
  ```
195
255
 
@@ -1,5 +1,7 @@
1
1
  # ShellFlow
2
2
 
3
+ > AI agent native DevOps bash script orchestrator.
4
+
3
5
  [![DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/longcipher/shellflow)
4
6
  [![Context7](https://img.shields.io/badge/Website-context7.com-blue)](https://context7.com/longcipher/shellflow)
5
7
  [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://www.python.org/downloads/)
@@ -18,6 +20,10 @@ ShellFlow is a minimal shell script orchestrator for mixed local and remote exec
18
20
  - Run each block fail-fast, in order.
19
21
  - Reuse the shared prelude before the first marker for every block.
20
22
  - Pass the previous block output forward as `SHELLFLOW_LAST_OUTPUT`.
23
+ - Export named scalar values from a block into later block environments.
24
+ - Emit either a final JSON report or streaming JSON Lines events for agents.
25
+ - Support bounded `@TIMEOUT` and `@RETRY` directives without embedding workflow logic.
26
+ - Provide non-interactive, dry-run, and audit-log modes for automated execution.
21
27
  - Resolve remote targets from `~/.ssh/config` or a custom SSH config path.
22
28
 
23
29
  ## Quick Start
@@ -80,6 +86,12 @@ Shellflow recognizes two markers:
80
86
  - `# @LOCAL`
81
87
  - `# @REMOTE <ssh-host>`
82
88
 
89
+ Shellflow also recognizes bounded block directives at the top of a block body:
90
+
91
+ - `# @TIMEOUT <seconds>`
92
+ - `# @RETRY <count>`
93
+ - `# @EXPORT NAME=stdout|stderr|output|exit_code`
94
+
83
95
  `<ssh-host>` must match a `Host` entry in your SSH config. Shellflow then connects using that SSH host definition, which means the actual machine can be resolved through the configured `HostName`, `User`, `Port`, and `IdentityFile` values.
84
96
 
85
97
  Example:
@@ -89,6 +101,7 @@ Example:
89
101
  set -euo pipefail
90
102
 
91
103
  # @LOCAL
104
+ # @EXPORT VERSION=stdout
92
105
  echo "runs locally"
93
106
 
94
107
  # @REMOTE sui
@@ -96,6 +109,7 @@ uname -a
96
109
 
97
110
  # @LOCAL
98
111
  echo "remote output: $SHELLFLOW_LAST_OUTPUT"
112
+ echo "version = $VERSION"
99
113
  ```
100
114
 
101
115
  ## SSH Configuration
@@ -141,6 +155,18 @@ echo "build-123"
141
155
  echo "last output = $SHELLFLOW_LAST_OUTPUT"
142
156
  ```
143
157
 
158
+ Named exports are additive to `SHELLFLOW_LAST_OUTPUT`:
159
+
160
+ ```bash
161
+ # @LOCAL
162
+ # @EXPORT VERSION=stdout
163
+ echo "2026.03.15"
164
+
165
+ # @REMOTE sui
166
+ echo "deploying $VERSION"
167
+ echo "last output = $SHELLFLOW_LAST_OUTPUT"
168
+ ```
169
+
144
170
  Lines before the first marker are treated as a shared prelude and prepended to every executable block:
145
171
 
146
172
  ```bash
@@ -154,11 +180,41 @@ echo "prelude is active"
154
180
  echo "prelude is also active here"
155
181
  ```
156
182
 
183
+ ## Agent-Native Usage
184
+
185
+ Shellflow is designed to be the execution substrate for an outer agent, not an embedded planner.
186
+
187
+ - Use `--json` when you want one final machine-readable run report.
188
+ - Use `--jsonl` when you want ordered event records while the script runs.
189
+ - Use `--no-input` for CI or agent runs where interactive prompts must fail deterministically.
190
+ - Use `--dry-run` to preview planned execution without running commands.
191
+ - Use `--audit-log <path>` to mirror the structured event stream into a redacted JSONL file.
192
+
193
+ Recommended agent flow:
194
+
195
+ 1. Generate or select a plain shell script with `@LOCAL` and `@REMOTE` markers.
196
+ 2. Add bounded directives only where needed: `@TIMEOUT`, `@RETRY`, and `@EXPORT`.
197
+ 3. Run with `--json` or `--jsonl`.
198
+ 4. Let the outer agent decide whether to retry, branch, or stop based on Shellflow's structured result.
199
+
200
+ Shellflow intentionally does not provide:
201
+
202
+ - Conditional directives such as `@IF stdout_contains=...`
203
+ - A workflow DSL or embedded ReAct loop
204
+ - Heuristic destructive-command detection
205
+
206
+ Those decisions belong in the outer agent or automation layer.
207
+
157
208
  ## CLI
158
209
 
159
210
  ```text
160
211
  shellflow run <script>
161
212
  shellflow run <script> --verbose
213
+ shellflow run <script> --json
214
+ shellflow run <script> --jsonl
215
+ shellflow run <script> --no-input
216
+ shellflow run <script> --dry-run
217
+ shellflow run <script> --audit-log ./audit.jsonl --jsonl
162
218
  shellflow run <script> --ssh-config ./ssh_config
163
219
  shellflow --version
164
220
  ```
@@ -168,6 +224,10 @@ Examples:
168
224
  ```bash
169
225
  shellflow run playbooks/hello.sh
170
226
  shellflow run playbooks/hello.sh -v
227
+ shellflow run playbooks/hello.sh --json
228
+ shellflow run playbooks/hello.sh --jsonl --no-input
229
+ shellflow run playbooks/hello.sh --dry-run --jsonl
230
+ shellflow run playbooks/hello.sh --audit-log ./audit.jsonl --jsonl
171
231
  shellflow run playbooks/hello.sh --ssh-config ~/.ssh/config.work
172
232
  ```
173
233
 
@@ -114,7 +114,60 @@ pwd
114
114
 
115
115
  Why it is bad: the `cd /srv/app` line becomes part of every block, including remote blocks.
116
116
 
117
- ## 4. Assume every block runs in a fresh shell
117
+ ## 4. Use block directives for timeout, retry, and exports
118
+
119
+ Block directives must appear immediately after the `# @LOCAL` or `# @REMOTE <host>` marker, before any command lines. They configure execution behavior for that specific block.
120
+
121
+ ### Timeout Directive
122
+
123
+ `# @TIMEOUT <seconds>` - Abort the block if it exceeds the specified duration.
124
+
125
+ ```bash
126
+ # @LOCAL
127
+ # @TIMEOUT 30
128
+ sleep 60
129
+ ```
130
+
131
+ ### Retry Directive
132
+
133
+ `# @RETRY <count>` - Retry the block up to N times on failure (0 means no retry).
134
+
135
+ ```bash
136
+ # @LOCAL
137
+ # @RETRY 3
138
+ curl -f https://api.example.com/health
139
+ ```
140
+
141
+ ### Export Directive
142
+
143
+ `# @EXPORT NAME=source` - Capture a value from the block result and pass it to subsequent blocks as an environment variable.
144
+
145
+ Valid sources:
146
+
147
+ - `stdout` - The block's standard output
148
+ - `stderr` - The block's standard error
149
+ - `output` - Combined stdout and stderr
150
+ - `exit_code` - The block's exit code (as string)
151
+
152
+ ```bash
153
+ # @LOCAL
154
+ # @EXPORT BUILD_ID=stdout
155
+ echo "build-$(date +%s)"
156
+
157
+ # @LOCAL
158
+ echo "Building: $BUILD_ID"
159
+ ```
160
+
161
+ You can use multiple exports in a single block:
162
+
163
+ ```bash
164
+ # @LOCAL
165
+ # @EXPORT STATUS_CODE=exit_code
166
+ # @EXPORT RESPONSE=stdout
167
+ curl -s -w "%{http_code}" -o response.txt https://api.example.com
168
+ ```
169
+
170
+ ## 5. Assume every block runs in a fresh shell
118
171
 
119
172
  Each block is isolated.
120
173
 
@@ -158,7 +211,7 @@ pwd
158
211
 
159
212
  Why it is bad: `artifact` and the working directory do not persist.
160
213
 
161
- ## 5. Use SHELLFLOW_LAST_OUTPUT for explicit handoff
214
+ ## 6. Use SHELLFLOW_LAST_OUTPUT for explicit handoff
162
215
 
163
216
  Shellflow passes the previous block's combined output into the next block as `SHELLFLOW_LAST_OUTPUT`.
164
217
 
@@ -197,7 +250,7 @@ print(payload["release"])
197
250
  PY
198
251
  ```
199
252
 
200
- ## 6. Use SSH config host aliases, not ad-hoc targets
253
+ ## 7. Use SSH config host aliases, not ad-hoc targets
201
254
 
202
255
  `# @REMOTE <ssh-host>` should point to a host that resolves through SSH config.
203
256
 
@@ -210,7 +263,7 @@ Avoid assuming Shellflow accepts any arbitrary free-form destination unless it i
210
263
 
211
264
  If a remote host is unknown, Shellflow fails before execution.
212
265
 
213
- ## 7. Keep blocks self-contained and fail-fast
266
+ ## 8. Keep blocks self-contained and fail-fast
214
267
 
215
268
  Shellflow runs blocks in order and stops on the first failure.
216
269
 
@@ -243,17 +296,69 @@ docker compose up -d
243
296
 
244
297
  Why: the second block cannot rely on the first block's `cd`.
245
298
 
299
+ ## 9. CLI Options and Output Modes
300
+
301
+ Shellflow provides several CLI options for different use cases:
302
+
303
+ ### Basic Options
304
+
305
+ ```bash
306
+ shellflow run script.sh # Run a script
307
+ shellflow run script.sh -v # Run with verbose output
308
+ shellflow run script.sh --dry-run # Preview execution plan without running
309
+ ```
310
+
311
+ ### Structured Output
312
+
313
+ ```bash
314
+ shellflow run script.sh --json # Single JSON report
315
+ shellflow run script.sh --jsonl # Streaming JSON Lines events
316
+ ```
317
+
318
+ - `--json`: Outputs a single JSON object with the complete run report
319
+ - `--jsonl`: Outputs one JSON object per event (run_started, block_started, block_finished, run_finished)
320
+
321
+ ### Execution Control
322
+
323
+ ```bash
324
+ shellflow run script.sh --no-input # Non-interactive mode (stdin closed)
325
+ shellflow run script.sh --ssh-config /path/to/config # Custom SSH config
326
+ ```
327
+
328
+ - `--no-input`: Closes stdin before running blocks; useful for automation
329
+ - `--ssh-config`: Override the default SSH config path (`~/.ssh/config`)
330
+
331
+ ### Audit Logging
332
+
333
+ ```bash
334
+ shellflow run script.sh --audit-log audit.jsonl --jsonl
335
+ ```
336
+
337
+ The `--audit-log` option writes redacted JSON Lines events to a file. Secret-like exports (containing TOKEN, SECRET, or PASSWORD in the name) are automatically redacted to `[REDACTED]`.
338
+
339
+ ## 10. Exit Codes
340
+
341
+ Shellflow returns distinct exit codes for different failure types:
342
+
343
+ - `0`: Success
344
+ - `1`: General execution failure
345
+ - `2`: Parse failure (invalid script syntax)
346
+ - `3`: SSH config failure (host not found)
347
+ - `4`: Timeout failure (block exceeded timeout)
348
+
246
349
  ## Authoring Checklist
247
350
 
248
351
  Before returning a Shellflow playbook, verify that:
249
352
 
250
353
  - The script is valid bash without custom DSL syntax.
251
- - Only `# @LOCAL` and `# @REMOTE <host>` are used.
354
+ - Only `# @LOCAL`, `# @REMOTE <host>`, and block directives (`# @TIMEOUT`, `# @RETRY`, `# @EXPORT`) are used.
355
+ - Block directives appear immediately after the block marker, before any commands.
252
356
  - Anything before the first marker is safe to repeat for every block.
253
357
  - Every block can run independently in a fresh shell.
254
- - Cross-block data uses `SHELLFLOW_LAST_OUTPUT` explicitly.
358
+ - Cross-block data uses `SHELLFLOW_LAST_OUTPUT` or `@EXPORT` explicitly.
255
359
  - Remote targets match the intended SSH host aliases.
256
360
  - Commands that should happen once are not accidentally placed in the shared prelude.
361
+ - Export sources are valid (stdout, stderr, output, exit_code).
257
362
 
258
363
  ## Reference Example
259
364
 
@@ -266,20 +371,25 @@ log() {
266
371
  }
267
372
 
268
373
  # @LOCAL
374
+ # @EXPORT BUILD_ID=stdout
269
375
  log "building artifact"
270
- artifact="$(mktemp /tmp/shellflow-release.XXXXXX)"
271
- printf 'release-%s\n' "$(date +%Y%m%d%H%M%S)" > "$artifact"
272
- echo "$artifact"
376
+ build_id="build-$(date +%Y%m%d%H%M%S)"
377
+ echo "$build_id"
378
+
379
+ # @LOCAL
380
+ # @TIMEOUT 60
381
+ # @RETRY 2
382
+ log "deploying to staging"
383
+ echo "Deploying $BUILD_ID to staging"
273
384
 
274
385
  # @REMOTE staging
275
- cd /srv/app
276
- artifact_path="$SHELLFLOW_LAST_OUTPUT"
277
- log "receiving artifact path $artifact_path"
278
- test -n "$artifact_path"
279
- uname -a
386
+ # @EXPORT DEPLOYED_HOST=stdout
387
+ log "receiving deployment"
388
+ hostname
280
389
 
281
390
  # @LOCAL
282
- log "remote said: $SHELLFLOW_LAST_OUTPUT"
391
+ log "deployed to: $DEPLOYED_HOST"
392
+ log "build $BUILD_ID complete"
283
393
  ```
284
394
 
285
395
  ## Common Mistakes
@@ -287,6 +397,10 @@ log "remote said: $SHELLFLOW_LAST_OUTPUT"
287
397
  - Putting one-time commands before the first marker, then being surprised when they run for every block.
288
398
  - Expecting `cd`, `export`, or local shell variables from one block to exist in the next block.
289
399
  - Using an undefined remote host alias.
290
- - Printing extra debug output from a block whose output is consumed by the next block.
400
+ - Placing block directives after commands instead of immediately after the marker.
401
+ - Using invalid export sources (not stdout, stderr, output, or exit_code).
402
+ - Forgetting that `@RETRY 0` means no retry attempts.
403
+ - Using `@TIMEOUT` with values too small for normal operation.
404
+ - Printing extra debug output from a block whose output is consumed by the next block via `@EXPORT`.
291
405
  - Forgetting to quote `"$SHELLFLOW_LAST_OUTPUT"`.
292
406
  - Treating Shellflow as a persistent session instead of sequential isolated shells.
@@ -0,0 +1,29 @@
1
+ Feature: Agent-facing execution contract
2
+ As an AI agent operating Shellflow
3
+ I want structured execution results and stable exit codes
4
+ So that I can observe outcomes and decide what to do next outside Shellflow
5
+
6
+ Scenario: JSON report mode returns machine-readable run and block results
7
+ Given a script file with a local block that prints a release version
8
+ When I run the script with JSON output enabled
9
+ Then the command should succeed
10
+ And the JSON output should contain a run id
11
+ And the JSON output should contain a schema version
12
+ And the JSON output should include the first block exit code
13
+ And the JSON output should include the first block stdout separately from stderr
14
+
15
+ Scenario: JSONL mode emits ordered events suitable for live observation
16
+ Given a script file with two local blocks that both succeed
17
+ When I run the script with JSON Lines output enabled
18
+ Then the command should succeed
19
+ And the output should contain a run_started event before a block_started event
20
+ And the output should contain a block_finished event for each block
21
+ And the output should end with a run_finished event
22
+
23
+ Scenario: Exit codes distinguish parse, SSH config, runtime, and timeout failures
24
+ Given the relevant failing scripts for parse, missing SSH host, block failure, and timeout
25
+ When I run each script in machine-readable mode
26
+ Then the parse failure should exit with code 2
27
+ And the missing SSH host failure should exit with code 3
28
+ And the block execution failure should exit with code 1
29
+ And the timeout failure should exit with code 4
@@ -0,0 +1,24 @@
1
+ Feature: Resilience and context propagation
2
+ As an AI agent using Shellflow as an action tool
3
+ I want bounded retries, timeouts, and named exports
4
+ So that I can recover from transient failures without turning Shellflow into a workflow engine
5
+
6
+ Scenario: Timeout stops a stuck block and reports a timeout-specific failure
7
+ Given a script file with a local block that exceeds its timeout directive
8
+ When I run the script in machine-readable mode
9
+ Then the command should fail with timeout exit code 4
10
+ And the structured output should mark the block as timed out
11
+ And the structured output should record the timeout duration policy
12
+
13
+ Scenario: Retry reruns a transiently failing block and reports attempts
14
+ Given a script file with a local block that fails once and then succeeds with a retry directive
15
+ When I run the script in machine-readable mode
16
+ Then the command should succeed
17
+ And the structured output should record 2 attempts for that block
18
+ And the structured output should include a retrying event before the successful finish event
19
+
20
+ Scenario: Named exports become environment variables for later blocks
21
+ Given a script file whose first block exports VERSION from stdout
22
+ When I run the script
23
+ Then the later block should receive VERSION in its environment
24
+ And SHELLFLOW_LAST_OUTPUT should still be available
@@ -0,0 +1,24 @@
1
+ Feature: Safety controls for automated runs
2
+ As an operator delegating execution to an AI agent
3
+ I want non-interactive and audit-friendly controls
4
+ So that automated runs are observable without relying on shell heuristics
5
+
6
+ Scenario: No-input prevents blocking on stdin
7
+ Given a script file with a local block that reads from standard input
8
+ When I run the script with no-input enabled
9
+ Then the command should fail deterministically instead of waiting for input
10
+ And the structured output should indicate that no interactive input was available
11
+
12
+ Scenario: Dry-run previews execution without running commands
13
+ Given a script file with local and remote blocks
14
+ When I run the script in dry-run mode
15
+ Then no block commands should be executed
16
+ And the output should describe the planned blocks in order
17
+ And the output should include structured dry-run events when machine-readable mode is enabled
18
+
19
+ Scenario: Audit-log writes structured events for later inspection
20
+ Given a script file with a named export that looks like a secret
21
+ When I run the script with an audit log path
22
+ Then the command should succeed
23
+ And the audit log file should contain JSON Lines events
24
+ And the audit log should redact the secret-like exported value