Jaiph CLI Reference

Overview

Jaiph workflow sources (.jh / .jph) are programs: the CLI parses them, checks references, and transpiles them to bash that runs on your machine. Optional Sandboxing runs that generated bash inside Docker instead of directly on the host. The same jaiph executable drives compilation (build), execution (run), the native test runner (test), workspace scaffolding (init), reinstalling from a Git ref (use), and a read-only local UI over run logs (report). Language syntax and semantics are documented separately (for example Grammar); this page is the command-line contract.

Typical tasks:

Commands: build, run, test, init, use, report.

Global options: -h / --help and -v / --version are only recognized when they are the first argument (for example jaiph --help). They do not apply after a subcommand (jaiph build --help is not supported). The reporting subcommand documents its own flags: jaiph report --help.


jaiph <file.jh> and jaiph <file.test.jh> (shorthand)

If the first argument is a path to an existing file whose name ends with .jh or .jph, Jaiph treats it as a workflow and runs it (same as jaiph run <file>). If the first argument ends with .test.jh or .test.jph and the file exists, Jaiph runs that test file (same as jaiph test <file>).

Workflow shorthand:

jaiph ./flows/review.jh "review this diff"
# equivalent to: jaiph run ./flows/review.jh "review this diff"

Test shorthand:

jaiph ./e2e/say_hello.test.jh
# equivalent to: jaiph test ./e2e/say_hello.test.jh

jaiph build

Compile .jh and .jph files into shell scripts.

jaiph build [--target <dir>] [path]

If path is omitted, the current directory (./) is used. Without --target, compiled .sh scripts are written alongside the source files. Use --target to redirect output to a specific directory.

Examples:

jaiph build ./
jaiph build --target ./build ./flows
jaiph build ./flows/review.jh

jaiph run

Compile and run a Jaiph workflow file. jaiph run requires a workflow default entrypoint.

jaiph run [--target <dir>] <file.jh|file.jph> [--] [args...]

Only the specified file and its transitive imports are compiled. Parse errors in sibling .jh files do not affect the run. Use --target to keep the compiled shell script in a specific directory (useful for debugging the transpiler output); without it, the compiled script is written to a temp directory and cleaned up after the run. Use -- to separate Jaiph flags from workflow arguments (e.g. jaiph run file.jh -- --verbose).

Examples:

jaiph run ./.jaiph/bootstrap.jh
jaiph run ./flows/review.jh "review this diff"

Argument passing matches standard bash script behavior:

Rules also receive forwarded arguments through ensure, for example:

rule current_branch {
  test "$(git branch --show-current)" = "$1"
}

workflow default {
  ensure current_branch "main"
}

prompt text follows bash-style variable expansion (for example $1, ${HOME}, ${FILES[@]}). For safety, command substitution is not allowed in prompt text: $(...) and backticks are rejected with E_PARSE.

Elsewhere in workflows, $(...) is shell-only: it must not invoke Jaiph rules, workflows, or functions, contain inbox send (<-), or use run / ensure as shell commands (E_VALIDATE). The same rules apply to every workflow shell line: the first command word cannot name a Jaiph symbol, even when the line also contains $(...); use run to call functions from a workflow, not a bare fn arg line. See Grammar.

If a .jh or .jph file is executable and has #!/usr/bin/env jaiph, you can run it directly:

./.jaiph/bootstrap.jh "task details"
./flows/review.jh "review this diff"

Run progress and tree output

During jaiph run, the CLI renders a tree of steps. Shared in TTY and non-TTY: each step appears as a line with a marker (▸ when started, ✓/✗ when done), the step kind (workflow, prompt, function, rule), and the step name. log messages also appear inline in the tree at the correct indentation depth — they have no marker, spinner, or timing; just the symbol (dim/gray) followed by the message text. Completion lines include the step kind and name so that each line is self-identifying even when multiple steps run concurrently (e.g. ✓ workflow scanner (0s), ✗ rule ci_passes (11s)). The root PASS/FAIL summary retains its existing format (✓ PASS workflow default (0.2s)). There are no per-step live elapsed counters or in-place updates on the start/completion tree lines themselves.

