This page walks you through installing Jaiph, running your first workflow, and mapping the core language to deeper reference pages.
You will: install the CLI and stdlib, run a workflow (from the shell or as an executable .jh file), optionally scaffold .jaiph/ in a repository, then use the language overview below as an index into Grammar, CLI Reference, and the other guides.
If you are hacking on the compiler or CLI in this repository, read Contributing for build commands, tests, and review expectations.
Jaiph is a composable scripting language and runtime for defining and orchestrating AI agent workflows.
It combines declarative workflow structure with bash, then compiles to pure shell scripts. That keeps workflows portable and easy to understand while staying compatible with standard shell environments.
Core concepts:
run calls to other workflows and functions) that can change system state.ensure and in conditionals.prompt "..." sends text to a configured agent (e.g. Cursor or Claude CLI); workflows orchestrate when the agent runs..jh / .jph modules and call their rules, workflows, and functions by alias (e.g. ensure security.scan_passes, run bootstrap.nodejs). Use ensure only for rules and run for workflows and functions so every Jaiph call is keyword-led; a bare symbol name cannot start a workflow shell step, including when the line also contains $(...).x = ensure … / x = run … / x = prompt … (for ensure / run, the captured value is the callee’s explicit return; ordinary command stdout goes to step artifacts under .jaiph/runs). See Step output contract and Managed calls vs command substitution.[!WARNING] Jaiph is still in an early stage. Expect breaking changes.
main.jh:
#!/usr/bin/env jaiph
import "bootstrap_project.jh" as bootstrap
import "tools/security.jh" as security
# Validates local build prerequisites.
rule project_ready {
test -f "package.json"
test -n "$NODE_ENV"
}
# Verifies the project compiles successfully.
rule build_passes {
npm run build
}
# Orchestrates checks, prompt execution, and docs refresh.
# Arguments:
# $1: Feature requirements passed to the prompt.
workflow default {
if ! ensure project_ready; then
run bootstrap.nodejs
fi
prompt "
Build the application using best practices.
Follow requirements: $1
"
ensure build_passes
ensure security.scan_passes
run update_docs
}
# Refreshes documentation after a successful build.
workflow update_docs {
prompt "Update docs"
}
Transpiled output is standard bash. The generated script sources the runtime stdlib by reading JAIPH_STDLIB if set, otherwise defaulting to ~/.local/bin/jaiph_stdlib.sh (the path used by the install script). When you run a workflow via jaiph run, jaiph ./file.jh, or a #!/usr/bin/env jaiph shebang, the CLI sets JAIPH_STDLIB to the jaiph_stdlib.sh bundled next to that jaiph binary so you always match the compiler version. Advanced overrides are documented under Environment variables.
A runnable copy of this example lives in the Jaiph repository under test/fixtures/ (with stub modules bootstrap_project.jh and tools/security.jh).
curl -fsSL https://jaiph.org/install | bash
Verify installation:
jaiph --version
Switch installed version:
jaiph use nightly # tracks main branch
jaiph use 0.5.0 # installs tag v0.5.0
If that fails, check that ~/.local/bin is in your PATH (default install directory).
Installation places both the jaiph CLI and the global runtime stdlib (jaiph_stdlib.sh) in ~/.local/bin/.
./path/to/main.jh "feature request or task"
Arguments are passed exactly like bash scripts ($1, $2, "$@").
Entrypoint resolution: the entry file must define a workflow named default. Executable .jh files with #!/usr/bin/env jaiph run that workflow when invoked as ./file.jh (the jaiph binary must be on your PATH). The same applies to jaiph run path/to/file.jh and the shorthand jaiph path/to/file.jh when the path exists. The .jph extension is still supported but deprecated for new files; jaiph run prints a deprecation notice on a TTY when you pass a .jph path.
Other useful CLI commands:
jaiph build [--target <dir>] [path] # compile .jh/.jph files to bash without running
jaiph test [path] # run tests (see below)
jaiph report --workspace . # browse .jaiph/runs in a local dashboard
jaiph test: With no path, Jaiph discovers every *.test.jh / *.test.jph under the workspace root: walk up from the current working directory until a directory containing .jaiph or .git is found; if neither exists on that path, the root is the resolved cwd. Pass a directory to run all tests under it (workspace root is detected the same way, starting from that path). Pass a single *.test.jh / *.test.jph file to run one suite. See Testing.
For all CLI commands, flags, and environment variables, see CLI Reference. For the run history UI and HTTP API, see Reporting server.
jaiph init
This creates .jaiph/bootstrap.jh (executable) and writes .jaiph/jaiph-skill.md when the installer ships a skill file next to the jaiph binary; if that file is missing, sync is skipped and a note is printed.
Then run:
./.jaiph/bootstrap.jh
This asks an agent to detect project configuration and bootstrap recommended Jaiph workflows for feature implementation.
Tip: add .jaiph/ to your .gitignore.
Jaiph source files use .jh (recommended); .jph is still accepted. A file contains rules, workflows, functions, and optional config blocks. All primitives interoperate with standard bash. For the full grammar, validation rules, and transpilation details, see Grammar.
config { ... } — Optional block setting runtime options (agent backend, model, Docker sandbox, etc.). Allowed at the top level (module-wide) and inside individual workflows for per-workflow overrides (agent.* and run.* keys only). See Configuration.import "path" as alias — Import rules, workflows, and functions from another module. The path may include a .jh / .jph suffix or omit it; resolution prefers .jh when both exist. Verified at compile time.local name = value — Module-scoped variable, accessible as $name in all blocks within the module.rule name { ... } — Reusable check/action returning a shell exit code. Rules run in an isolated child shell; on Linux, a read-only mount namespace is used when unshare and passwordless sudo are available, otherwise the same child-shell fallback as on other platforms. Can call other rules via ensure. Optional export for cross-module access.workflow name { ... } — Orchestration entrypoint of ordered steps. Can change system state. Optional export for cross-module access.function name { ... } — Reusable writable shell function (shell-like body; no run/ensure/routes inside). From a workflow, call it with run name so logs and return values use the managed step contract. The () after the name is optional (function name() { ... } also works).ensure ref [args...] — Execute a rule; optional recover for bounded retry loops (default max retries 10, overridable with JAIPH_ENSURE_MAX_RETRIES). See Grammar.run ref [args...] — Execute another workflow or a top-level function. Not allowed inside rules.prompt "..." — Send text to the configured agent. Optional returns '{ field: type }' for validated JSON responses. See Grammar.name = <step> — Capture a value from a step: for ensure / run, only the callee’s explicit return (stdout from commands inside the callee goes to artifacts, not into name); for prompt, the final answer; for a plain shell command, full stdout (bash semantics). See Grammar and managed calls.log "message" / logerr "message" — Display a message in the progress tree (stdout / stderr).channel <- cmd / channel -> workflow — Send and route messages between workflows. See Inbox & Dispatch.cmd & / wait — Background commands and synchronise with wait inside shell steps for in-step parallelism. See Grammar.if [!] ensure ref; then ... [else ...] fi — Conditional based on rule result.if [!] run ref; then ... [else ...] fi — Conditional based on workflow or function exit code.if ! <shell_cmd>; then ... fi — Conditional based on a shell command exit code.Runtime behavior (progress tree, step output, run logs) is documented in CLI Reference. To browse past and in-progress runs in a browser, use Reporting server. For agent backend configuration, see Configuration. For Docker sandboxing (beta), see Sandboxing. For testing workflows with mocks and assertions, see Testing. For lifecycle hooks, see Hooks.