Skip to main content
Shipfox uses CEL (Common Expression Language) in two places: predicates that decide an outcome (a gate, a job’s success), and template interpolation — the ${{ }} syntax that injects run and trigger context into your step values. Both are evaluated by the same read-only CEL engine: expressions can compute over the data in scope, but they cannot read secrets, the database, the network, or the filesystem.

The CEL engine

Expressions support CEL’s standard value types — integers, strings, booleans, lists, and maps — and its standard operators (==, !=, <, >, &&, ||, !, in, arithmetic) and macros (.map(), .filter(), .all(), .exists()) plus string helpers like .contains(), .startsWith(), and .endsWith(). There are no custom functions and no side effects.

Predicates

Gate success — gate.success_if

Evaluated on a gated step the moment it finishes. The only variable in scope is exit_code (an integer). See Gates for the full gate model.
gate:
  success_if: "exit_code == 0"

Job success — success

A job’s optional success expression decides whether the job succeeded once all its step executions have settled. In scope is executions — a list of {index, status} — so you can express partial-success rules. The default, applied when you omit success, is:
jobs:
  build:
    success: 'executions.all(e, e.status == "succeeded")'
    steps:
      - run: ./maybe-flaky.sh

Template interpolation — ${{ }}

Interpolation injects run and trigger context into step values. Expressions are resolved when a run is created, before any runner sees the step, and the resolved values are what execute.
jobs:
  build:
    env:
      RUN_ID: "${{ run.id }}"
      SOURCE: "${{ trigger.source }}"
    steps:
      - run: echo "Building for ${{ trigger.event }}"
      - prompt: "Investigate the event that triggered this run: ${{ event.title }}"
Interpolation is supported in run commands, env values, and agent prompts. To write a literal ${{, escape it as $${{.

Context available

ContextFieldsTrust
runid, name, definition_id, project_id, workspace_id, created_atTrusted
triggersource, eventTrusted
jobnameTrusted
eventThe trigger’s raw event payload (open shape — e.g. event.ref, event.action, event.body)Untrusted
inputsValues passed through a trigger’s with block (open shape)Untrusted
Untrusted context can’t select infrastructure. event and inputs carry data from outside your workspace, so they may be used in env, run, and prompt values but not to choose an agent’s model or provider, which accept trusted context only.

Interpolation inside run commands

For safety, values interpolated into a run command are passed to the shell through generated environment variables rather than spliced into the command text. You write echo "${{ run.id }}" as normal; Shipfox rewrites it to reference a generated variable holding the resolved value, so event-derived data can’t inject shell syntax.

Trigger filters are not evaluated yet

A trigger’s filter also accepts a CEL expression (over the event, e.g. event.ref == "refs/heads/main"), but it is parsed and stored, not evaluated — every matching (source, event) fires the trigger today. See Triggers. To gate on event data now, branch inside a run step or interpolate the value and check it there.

Shipped vs. roadmap

FeatureStatus
gate.success_if (CEL over exit_code)✅ Shipped
Job success (CEL over executions)✅ Shipped
${{ }} interpolation in run, env, prompt✅ Shipped
Trigger filter evaluation🔜 Roadmap
loop, matrix, branch🔜 Roadmap

Gates

Where success_if decides a step outcome.

Workflow schema

The full YAML schema these expressions live in.