TTY only: One extra line at the bottom shows which workflow is running and total elapsed: ▸ RUNNING workflow <name> (X.Xs)▸ RUNNING in yellow, workflow in bold, workflow name in default style, time in dim. This line is the only line updated in place (every second). When the run completes, that line is cleared and replaced by the final PASS/FAIL line.

Non-TTY (stdout not a TTY — CI, pipes, log capture): No RUNNING line and no in-place updates. Step start lines (▸) and completion lines (✓/✗) still print as they occur. Long-running steps additionally print status heartbeat lines so a quiet stretch between ▸ and ✓ does not look like a hang:

On stderr, the runtime emits __JAIPH_EVENT__ lines (each followed by JSON). The CLI parses valid JSON to drive the tree, hooks, and failure summaries, so those lines do not appear verbatim in the log. Any other stderr text is forwarded to your terminal; in TTY mode the bottom “RUNNING …” line is cleared and redrawn around those writes. STEP_END payloads may embed step output (out_content / err_content); the runtime JSON-escapes those strings so tabs, ANSI escape bytes, and other control characters cannot break the line. If a payload is not valid JSON, the CLI treats it as plain stderr — in CI you may see a raw __JAIPH_EVENT__ … line instead of structured progress.

For parameterized invocations—when you pass arguments to a workflow, prompt, function, or rule—the tree shows those argument values inline in gray immediately after the step name. Format:

Example lines:

If no parameters are passed, the line is unchanged (e.g. ▸ workflow default). Color can be disabled with NO_COLOR=1.

Prompt steps show no output in the tree. When a prompt step completes, only the step line and ✓ appear — no Command, Prompt, Reasoning, or Final answer block. To display agent output in the tree, use log explicitly:

response = prompt "Summarize the report"
log "$response"

The log line renders inline at the correct depth as ℹ <message> (dim/gray) and writes to stdout. The logerr variant renders as ! <message> in red and writes to stderr. The step’s .out file in .jaiph/runs/ still contains the full agent transcript for debugging.

Run artifacts and live output

Every step writes its stdout and stderr to artifact files under .jaiph/runs/<date>/<time>-<source>/ (see JAIPH_RUNS_DIR). Files are named with a zero-padded sequence prefix reflecting execution order: 000001-module__rule.out, 000002-module__workflow.err, etc.

All step kinds write to artifact files incrementally during execution, not only after the step completes. This means you can tail a running step’s output in real time from another terminal:

# In one terminal — run a long workflow
jaiph run ./flows/deploy.jh

# In another terminal — watch a step's output as it executes
tail -f .jaiph/runs/2026-03-22/14-30-00-deploy.jh/000003-deploy__run_migrations.out

Both .out (stdout) and .err (stderr) files grow as the step produces output. Steps that produce no output on a given stream have no corresponding artifact file. Empty files are cleaned up automatically at step end.

Run summary (run_summary.jsonl)

Each run directory also contains run_summary.jsonl: one JSON object per line, appended in execution order. It is the canonical append-only record of reporting-oriented runtime events (lifecycle, logs, inbox flow, and step boundaries). Tooling can tail the file by byte offset and process new lines idempotently; parallel inbox dispatch may reorder some events relative to wall-clock time, but each line is written atomically under the same lock used for concurrent writers (see Inbox — Lock behavior).

Versioning. Every persisted object includes event_version (currently 1). New fields may be added in later versions; consumers should tolerate unknown keys.

Common fields. All summary lines include type, ts (UTC timestamp), run_id, and event_version. Step-related types also carry stable correlation fields id, parent_id, seq, and depth where applicable (matching the __JAIPH_EVENT__ stream on stderr).

Correlation rules (reporting).

Event taxonomy — persisted schema (event_version 1). The live __JAIPH_EVENT__ stream on stderr is unchanged except as noted in release notes; the tables below describe only what is written to run_summary.jsonl.

