YARLI
What is this?
YARLI is a Rust project for executing plan-driven engineering workflows with durable state and explicit operator control. It treats runs, tasks, worktrees, merges, command execution, and policy decisions as state-machine entities persisted through an event log.
The primary workflow is yarli run: resolve prompt context, discover open tranches, dispatch execution tasks, and emit explainable run/task status. YARLI supports both local ephemeral development and durable Postgres-backed operation.
This project is for teams that want reproducible orchestration behavior, auditable transitions, and safe defaults around Git operations, policy checks, and runtime controls.
Features
- Config-first orchestration (
yarli.toml) with plan-driven tranche dispatch. - Durable event store and queue backends (Postgres) with in-memory mode for local testing.
- Explicit operator controls (
pause,resume,cancel,drain) and explainability commands. - Policy and gate evaluation over task/run state.
- Parallel workspace execution with scoped merge and recovery artifacts.
- Startup salvage of abandoned git-worktree run roots before parallel slot allocation.
- Optional memory provider adapters via
[memory.providers.<name>]. - REST API crate (
yarli-api) with health, status, control, webhook, and websocket event routes.
Installation
Build from source
Cargo install (local path)
Shared commithooks
This repo tracks project-local hooks in .githooks/. Building yarli
refreshes the shared dispatchers and hook library into .git/hooks/ and
.git/lib/ when COMMITHOOKS_DIR or $HOME/Documents/commithooks is
available.
Install script
Docker
Quick Start
# 1) Generate config template
# 2) For local ephemeral writes, set in yarli.toml:
# [core]
# backend = "in-memory"
# allow_in_memory_writes = true
# 3) Ensure PROMPT.md exists, then run
For durable mode, configure:
[]
= "postgres"
[]
= "postgres://postgres:postgres@localhost:5432/yarli"
Then apply migrations:
in-memory mode is ephemeral: once the process exits, captured task output and
audit history do not survive. In durable Postgres mode, YARLI persists run/task
state plus captured command output so operators and agents can inspect failures
later with yarli run explain-exit, yarli task explain, yarli task output,
and yarli audit.
Core Concepts
Prompt Resolution
yarli run resolves the prompt file in this order:
yarli run --prompt-file <path>[run].prompt_fileinyarli.toml- Fallback lookup for
PROMPT.mdby walking upward from your current directory
Relative prompt paths are resolved from repo root (.git ancestor) when available, otherwise from the config file directory. @include <path> directives are expanded (confined under the directory containing the resolved prompt file).
Default execution discovers incomplete tranches in IMPLEMENTATION_PLAN.md, dispatches each tranche as a task, then appends a verification task. If no run-spec configuration exists and no incomplete tranches are found, it dispatches the full prompt text as one task.
Minimum PROMPT.md structure:
@include IMPLEMENTATION_PLAN.md
Tranche Metadata
Optional metadata on IMPLEMENTATION_PLAN.md tranche lines:
tranche_group=<name>— group adjacent entries for dispatch togetherallowed_paths=path/a,path/b— scope constraints (requires[run].enforce_plan_tranche_allowed_paths = true)verify="cmd"— post-tranche verification command hintdone_when="criteria"— explicit completion contractmax_tokens=N— per-tranche token-budget hint
Control Terminology
- Policy gates: code-defined checks evaluated by YARLI (
yarli gate ...). - Verification command chain: plan/config/script-defined command execution (tranche + verification tasks).
- Observer mode: monitoring/reporting only; observer events never gate or mutate active run execution.
- Operator controls: explicit control-plane actions via
yarli run pause|resume|cancel|drain.
Output Modes
Global flags:
--stream: force stream output (inline, no fullscreen UI)--tui: force fullscreen dashboard UI
If --stream is requested but the current environment is not a TTY, YARLI falls back to headless mode.
CLI Reference
yarli init
Creates a documented yarli.toml template to bootstrap a workspace. This is where you initialize durability (Postgres vs ephemeral), execution backend (native vs Overwatch), budgets, policy mode, and UI mode.
yarli run
Start, monitor, and explain orchestration runs. yarli run (no subcommand) is the primary config-first, plan-driven workflow.
- Parallel mode defaults to enabled (
[features].parallel = true); requires[execution].worktree_root. - In parallel mode, YARLI prepares one workspace per task under
execution.worktree_root. - Before creating new git-worktree task slots, YARLI sweeps
execution.worktree_rootfor abandonedrun-*roots, salvages dirty worktrees onto durable branches, and reclaims empty stale roots. - On
RunCompleted, YARLI scopes each task merge to paths that actually differ, then applies a patch withgit apply --3way. - Merge conflict resolution is controlled by
[run].merge_conflict_resolution:fail(default),manual,auto-repair. - Auto-advance policy:
[run] auto_advance_policy = "improving-only" | "stable-ok" | "always"(default:stable-ok). - Task health trends (
[run.task_health.improving|stable|deteriorating]) can triggercontinue,checkpoint-now,force-pivot, orstop-and-summarize. [run].soft_token_cap_ratiotriggers checkpoint-now when total token usage reachesratio * max_run_total_tokens(default:0.9).- Use
yarli run --allow-recursive-run ...when a task command intentionally needs to invoke nestedyarli runexecution for that invocation.
# Run the workspace's default prompt-defined loop.
# Override the prompt file for this invocation.
# Start an ad-hoc run with explicit commands (one task per --cmd).
# Start using a named pace from yarli.toml.
# Query status (run-id can be a full UUID or unique prefix from `yarli run list`).
# Explain why the run exited (or why it is not done).
# List all runs.
# Operator controls.
# Continue from the latest persisted continuation payload.
# Legacy pace-based execution.
Feature-gated sw4rm agent mode:
YARLI_LOG=debug
yarli run sw4rm requires a build with --features sw4rm and reads its runtime configuration from [sw4rm] in yarli.toml.
Plan guard (recommended for tranche/card workflows):
[]
= "CARD-R8-01"
= "implement" # "implement" (default) or "verify-only"
yarli task
Inspect tasks and clear blockers.
Use yarli task output <task-id> to retrieve the raw stdout/stderr captured for
that task's command execution. This retrieval path depends on durable persisted
output events, so it is most useful in Postgres mode.
yarli gate
Inspect configured gates and manually re-run gate evaluation.
yarli worktree
Inspect and recover git worktree state for a run.
# action values: abort | resume | manual-block
yarli merge
Request, approve, reject, and inspect merge intents.
# strategy values: merge-no-ff | rebase-then-ff | squash-merge
yarli audit
Tail and query the JSONL audit log emitted by policy decisions, governance accounting, and command execution events.
Use audit history alongside yarli task output: task output shows what the
command printed, while audit entries show the surrounding policy, gate, and
operator-decision trail. By default yarli audit tail reads the local
.yarl/audit.jsonl file.
Quick diagnosis workflow for a failed durable run:
# 1) Get the summary of why the run exited or stopped.
# 2) Inspect the failing task's raw captured stdout/stderr.
# 3) Query the event and policy trail around that task.
yarli evidence
Validate structured tranche evidence files in .yarli/evidence/. Checks TOML frontmatter, filename-to-tranche matching, required markdown headings, and metadata consistency.
yarli plan
Manage the structured tranches file (.yarli/tranches.toml) used by plan-driven dispatch.
yarli plan tranche add also supports tranche metadata fields used by plan-driven dispatch: --group, --allowed-paths, --verify, --done-when, and --max-tokens.
yarli debug
Inspect live scheduler internals and queue/runtime telemetry.
yarli migrate
Manage Postgres migration lifecycle for durable mode.
yarli serve
Start the HTTP API server for run, task, and audit introspection.
yarli info
Print version and detected terminal capabilities.
AI Agent Integration
YARLI integrates with agent CLIs through [cli] configuration (for example codex, claude, gemini, kiro-cli, or custom command wiring).
[]
= "codex"
= "arg"
= "codex"
= ["exec"]
Kiro CLI example (kiro-cli is Claude under the hood):
[]
= "kiro-cli"
= "arg"
= "kiro-cli"
= ["chat", "--no-interactive", "--trust-all-tools"]
YARLI is not currently an MCP server. Agent integration is command-dispatch based.
gRPC API
YARLI does not currently expose a native gRPC API. I did not find any .proto
files in this repo, and the supported network API surface today is the HTTP
server from crates/yarli-api.
REST API
Routes from crates/yarli-api/src/server.rs:
| Method | Path | Description |
|---|---|---|
| GET | /health |
Health check |
| GET | /metrics |
Prometheus metrics |
| GET | /v1/events/ws |
WebSocket event stream |
| POST | /v1/webhooks |
Register webhook |
| POST | /v1/runs |
Create run |
| GET | /v1/runs |
List runs |
| GET | /v1/runs/:run_id/status |
Run status |
| POST | /v1/runs/:run_id/pause |
Pause run |
| POST | /v1/runs/:run_id/resume |
Resume run |
| POST | /v1/runs/:run_id/cancel |
Cancel run |
| GET | /v1/tasks |
List tasks |
| GET | /v1/tasks/:task_id |
Task status |
| POST | /v1/tasks/:task_id/annotate |
Annotate task |
| POST | /v1/tasks/:task_id/unblock |
Unblock task |
| POST | /v1/tasks/:task_id/retry |
Retry task |
| GET | /v1/audit |
Audit log |
| GET | /v1/metrics/reporting |
Reporting metrics |
Debug-only routes (feature-gated: debug-api):
| Method | Path | Description |
|---|---|---|
| POST | /v1/tasks/:task_id/priority |
Override priority |
| GET | /debug/queue-depth |
Queue depth |
| GET | /debug/active-leases |
Active leases |
| GET | /debug/resource-usage/:run_id |
Resource usage |
Authentication is enabled when YARLI_API_KEYS is set. Public endpoints (/health, /metrics) bypass auth.
# Public endpoint
# Non-public endpoint when auth is disabled
# Non-public endpoint when auth is enabled
Configuration
yarli.toml
Main config file, generated via yarli init. Example in yarli.example.toml. Run yarli init --help for a full annotated list of every config key and its default.
Key sections:
| Section | Purpose |
|---|---|
[core] |
Backend (in-memory/postgres), safe mode, worker identity |
[postgres] |
Database URL, URL file (Kubernetes secret pattern) |
[cli] |
LLM CLI backend (codex/claude/gemini/kiro-cli/custom), prompt mode, command, args |
[features] |
Parallel execution, git worktree mode |
[queue] |
Claim batch size, lease TTL, per-class caps |
[execution] |
Runner (native/overwatch), working dir, worktree root, timeouts |
[run] |
Prompt file, auto-advance policy, task health, merge conflict resolution, plan guard |
[budgets] |
Per-task and per-run resource limits (RSS, CPU, IO, tokens) |
[git] |
Default target branch, destructive operation deny |
[policy] |
Policy enforcement, audit toggle |
[memory] |
Provider selection and adapter config |
[observability] |
Audit file path, log level |
[ui] |
Display mode, verbose output, cancellation diagnostics |
[sw4rm] |
Agent name, capabilities, registry/router/scheduler URLs (requires --features sw4rm) |
Memory Providers
YARLI can store and query memories (short, reusable incident summaries) via provider adapters.
[]
= "default"
[]
= "cli"
= true
= "memory-backend"
= 8
= true
= true
Bootstrap per repo: memory-backend init -y
Environment Variables
| Variable | Purpose |
|---|---|
DATABASE_URL |
Postgres DSN fallback |
YARLI_LOG |
Log level (populates RUST_LOG when unset) |
YARLI_ALLOW_RECURSIVE_RUN |
Recursive-run override |
YARLI_API_KEYS |
Comma-separated API auth keys |
YARLI_API_RATE_LIMIT_PER_MINUTE |
API rate limit (default: 120) |
OTEL_EXPORTER_OTLP_ENDPOINT |
OTLP tracing exporter endpoint |
YARLI_TEST_DATABASE_URL |
Postgres URL for integration tests |
YARLI_REQUIRE_POSTGRES_TESTS |
Enable Postgres integration tests |
Architecture
+---------------------+
| yarli CLI (run/*) |
+----------+----------+
|
v
+---------------------+
| Scheduler + Queue |
| (yarli-queue) |
+----------+----------+
|
+------------------+------------------+
v v
+---------------+ +------------------+
| Command Runner| | Policy + Gates |
| (yarli-exec) | | (yarli-policy, |
+-------+-------+ | yarli-gates) |
| +--------+---------+
v |
+---------------+ |
| Git/Worktree |<----------------------------+
| (yarli-git) |
+-------+-------+
|
v
+---------------+
| Event Store |
| (in-memory or |
| Postgres) |
+-------+-------+
|
v
+---------------+
| API / Observe |
| (yarli-api) |
+---------------+
Key implementation modules and integration tests still live under crates/yarli-*, but Cargo now builds through the single root package yarli.
Security
- Safe mode and policy enforcement are configurable (
observe,restricted,execute,breakglass). - Destructive Git operations are denied by default (
git.destructive_default_deny = true). - API authentication is enabled when
YARLI_API_KEYSis set (supportsAuthorization: Bearer,x-api-key,api-keyheaders). - API key rate limiting uses
YARLI_API_RATE_LIMIT_PER_MINUTE(default 120/min). - Durable mode is recommended for write commands; in-memory mode blocks writes unless explicitly allowed.
Runner Hardening and sw4rm Notes
yarli runnow wires per-task scheduler budgets into command execution asResourceLimitsand applies Linuxsetrlimit(2)caps for memory, CPU, open files, and process count before spawning workers.- Prometheus now exposes
yarli_enforcement_outcomes_total{mechanism,outcome,reason}for runner hardening paths, includingrlimit,cgroup,pidfd, andpid_terminationoutcomes plusrlimits_only_*fallback reasons. sw4rmagent runtime transport uses a correlation-aware gRPC sender/receiver (GrpcRouterSender) andCT_IMPLEMENTATION_RESPONSEnow maps back to pending local correlation state.yarli run sw4rmfails fast when router/report clients or runtime registration cannot connect; it does not silently degrade into a partial local mode.- Invalid sw4rm verification run-spec configuration falls back to minimal verification defaults, while correlation drops from shutdown/stream cancellation surface as
Cancelledand request expiry surfaces asLlmTimeout. - Process lifecycle control prefers pidfd (
pidfd_open(2)/pidfd_send_signal(2)) when available, with automatic fallback for older kernels. - A cgroup v2 sandbox is enabled when writable; when unavailable or unwritable, execution continues in fallback mode using rlimits only.
- Containerized cgroup enforcement requires a writable delegated cgroup subtree for the YARLI process. Read-only or non-delegated hierarchies are supported, but they stay in rlimits-only fallback mode.
/proc/self/cgroupis used in integration probes to confirm sandbox attachment under writable cgroup v2 runs.- Build
yarliwith--features sw4rmwhen running the sw4rm runtime (yarli run sw4rm), plus compatible gRPC endpoints.
Examples
# Bootstrap config, then run the default plan-driven loop.
# Start an ad-hoc run with explicit commands.
# Inspect or control a live run.
# Recover interrupted worktree state.
Playbooks
Runtime Guard Response
When guard-related telemetry indicates a stop or pivot condition:
yarli run status <run-id>— inspect budget and deterioration signals.yarli run explain-exit <run-id>— inspect guard breach reasons and trend summary.yarli task explain <task-id>— inspect task-level budget, usage, and failure provenance.yarli run pause|resume|cancel|drain <run-id>— hold, stop, or finish-current-then-exit while adjusting scope.yarli run continue— continue only after guard intent has been reviewed.
Merge Conflict Recovery
When run.status or run.explain-exit show unresolved merge state:
- Inspect:
yarli run status <run-id>andyarli audit tail --category merge.apply.conflict. - Open
PARALLEL_MERGE_RECOVERY.txtin the preserved workspace root. - Follow the printed recovery steps (inspect, review patch, retry apply, resolve markers).
- Pick action based on
[run].merge_conflict_resolutionpolicy (fail,manual,auto-repair). yarli run continueafter remediation.
Troubleshooting
"write commands blocked" in in-memory mode
Either configure durable mode (core.backend = "postgres" + DATABASE_URL or [postgres].database_url) and apply migrations, or explicitly opt into ephemeral writes:
[]
= "in-memory"
= true
Secret rotation
- Mount credentials as files in a dedicated secret volume (e.g.
/run/secrets/...). - Set
postgres.database_url_fileto that mounted path inyarli.toml. - Update the secret, then restart YARLI (
kubectl rollout restart ...).
Stream requested but "headless mode"
If you run yarli run --stream in a non-interactive environment (no TTY), YARLI falls back to headless mode and still executes the run.
License
Dual licensed under MIT OR Apache-2.0.