Scripting

Everything below applies to every command.

Reading input from files and stdin

Any flag that takes JSON or a list also accepts @path to read a file, or @- to read stdin.

sim workflows import --workflow @wf.json
sim tables rows query tbl_123 --filter @filter.json
cat wf.json | sim workflows import --workflow @-

List flags

Primitive lists take space-separated values. With @, the file supplies one value per line:

sim files mv --file-ids file_1 file_2 --to Archive
sim files mv --file-ids @file-ids.txt --to Archive
printf 'file_1\nfile_2\n' | sim files mv --file-ids @- --to Archive

Arrays of objects stay JSON.

Filtering table rows

--filter takes the same predicate tree the API uses: all (AND) or any (OR) groups of {field, op, value} conditions, nestable.

sim tables rows query tbl_123 \
  --filter '{"all":[{"field":"status","op":"eq","value":"open"},
                    {"field":"score","op":"gt","value":10}]}' \
  --limit 50

Operators: eq, ne, gt, gte, lt, lte, in, nin, contains, ncontains, startsWith, endsWith, like, ilike, nlike, nilike, isEmpty, isNotEmpty, isNull, isNotNull.

--sort is also JSON, an ordered list of keys:

sim tables rows query tbl_123 --sort '[{"field":"createdAt","direction":"desc"}]'

Pagination

List commands page automatically up to --limit, which defaults to 100. Pass --limit 0 to fetch everything:

sim logs list --limit 0 --output json > all-logs.json

Destructive commands

Deletions require an explicit selector and --yes. There is no "delete everything" default:

sim tables rows batch-delete tbl_123 --row row_1 row_2 --yes
sim files delete file_123 --yes

Without --yes the command explains what it would have destroyed and stops.

batch-delete and batch-update carry the default --limit of 100, so a filter matching more rows than that silently affects only the first 100. Pass --limit 0 to affect every matching row.

Exit codes

CodeMeaning
0Success
1Anything else — API error, bad configuration, invalid arguments, or a missing --yes

Errors print one line to stderr, prefixed Error:, plus the API's error code and validation details when it supplies them. Failures are safe to branch on:

if ! sim workflows run wf_7Yb2 --output json > result.json; then
  echo "run failed" >&2
  exit 1
fi

An unexpected error prints a stack trace — that is a bug in the CLI, so please open an issue.

Selecting workflow output

--select-output takes blockName.field selectors. Fields that a run did not produce are simply omitted:

sim workflows run wf_7Yb2 --select-output agent_1.content --output json

Polling a long run

Start the run asynchronously, then poll its status:

run_id=$(sim workflows run wf_7Yb2 --async --output json | jq -r '.runId')

until sim workflows runs get "$run_id" --workflow wf_7Yb2 --output json \
  | jq -e '.status | IN("completed","failed","cancelled")' > /dev/null; do
  sleep 5
done

sim logs get "$run_id" --trace

workflows runs get is the lightweight status check; logs get is the full diagnostic. For a paused run, the status includes the context ID that sim workflows runs resume needs.

Working with folders

Every folder-backed resource — workflows, tables, files, knowledge — shares the same path commands:

sim tables ls Reports
sim tables mkdir Reports/Quarterly
sim tables folders mv Reports/Quarterly Archive/Quarterly
sim tables folders delete Archive --recursive --yes

ls lists the resources at a path plus that folder's direct children, never deeper. Its ref column is the value to pass to the next command. Use list for resources only, or folders ls for folders only. A leading / is optional.

A nightly job, end to end

nightly-digest.sh
#!/usr/bin/env bash
set -euo pipefail

export SIM_API_KEY="${SIM_API_KEY:?missing}"
export SIM_WORKSPACE="${SIM_WORKSPACE:?missing}"
export SIM_OUTPUT=json

run_id=$(sim workflows run wf_7Yb2 --input '{"source":"nightly"}' | jq -r '.runId')

if [ "$(sim workflows runs get "$run_id" --workflow wf_7Yb2 | jq -r '.status')" != "completed" ]; then
  sim logs get "$run_id" >&2
  exit 1
fi

On this page