Field WORKFLOW_START WORKFLOW_END STEP_START STEP_END LOG LOGERR INBOX_ENQUEUE INBOX_DISPATCH_START INBOX_DISPATCH_COMPLETE
type required required required required required required required required required
ts required required required required required required required required required
run_id required required required required required required required required required
event_version required (1) required (1) required (1) required (1) required (1) required (1) required (1) required (1) required (1)
workflow required (name) required (name)
source required (basename or empty) required (basename or empty)
func, kind, name required required
status, elapsed_ms (step) null on start required numbers when ended
out_file, err_file required strings required strings
id, parent_id, seq, depth required required
params optional JSON array optional JSON array
dispatched, channel, sender optional (inbox dispatch) optional (inbox dispatch)
out_content, err_content optional on STEP_END
message, depth required required
inbox_seq, channel, sender required required required
payload_preview, payload_ref required
target required required
status, elapsed_ms (dispatch) required (exit code and ms)

Semantics and notes:

Together with step .out / .err files, a single run_summary.jsonl is enough to reconstruct the step tree (start/end pairs), log and logerr timelines, inbox enqueue → dispatch → completion flow, and workflow boundaries.

The jaiph report command exposes this data through a small local HTTP API and browser UI (run list, step tree, embedded previews, raw logs, aggregate view, active runs). See Reporting server.

Automated regression for this contract (including parallel inbox dispatch) lives in the repository E2E script e2e/tests/88_run_summary_event_contract.sh (uses python3 to parse and assert on the JSONL file).

Hooks

You can run custom commands at workflow/step lifecycle events via hooks. Config lives in ~/.jaiph/hooks.json (global) and <project>/.jaiph/hooks.json (project-local); project-local overrides global per event. See Hooks for schema, events, payload, and examples.

jaiph test

Run tests from native test files (*.test.jh / *.test.jph) that contain test "..." { ... } blocks. Test files can import workflows and use mock prompt (or mock prompt { ... }) to simulate agent responses without calling the real backend.

Usage:

With no arguments, or with a directory that contains no test files, the command exits with status 1 and prints an error.

You must pass a test file (e.g. say_hello.test.jh) or a directory. Passing a plain workflow file (e.g. say_hello.jh) is not supported; the test file imports the workflow and declares mocks. See Testing for test block syntax and expectContain / expectEqual.

Examples:

jaiph test
jaiph test ./e2e
jaiph test e2e/workflow_greeting.test.jh
jaiph test e2e/say_hello.test.jh

jaiph init

Initialize Jaiph files in a workspace directory.

jaiph init [workspace-path]

Creates:

jaiph use

Reinstall Jaiph globally with the selected channel/version.

jaiph use <version|nightly>

Behavior:

Examples:

jaiph use nightly
jaiph use 0.5.0

jaiph report

Serve a read-only reporting dashboard over run artifacts: run_summary.jsonl plus step .out / .err files under the runs root (default <workspace>/.jaiph/runs). No database; the server indexes and tails summary files the runtime already writes.

jaiph report [start|stop|status] [--host <addr>] [--port <n>] [--poll-ms <n>] [--runs-dir <path>] [--workspace <path>] [--pid-file <path>]

Commands:

Options:

Behavior (summary): Discovers runs under <YYYY-MM-DD>/<time>-<source>/run_summary.jsonl, keeps a cached directory scan with a minimum interval between full rescans, and tails each summary with a byte offset and inode/size tracking so appended lines update live state without rereading whole files. Truncation or file replacement triggers a full resync for that run. HTTP API and UI details: Reporting server.

File extensions

Imports resolve for both extensions: import "foo" as x finds foo.jh or foo.jph (.jh is preferred when both exist).

Environment variables

Runtime and config overrides (for jaiph run and workflow execution):

For JAIPH_DOCKER_*, defaults, image selection (including .jaiph/Dockerfile), mounts, and container behavior are covered in Sandboxing.

jaiph report:

Install and jaiph use:

jaiph init: