Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions .claude/skills/swamp-model/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,31 +59,31 @@ definitions referenced across multiple workflows.

## Quick Reference

| Task | Command |
| ------------------- | ---------------------------------------------------------------- |
| Search model types | `swamp model type search [query] --json` |
| Describe a type | `swamp model type describe <type> --json` |
| Create model input | `swamp model create <type> <name> --json` |
| Create with args | `swamp model create <type> <name> --global-arg key=value --json` |
| Search models | `swamp model search [query] --json` |
| Get model details | `swamp model get <id_or_name> --json` |
| Edit model input | `swamp model edit [id_or_name]` |
| Delete a model | `swamp model delete <id_or_name> --json` |
| Validate model | `swamp model validate [id_or_name] --json` |
| Validate by label | `swamp model validate [id_or_name] --label policy --json` |
| Validate by method | `swamp model validate [id_or_name] --method create --json` |
| Evaluate input(s) | `swamp model evaluate [id_or_name] --json` |
| Run a method | `swamp model method run <id_or_name> <method>` |
| Run with inputs | `swamp model method run <name> <method> --input key=value` |
| Run from stdin | `echo '{"k":"v"}' \| swamp model method run <name> <method>` |
| Direct type exec | `swamp model @<type> method run <method> <name> --input k=v` |
| Skip all checks | `swamp model method run <name> <method> --skip-checks` |
| Skip check by name | `swamp model method run <name> <method> --skip-check <n>` |
| Skip check by label | `swamp model method run <name> <method> --skip-check-label <l>` |
| Search outputs | `swamp model output search [query] --json` |
| Get output details | `swamp model output get <output_or_model> --json` |
| View output logs | `swamp model output logs <output_id> --json` |
| View output data | `swamp model output data <output_id> --json` |
| Task | Command |
| ------------------- | -------------------------------------------------------------------- |
| Search model types | `swamp model type search [query] --json` |
| Describe a type | `swamp model type describe <type> --json` |
| Create model input | `swamp model create <type> <name> --json` |
| Create with args | `swamp model create <type> <name> --global-arg key=value --json` |
| Search models | `swamp model search [query] --json` |
| Get model details | `swamp model get <id_or_name> --json` |
| Edit model input | `swamp model edit [id_or_name]` |
| Delete a model | `swamp model delete <id_or_name> --json` |
| Validate model | `swamp model validate [id_or_name] --json` |
| Validate by label | `swamp model validate [id_or_name] --label policy --json` |
| Validate by method | `swamp model validate [id_or_name] --method create --json` |
| Evaluate input(s) | `swamp model evaluate [id_or_name] --json` |
| Run a method | `swamp model method run <id_or_name> <method>` |
| Run with inputs | `swamp model method run <name> <method> --input key=value` |
| Run from stdin | `echo '{"k":"v"}' \| swamp model method run <name> <method> --stdin` |
| Direct type exec | `swamp model @<type> method run <method> <name> --input k=v` |
| Skip all checks | `swamp model method run <name> <method> --skip-checks` |
| Skip check by name | `swamp model method run <name> <method> --skip-check <n>` |
| Skip check by label | `swamp model method run <name> <method> --skip-check-label <l>` |
| Search outputs | `swamp model output search [query] --json` |
| Get output details | `swamp model output get <output_or_model> --json` |
| View output logs | `swamp model output logs <output_id> --json` |
| View output data | `swamp model output data <output_id> --json` |

## Repository Structure

Expand Down Expand Up @@ -424,9 +424,9 @@ swamp model method run my-deploy create --input config.timeout=30 # dot notatio
swamp model method run my-deploy create --input 'tags:json=["prod","west"]' # :json suffix for arrays/objects
swamp model method run my-deploy create --input '{"environment": "prod"}' # legacy single-shot JSON
swamp model method run my-deploy create --input-file inputs.yaml
echo '{"environment": "prod"}' | swamp model method run my-deploy create # stdin auto-detected
printf '{"environment":"dev"}\n{"environment":"prod"}' | swamp model method run my-deploy create # NDJSON: one run per line
swamp data query 'modelName == "source"' --json | jq -c '.results[] | {environment: .attributes.env}' | swamp model method run my-deploy create # pipe composition
echo '{"environment": "prod"}' | swamp model method run my-deploy create --stdin
printf '{"environment":"dev"}\n{"environment":"prod"}' | swamp model method run my-deploy create --stdin # NDJSON: one run per line
swamp data query 'modelName == "source"' --json | jq -c '.results[] | {environment: .attributes.env}' | swamp model method run my-deploy create --stdin
swamp model method run my-deploy create --last-evaluated
swamp model method run my-deploy create --skip-checks
swamp model method run my-deploy create --skip-check valid-region
Expand Down
10 changes: 5 additions & 5 deletions .claude/skills/swamp-model/references/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,19 +204,19 @@ swamp model method run my-deploy deploy --input '{"environment": "production"}'
# YAML file input
swamp model method run my-deploy deploy --input-file inputs.yaml

# Piped stdin (auto-detected, no flag needed)
echo '{"environment": "production"}' | swamp model method run my-deploy deploy
# Piped stdin (explicit --stdin flag required)
echo '{"environment": "production"}' | swamp model method run my-deploy deploy --stdin

# NDJSON from stdin: one run per line
printf '{"environment":"dev"}\n{"environment":"prod"}' | swamp model method run my-deploy deploy
printf '{"environment":"dev"}\n{"environment":"prod"}' | swamp model method run my-deploy deploy --stdin

# Pipe from data query via jq
swamp data query 'modelName == "source"' --json \
| jq -c '.results[] | {environment: .attributes.env}' \
| swamp model method run my-deploy deploy
| swamp model method run my-deploy deploy --stdin

# Stdin + --input overrides (--input wins on conflict)
echo '{"environment": "dev"}' | swamp model method run my-deploy deploy --input dryRun=true
echo '{"environment": "dev"}' | swamp model method run my-deploy deploy --stdin --input dryRun=true
```

**Input file format (inputs.yaml)**:
Expand Down
10 changes: 5 additions & 5 deletions .claude/skills/swamp-model/references/scenarios.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,8 @@ swamp model validate my-instance --json
```
User wants runtime parameterization → Use inputs schema
Values change per invocation → --input or --input-file
Values come from another command → Pipe stdin (auto-detected)
Batch run over query results → data query --json | jq | method run
Values come from another command → Pipe with --stdin
Batch run over query results → data query --json | jq | method run --stdin
```

### Step-by-Step
Expand Down Expand Up @@ -302,14 +302,14 @@ swamp model method run my-deploy deploy --input-file inputs/production.yaml
**6. Alternative: Pipe inputs from another command**

```bash
# Stdin is auto-detected — pipe JSON and it becomes the inputs
# Pass --stdin to read piped JSON as inputs
echo '{"environment": "production", "replicas": 5}' \
| swamp model method run my-deploy deploy
| swamp model method run my-deploy deploy --stdin

# Batch: run deploy for each result from a data query
swamp data query 'modelName == "infra" && attributes.status == "pending"' --json \
| jq -c '.results[] | {environment: .attributes.env, replicas: .attributes.count}' \
| swamp model method run my-deploy deploy
| swamp model method run my-deploy deploy --stdin
```

### CEL Paths Used
Expand Down
49 changes: 25 additions & 24 deletions .claude/skills/swamp-workflow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,25 @@ run.

## Quick Reference

| Task | Command |
| ------------------ | ------------------------------------------------------ |
| Get schema | `swamp workflow schema get --json` |
| Search workflows | `swamp workflow search [query] --json` |
| Get a workflow | `swamp workflow get <id_or_name> --json` |
| Create a workflow | `swamp workflow create <name> --json` |
| Edit a workflow | `swamp workflow edit [id_or_name]` |
| Delete a workflow | `swamp workflow delete <id_or_name> --json` |
| Validate workflow | `swamp workflow validate [id_or_name] --json` |
| Evaluate workflow | `swamp workflow evaluate <id_or_name> --json` |
| Run a workflow | `swamp workflow run <id_or_name>` |
| Run with inputs | `swamp workflow run <id_or_name> --input key=value` |
| Run from stdin | `echo '{"k":"v"}' \| swamp workflow run <id_or_name>` |
| View run history | `swamp workflow history search --json` |
| Get latest run | `swamp workflow history get <workflow> --json` |
| View run logs | `swamp workflow history logs <run_or_workflow> --json` |
| List workflow data | `swamp data list --workflow <name> --json` |
| Query wf data | `swamp data query 'tags.workflow == "<name>"'` |
| Get workflow data | `swamp data get --workflow <name> <data_name> --json` |
| Task | Command |
| ------------------ | ------------------------------------------------------------- |
| Get schema | `swamp workflow schema get --json` |
| Search workflows | `swamp workflow search [query] --json` |
| Get a workflow | `swamp workflow get <id_or_name> --json` |
| Create a workflow | `swamp workflow create <name> --json` |
| Edit a workflow | `swamp workflow edit [id_or_name]` |
| Delete a workflow | `swamp workflow delete <id_or_name> --json` |
| Validate workflow | `swamp workflow validate [id_or_name] --json` |
| Evaluate workflow | `swamp workflow evaluate <id_or_name> --json` |
| Run a workflow | `swamp workflow run <id_or_name>` |
| Run with inputs | `swamp workflow run <id_or_name> --input key=value` |
| Run from stdin | `echo '{"k":"v"}' \| swamp workflow run <id_or_name> --stdin` |
| View run history | `swamp workflow history search --json` |
| Get latest run | `swamp workflow history get <workflow> --json` |
| View run logs | `swamp workflow history logs <run_or_workflow> --json` |
| List workflow data | `swamp data list --workflow <name> --json` |
| Query wf data | `swamp data query 'tags.workflow == "<name>"'` |
| Get workflow data | `swamp data get --workflow <name> <data_name> --json` |

## Repository Structure

Expand Down Expand Up @@ -259,13 +259,13 @@ swamp workflow run my-workflow --input environment=production --input replicas=3
swamp workflow run my-workflow --input 'tags:json=["prod","west"]' # :json suffix for arrays/objects
swamp workflow run my-workflow --input '{"environment": "production"}' # legacy single-shot JSON
swamp workflow run my-workflow --input-file inputs.yaml
echo '{"environment": "prod"}' | swamp workflow run my-workflow # stdin auto-detected
printf '{"environment":"dev"}\n{"environment":"prod"}' | swamp workflow run my-workflow # NDJSON: one run per line
echo '{"environment": "prod"}' | swamp workflow run my-workflow --stdin
printf '{"environment":"dev"}\n{"environment":"prod"}' | swamp workflow run my-workflow --stdin # NDJSON: one run per line
swamp workflow run my-workflow --last-evaluated # Use pre-evaluated workflow
```

Piped stdin is auto-detected. JSON objects, JSON arrays, NDJSON (one JSON per
line), and YAML are supported. Multiple items (array or NDJSON) produce one
Pass `--stdin` to read piped input. JSON objects, JSON arrays, NDJSON (one JSON
per line), and YAML are supported. Multiple items (array or NDJSON) produce one
workflow run per item. `--input` key=value overrides are deep-merged onto each
stdin item.

Expand All @@ -274,7 +274,8 @@ stdin item.
| Flag | Description |
| ------------------- | ------------------------------------------------------------------ |
| `--input <value>` | Input values (key=value repeatable, or JSON) |
| `--input-file <f>` | Input values from YAML file (cannot combine with piped stdin) |
| `--input-file <f>` | Input values from YAML file (cannot combine with `--stdin`) |
| `--stdin` | Read inputs from stdin (piped data) |
| `--last-evaluated` | Use previously evaluated workflow (skip eval and input validation) |
| `--driver <driver>` | Override execution driver for all steps (e.g. `raw`, `docker`) |

Expand Down
12 changes: 6 additions & 6 deletions .claude/skills/swamp-workflow/references/scenarios.md
Original file line number Diff line number Diff line change
Expand Up @@ -580,17 +580,17 @@ Run a workflow for each result from a data query using Unix pipes and `jq`.
# Run workflow once per pending item from a data query
swamp data query 'modelName == "source" && attributes.status == "pending"' --json \
| jq -c '.results[] | {environment: .attributes.env}' \
| swamp workflow run deploy-pipeline
| swamp workflow run deploy-pipeline --stdin

# NDJSON: run workflow once per line
printf '{"environment":"dev"}\n{"environment":"prod"}' \
| swamp workflow run deploy-pipeline
| swamp workflow run deploy-pipeline --stdin

# Stdin + --input overrides (--input wins on conflict)
echo '{"environment": "dev"}' \
| swamp workflow run deploy-pipeline --input dryRun=true
| swamp workflow run deploy-pipeline --stdin --input dryRun=true
```

Stdin is auto-detected — no flag needed. JSON objects, JSON arrays, NDJSON, and
YAML are all supported. Multiple items produce one workflow run per item.
Execution stops on the first failure.
Pass `--stdin` to read piped input. JSON objects, JSON arrays, NDJSON, and YAML
are all supported. Multiple items produce one workflow run per item. Execution
stops on the first failure.
18 changes: 9 additions & 9 deletions design/inputs.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ via `--input-file` with YAML/JSON, or via the legacy single-shot

### Reading inputs from stdin

Both `method run` and `workflow run` auto-detect piped stdin. When data is piped
to the command, it is read and parsed as inputs — no flag needed. This enables
Unix pipe composition following the same pattern as `vault put`, `model edit`,
and `workflow edit`.
Both `method run` and `workflow run` accept piped stdin via the `--stdin` flag.
When `--stdin` is passed, the command reads stdin until EOF and parses it as
inputs. This enables Unix pipe composition following the same pattern as `jq -n`
(explicit opt-in).

The input format is detected automatically:

Expand All @@ -250,22 +250,22 @@ executed once per item. Each execution is discrete — it produces its own data
artifacts, runs pre-flight checks, and reports independently. Execution stops on
the first failure.

Piped stdin and `--input-file` cannot be combined. `--input` key=value overrides
can be combined with piped stdin — they are deep-merged onto each stdin item (the
`--stdin` and `--input-file` cannot be combined. `--input` key=value overrides
can be combined with `--stdin` — they are deep-merged onto each stdin item (the
`--input` values win on conflict).

```sh
# Single JSON object from stdin
echo '{"run": "echo hello"}' | swamp model method run my-model execute
echo '{"run": "echo hello"}' | swamp model method run my-model execute --stdin

# NDJSON: run method once per line
printf '{"run":"echo a"}\n{"run":"echo b"}' \
| swamp model method run my-model execute
| swamp model method run my-model execute --stdin

# Pipe from data query via jq, with static overrides
swamp data query 'modelName == "source"' --json \
| jq -c '.results[] | {run: .attributes.command}' \
| swamp model method run target-model execute --input env=prod
| swamp model method run target-model execute --stdin --input env=prod
```

## Input Routing for Direct Type Execution
Expand Down
10 changes: 5 additions & 5 deletions src/cli/commands/model_method_run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,11 @@ export const modelMethodRunCommand = new Command()
)
.example(
"Pipe inputs from stdin",
'echo \'{"env":"prod"}\' | swamp model method run my-server deploy',
'echo \'{"env":"prod"}\' | swamp model method run my-server deploy --stdin',
)
.example(
"Batch run via NDJSON from stdin",
'printf \'{"env":"dev"}\\n{"env":"prod"}\' | swamp model method run my-server deploy',
'printf \'{"env":"dev"}\\n{"env":"prod"}\' | swamp model method run my-server deploy --stdin',
)
.description(
"Execute a method on a model. With @type prefix, auto-creates the definition if needed.",
Expand All @@ -115,8 +115,9 @@ export const modelMethodRunCommand = new Command()
})
.option(
"--input-file <file:string>",
"Input values from YAML file (cannot combine with piped stdin)",
"Input values from YAML file (cannot combine with --stdin)",
)
.option("--stdin", "Read inputs from stdin (piped data)", { default: false })
.option(
"--tag <tag:string>",
"Add tag to produced data (KEY=VALUE, repeatable)",
Expand Down Expand Up @@ -198,8 +199,7 @@ export const modelMethodRunCommand = new Command()
ctx.logger
.debug`Running method '${methodName}' on model: ${modelIdOrName}`;

// Auto-detect piped stdin (returns null when stdin is a TTY)
const stdinContent = await readStdin();
const stdinContent = options.stdin ? await readStdin() : null;
let stdinItems: Record<string, unknown>[] | null = null;
if (stdinContent !== null) {
if (options.inputFile) {
Expand Down
10 changes: 5 additions & 5 deletions src/cli/commands/workflow_run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ export const workflowRunCommand = new Command()
.example("Skip reports", "swamp workflow run deploy-pipeline --skip-reports")
.example(
"Pipe inputs from stdin",
'echo \'{"env":"prod"}\' | swamp workflow run deploy-pipeline',
'echo \'{"env":"prod"}\' | swamp workflow run deploy-pipeline --stdin',
)
.example(
"Batch run via NDJSON from stdin",
'printf \'{"env":"dev"}\\n{"env":"prod"}\' | swamp workflow run deploy-pipeline',
'printf \'{"env":"dev"}\\n{"env":"prod"}\' | swamp workflow run deploy-pipeline --stdin',
)
.arguments("<workflow_id_or_name:workflow_name>")
.option(
Expand All @@ -113,8 +113,9 @@ export const workflowRunCommand = new Command()
})
.option(
"--input-file <file:string>",
"Input values from YAML file (cannot combine with piped stdin)",
"Input values from YAML file (cannot combine with --stdin)",
)
.option("--stdin", "Read inputs from stdin (piped data)", { default: false })
.option(
"--tag <tag:string>",
"Add tag to produced data (KEY=VALUE, repeatable)",
Expand Down Expand Up @@ -174,8 +175,7 @@ export const workflowRunCommand = new Command()

const lastEvaluated = options.lastEvaluated as boolean;

// Auto-detect piped stdin (returns null when stdin is a TTY)
const stdinContent = await readStdin();
const stdinContent = options.stdin ? await readStdin() : null;
let stdinItems: Record<string, unknown>[] | null = null;
if (stdinContent !== null) {
if (options.inputFile) {
Expand Down
Loading
Loading