Your first workflow

This is a learning-oriented walkthrough. By the end of it you will have authored a single .jh file, run it with the jaiph CLI, watched the live progress tree, and inspected the durable artifacts the runtime wrote under .jaiph/runs/.

This tutorial deliberately uses only script steps — no agent backend, no API keys, no Docker. The follow-up tutorial Your first agent + sandboxed run adds a prompt step and the Docker sandbox on top of what you build here.

What you will build

A workflow that runs one script step which prints a greeting, and a return step that propagates the script’s output as the workflow’s return value. The whole file is five lines.

Prerequisites

Node, Docker, and API keys are not required for this tutorial. Runs use jaiph run --unsafe so execution stays on the host (Docker is on by default for jaiph run).

1. Install the CLI

Install the standalone binary:

curl -fsSL https://jaiph.org/install | bash

The installer downloads a per-platform binary, verifies its checksum, and writes it to ~/.local/bin/jaiph. See Install & switch versions for alternatives (npm, JAIPH_BIN_DIR, version switching).

Confirm the install:

jaiph --version

If the command is not found, prepend the install directory to PATH:

export PATH="$HOME/.local/bin:$PATH"

2. Author the workflow

Create a fresh directory and write a file named hello.jh:

script greet = `echo "Hello, ${1:-world}!"`

workflow default(who) {
  return run greet(who)
}

Three things are happening:

3. Run it

jaiph run --unsafe ./hello.jh "Adam"

--unsafe sets JAIPH_UNSAFE=true for this run only and skips the Docker sandbox. Two notes on what happens before any step runs:

You should see this (timings will differ):

Jaiph: Running hello.jh (no sandbox)

workflow default (who="Adam")
  ▸ script greet (1="Adam")
  ✓ script greet (0s)

✓ PASS workflow default (0.2s)

Hello, Adam!

The first line is the sandbox banner. The workflow default row and the indented / rows are the live progress tree ( = step started, = step completed; (0s) is per-step elapsed time). The root workflow row is static; only nested steps emit / lines. The blank line and Hello, Adam! after PASS are the workflow return valuejaiph run prints it on stdout after a successful run.

The (no sandbox) banner reflects --unsafe: the workflow runs on the host with no container. Omit --unsafe and jaiph run uses the Docker sandbox by default; the banner then reads (Docker sandbox, fusefs) or (Docker sandbox, tmp workspace) depending on the host. If Docker is enabled but the daemon is unavailable, the CLI exits with E_DOCKER_NOT_FOUND rather than falling back to the host.

4. Inspect the run artifacts

Every run writes durable files under .jaiph/runs/<YYYY-MM-DD>/<HH-MM-SS>-<entry>/ in UTC. List the most recent run:

ls -la .jaiph/runs/*/*/

The layout you should see:

Read the captured script output and the return value:

cat .jaiph/runs/*/*/000002-script__greet.out
cat .jaiph/runs/*/*/return_value.txt

Both should match the line printed after PASS. The full artifact layout is pinned in Architecture — Durable artifact layout; the event types in run_summary.jsonl are documented in CLI Reference — Run artifacts.

Replace the script body with one that exits non-zero:

script greet = `echo "Hello, ${1:-world}!" && exit 7`

workflow default(who) {
  return run greet(who)
}

Re-run with the same arguments:

jaiph run --unsafe ./hello.jh "Adam"

The CLI prints a ✗ FAIL line on stderr, a Logs: / Summary: / out: / err: block pointing to the run directory, and an Output of failed step: excerpt. The process exits non-zero. return_value.txt is not written on failure — only success.

Where to go next

Revert the failing script body so the workflow passes again, then pick a direction: