Jaiph Bootstrap Skill (for Agents)

Why this page exists. Agentic work needs the same things human teams need: a clear sequence of steps, explicit checks, and a record of what ran. Jaiph is a small workflow language for that: workflows sequence orchestration, rules express checks, script holds real shell, and the runtime logs steps and writes run artifacts. The payoff is behavior that is easier to repeat, verify, and debug than ad-hoc shell snippets alone.

Overview

This page is an agent skill: it tells an AI assistant how to author Jaiph workflows (.jh files) and what a sensible .jaiph/ layout looks like. It is not a full language specification — use Getting started as the documentation map, Grammar for syntax and validation details, Configuration for config keys, Inbox & Dispatch for channels, and Sandboxing for rule design vs optional Docker isolation.

Jaiph is a small language for agentic workflows: orchestration (rules, prompts, managed calls) and shell in script definitions. The Node workflow runtime (NodeWorkflowRuntime) interprets the parsed AST in process — there is no separate transpiled workflow shell on the execution path (Architecture). Before jaiph run or jaiph test, buildScripts() takes a single entry .jh path (the workflow file, or the *.test.jh file for tests), runs compile-time validation (validateReferences inside emitScriptsForModule), and writes extracted script files under scripts/ for that module and every file reachable from it via transitive import — not the whole workspace unless those files are imported. jaiph compile runs the same validateReferences checks by parsing each module in the computed closure without buildScripts, script emission, or the runner (Architecture). The runner’s buildRuntimeGraph() then loads the graph with parse-only imports (it does not re-run validateReferences).

Contracts (CLI vs runtime): Live: __JAIPH_EVENT__ JSON lines on stderr only (CLI progress and hooks — hooks are CLI-only, driven by that stream). Durable: .jaiph/runs/... and run_summary.jsonl. Channels are enforced at compile time and executed in the runtime (in-memory queue + inbox files under the run dir); they are not hooks.

The JS kernel (src/runtime/kernel/) handles prompt execution, managed script subprocesses, inbox queues and dispatch, and event/summary emission. Rule bodies run in-process; user script bodies run as separate OS processes (bash by default, polyglot via fence lang tags like node , python3 or a leading #! shebang in the body).

Test lane: jaiph test runs *.test.jh in-process (node-test-runner.ts): for each file it calls buildScripts(testFile, …) (same helper as jaiph run, with the test file as the entry so its import closure is validated and scripts are emitted), then buildRuntimeGraph(testFile) once per file, mocks, and assertions — same NodeWorkflowRuntime as jaiph run. The runtime enables suppressLiveEvents for those workflow runs so __JAIPH_EVENT__ lines are not written to stderr (keeping node --test output readable); run_summary.jsonl under the run directory is still updated where the emitter records workflow traffic (Architecture).

After jaiph init, a repository gets .jaiph/bootstrap.jh (a triple-quoted prompt that tells the agent to read .jaiph/SKILL.md) and a copy of this file. The bootstrap prompt asks the agent to scaffold workflows under .jaiph/ and to end with a clear WHAT CHANGED + WHY summary. The expected outcome is a minimal workflow set for safe feature work: preflight checks, an implementation workflow, verification, and a workflow default entrypoint that wires them together (with an optional human-or-agent “review” step when you use a task queue). Docker-backed runs use the official ghcr.io/jaiphlang/jaiph-runtime image by default; see Sandboxing to override with runtime.docker_image or JAIPH_DOCKER_IMAGE.

Concepts:

Step semantics (ensure, run, prompt, catch, recover, match, if, for, log, fail, return, send, run async) are detailed in the Steps section below.

Audience: Agents that produce or edit .jh files.


Safe delivery loop (any repository)

Use this loop whenever you add or change Jaiph workflows so failures surface before work is handed back. When the repo defines a workflow default entrypoint (often .jaiph/main.jh) that wires preflight → implementation → verification, use jaiph run on that file for end-to-end delivery after the narrower checks below pass.

  1. Preflight — Run the project’s readiness checks if they exist (often jaiph run .jaiph/readiness.jh or a named preflight workflow). When the repo ships native tests (*.test.jh), run jaiph test before large edits when practical.
  2. Implement — Edit .jh modules using only constructs described in Grammar; keep managed-call rules (ensure for rules, run for workflows and scripts); put multi-line or reusable bash in script definitions (rules never allow raw shell lines — use run to a script; workflows may use optional inline shell where the grammar allows, but prefer script + run for anything non-trivial — see Grammar — Language concepts).
  3. Format — Run jaiph format <file.jh ...> on all authored or modified .jh files before committing. This normalizes whitespace, indentation, and top-level ordering (imports, config, and channels hoisted to the top; everything else kept in source order). Use jaiph format --check <file.jh ...> to verify formatting without writing (non-zero exit on drift — useful in CI).
  4. Compile check — Run jaiph compile <file-or-dir> on the paths you touched (or jaiph compile --json … in automation). Same validateReferences checks as before a run, without executing workflows or writing scripts/ (Architecture). With a directory argument, only non-test *.jh files are used as entrypoints (*.test.jh is skipped); pass a test file path explicitly to validate it.
  5. Verify — Run jaiph test (whole workspace or a focused path) and any verification workflow the repo defines (commonly jaiph run .jaiph/verification.jh). Fix failures you introduce.
  6. Inspect (optional) — Browse .jaiph/runs directly when you need raw step logs or run_summary.jsonl instead of only the terminal tree.

CLI commands:

Command Purpose
jaiph run [--target <dir>] [--raw] <file.jh> [--] [args...] Execute workflow default in the given file (--raw: no banner/tree/hooks; used for embedding and Docker inner runs)
jaiph test [path] Run *.test.jh test files (workspace, directory, or single file)
jaiph format [--check] [--indent <n>] <file.jh ...> Reformat .jh files (or verify formatting without writing)
jaiph compile [--json] [--workspace <dir>] <.jh files or dirs…> Parse and validateReferences only (no script emission, no run)
jaiph init [workspace] Scaffold .jaiph/ with bootstrap workflow and skill file
jaiph install [--force] [<url[@version]> …] Clone libraries into .jaiph/libs/ or restore from .jaiph/libs.lock
jaiph use <version\|nightly> Reinstall Jaiph at a specific version or nightly

File shorthand: jaiph ./file.jh auto-routes — *.test.jh files run as tests, other *.jh files run as workflows.

Full flags and environment variables: CLI Reference.


When to Use This Guide

Use this guide when generating or updating .jaiph/*.jh workflows for a repository after jaiph init.

Source of Truth

When this skill conflicts with the compiler or runtime, follow the implementation. For language rules and validation codes, Grammar is the detailed reference. Published docs: jaiph.org.

jaiph init writes this skill to .jaiph/SKILL.md when the installer resolves a skill file: if JAIPH_SKILL_PATH is set, it is used only when that path exists on disk; otherwise the CLI searches install-relative locations and docs/jaiph-skill.md from the current working directory (CLI Reference). If no file is found, init skips SKILL.md — set JAIPH_SKILL_PATH to an existing markdown file (for example docs/jaiph-skill.md in a checkout) and run jaiph init again.

Ignore any outdated Markdown that contradicts the above.

What to Produce

A minimal workflow set under .jaiph/ that matches the delivery loop above:

  1. Sandbox baseline (optional) — If the repo uses Docker sandboxing, confirm runtime.docker_image / JAIPH_DOCKER_IMAGE match the tooling the team needs; the default is ghcr.io/jaiphlang/jaiph-runtime (see Sandboxing).
  2. Preflight — Rules and ensure for repo state and required tools (e.g. clean git, required binaries). Expose a small workflow (e.g. workflow default in readiness.jh) that runs these checks.
  3. Review (optional) — A workflow that reviews queued tasks before development starts (any filename, e.g. ba_review.jh). An agent prompt evaluates the next task for clarity, consistency, conflicts, and feasibility, then either marks it as ready or exits with questions. The implementation workflow gates on this marker so unreviewed tasks cannot proceed. This repository’s .jaiph/architect_review.jh is one concrete example; it uses QUEUE.md as the task queue.
  4. Implementation — A workflow that drives coding changes (typically via prompt), e.g. workflow implement in main.jh. When using a task queue, the implementation workflow should check that the first task is marked as ready (e.g. via a <!-- dev-ready --> marker) before proceeding.
  5. Verification — Rules and a workflow default for lint/test/build (e.g. verification.jh). Complement this with repo-native *.test.jh suites run by jaiph test where appropriate.
  6. Entrypoint — A single workflow default (e.g. in .jaiph/main.jh) that runs: preflight → (optional) review → implementation → verification. This is what jaiph run .jaiph/main.jh "..." executes.

Prefer composable modules over one large file.

Language Rules You Must Respect

Quick reference examples:

# catch — one-shot failure handling
ensure ci_passes() catch (failure) {
  prompt "CI failed — fix the code."
  run deploy(env)
}

# recover — repair-and-retry loop (retries until success or limit)
run deploy(env) recover(err) {
  log "Deploy failed: ${err}"
  run auto_repair(env)
}

# match — value branching (statement and expression forms)
const label = match status {
  "ok" => "success"
  /err/ => "something went wrong"
  _ => "unknown"
}

# if — conditional guard (no else; use match for exhaustive branching)
if env == "" {
  fail "env was not provided"
}
if mode =~ /^debug/ {
  log "Debug mode enabled"
}

# for — iterate over lines of a string variable
const paths = """
docs/a.md
docs/b.md
"""
for path in paths {
  log "${path}"
}

# typed prompt — structured JSON with dot-notation field access
const result = prompt "Analyze this code" returns "{ type: string, risk: string }"
log "Type: ${result.type}, Risk: ${result.risk}"

# const capture — from run, ensure, prompt
const tag = run get_version()
const ok = ensure validate(tag)
const answer = prompt "Summarize the changes"

# inline scripts — one-off commands without a named script definition
run `echo $1`("hello")
const ts = run `date +%s`()

Conventions:

Authoring Heuristics

Writing Tests

Test files use the *.test.jh suffix and contain test "name" { ... } blocks. They import the workflows under test and use mocks to replace live agent/script behavior. The test runner uses the same NodeWorkflowRuntime as jaiph run. See Testing for the full reference.

Running: jaiph test (all *.test.jh in workspace), jaiph test <dir> (recursive), or jaiph test <file.test.jh> (single file).

Available mocks:

Assertions:

Minimal example:

import "main.jh" as app

test "happy path produces greeting" {
  mock prompt "hello from mock"
  const out = run app.default("task")
  expect_contain out "hello from mock"
}

test "handles failure gracefully" {
  mock prompt "error"
  const out = run app.default("bad input") allow_failure
  expect_contain out "error"
}

allow_failure on a run step (with or without const … =) prevents a non-zero workflow exit from failing the test — useful for testing error paths. For mock script, put shell lines on lines after the opening {, then close with } on its own line (see Testing).

Suggested Starter Layout

Optional: .jaiph/implementation.jh if you prefer the implementation workflow in a separate module; otherwise keep it in main.jh.

Final Output Requirement

After scaffolding workflows, print the exact commands the developer should run. The primary command runs the default entrypoint (typically preflight, then implementation, then verification — plus any optional review step you added). Point users to the canonical skill URL for agents: https://raw.githubusercontent.com/jaiphlang/jaiph/refs/heads/main/docs/jaiph-skill.md.

Include a compile check and, when the repository has native tests (*.test.jh), jaiph test (see Testing); skip jaiph test if there are no test files, since discovery mode exits with an error when nothing matches.

jaiph format .jaiph/*.jh
jaiph compile .jaiph
# Omit the next line when the repo has no *.test.jh files (workspace discovery exits 1 with "no *.test.jh files found").
jaiph test
jaiph run .jaiph/main.jh "implement feature X"
# Or run verification only:
jaiph run .jaiph/verification.jh

Arguments after the file path are passed to workflow default as named parameters (when declared) and as $1, $2 in script bodies.

Minimal Sample (Agent Reference)

Use this as a shape to adapt. Paths and prompts should match the target repository. All three files live under .jaiph/. Imports in main.jh are relative to that file (e.g. "readiness.jh" resolves to .jaiph/readiness.jh). When you run jaiph run .jaiph/main.jh "implement feature X", the default workflow receives "implement feature X" as ${task} (named parameter). Note that run does not forward args implicitly, so the default workflow passes task as a bare identifier to run implement(task) so the implement workflow’s prompt can use ${task}.

File: .jaiph/readiness.jh

script git_is_clean = `test -z "$(git status --porcelain)"`

rule git_clean() {
  run git_is_clean() catch (err) {
    fail "git working tree is not clean"
  }
}

script require_git_node_npm = ```
command -v git
command -v node
command -v npm

rule required_tools() { run require_git_node_npm() }

workflow default() { ensure required_tools() ensure git_clean() }


**File: .jaiph/verification.jh**

```jaiph
script npm_test_ci = `npm test`

rule unit_tests_pass() {
  run npm_test_ci()
}

script run_build = `npm run build`

rule build_passes() {
  run run_build()
}

workflow default() {
  ensure unit_tests_pass()
  ensure build_passes()
}

File: .jaiph/main.jh

import "readiness.jh" as readiness
import "verification.jh" as verification

workflow implement(task) {
  prompt """
Implement the requested feature or fix with minimal, reviewable changes.
Keep edits consistent with existing architecture and style.
Add or update tests for behavior changes.

User asks for: ${task}
"""
}

workflow default(task) {
  run readiness.default()
  run implement(task)
  run verification.default()
}