jevia 0.1.2

Outcome-aware model routing CLI
jevia-0.1.2 is not a library.

Jevia

Jevia is an outcome-aware model router for coding agents. It asks Jev for a typed routing decision, applies a deterministic safety policy, and records the eventual result so later decisions can use evidence from earlier runs.

Jevia is experimental. The current milestones establish the CLI, routing contract, local outcome store, Jev integration, and generic harness execution. The managed control plane remains separate.

Why Jevia

Most model routers classify a task and immediately forget what happened. Jevia closes that loop:

  1. describe stable capability tiers rather than hard-coding model names;
  2. ask Jev which tier should handle the current task;
  3. fall back to a configured safe tier when confidence is low;
  4. record the routing decision in the configured history store;
  5. attach success or failure after the task finishes;
  6. include recent outcomes as evidence in future routing decisions.

The application owns the policy. Jev supplies a structured decision signal.

Quick start

Use the copyable /install.sh command on the Jevia landing page. It downloads a checksum-verified binary for macOS or Linux on Intel or ARM; Rust and Cargo are not required.

curl -fsSL https://jevia.vercel.app/install.sh | sh
jevia --version
jevia init
export TYPESAFE_API_KEY="your-key"
jevia check
jevia route "investigate an intermittent distributed-lock failure"

jevia check makes one live Jev request and requires a valid API key. Use jevia doctor for configuration/storage checks without a Jev API request. PostgreSQL storage checks do connect to the configured database.

To install the exact crates.io release with Rust 1.92 or newer:

cargo install jevia --version 0.1.2 --locked

To try unreleased development changes instead:

cargo install --git https://github.com/assistant-ui/jevia --locked jevia

Record the real result after the task completes:

jevia feedback <run-id> success
jevia runs

Machine-readable output is available for integrations:

jevia route --json "fix a typo in the README"
jevia runs --json

Commands

Command Purpose
jevia init Create .jevia/config.toml and local store rules.
jevia harness setup <name> Preview an explicit harness template; back up and save only with --apply.
jevia harness check <name> [--json] Inspect configuration and local executable candidates without launching programs or calling APIs.
jevia route <task> Ask Jev for a tier and record the decision.
jevia run <harness> <task> Route, launch a configured harness, and record its exit outcome.
jevia runs Inspect recent records in the configured backend.
jevia stats [--limit <records>] [--json] Summarize recent routing decisions, verified outcomes, manual feedback, and cache hits.
jevia feedback <id> <outcome> Mark a run as success, failure, or unknown.
jevia doctor Validate configuration, credentials, and configured storage.
jevia storage setup <sqlite|postgres> Preview database setup; explicitly apply after validation, backup, and optional JSONL import.
jevia storage init Explicitly initialize an opt-in database schema and project.
jevia storage check Check storage without needing a Jev API key.
jevia storage check --deep Inspect all history records and SQL routing/order metadata without a write probe or repair.
jevia storage import-jsonl [--from <file>] [--apply] Preview/import local history into a database without changing the source.
jevia storage export --output <file> Export history to a new JSONL snapshot; never overwrite a file.
jevia check Validate configured storage and complete a live Jev routing round trip without storing a run.
jevia cache status Inspect routing-cache settings and entry counts.
jevia cache clear Remove cached decisions without touching run history.

Run jevia <command> --help for command-specific options.

Routing insights

jevia stats
jevia stats --limit 500
jevia stats --json

stats reads the configured JSONL, SQLite, or PostgreSQL history without calling Jev, launching a harness, changing outcomes, or reading the decision-cache file. It needs no Jev API key; PostgreSQL still requires its configured database connection. Initialize an opted-in database with jevia storage init first. This command requires v0.1.2 or newer.

The default window is the latest 1,000 records in append order, not a date range or an all-time total. --limit accepts 1–100,000. The report says when older records were excluded; archived records are not included. SQL reads are bounded and project-scoped. JSONL still scans and validates the full file under its shared history lock, but retains only the requested tail in memory.

Totals and per-tier groups use the selected tier recorded at routing time, including tiers since removed from configuration. Tiers are not concrete model identities: changing a harness's model mapping does not split historical groups. Each record counts once, using its current outcome and provenance:

  • Verified success rate: verifier-backed successes divided by verifier-backed successes plus failures. Manual feedback, process-exit-only results, active runs, unknown outcomes, and legacy outcomes without provenance are excluded. A configured verifier's result is not a guarantee of task correctness.
  • Manual feedback: separate success/failure counts. Correcting a verified outcome with manual feedback moves that record to the manual group; prior feedback events and the old verifier result are not counted again.
  • Learning evidence: known, non-active verifier-backed or manual outcomes, using the same eligibility rule as routing. This is the eligible count in the stats window, not necessarily the smaller evidence window sent to Jev.
  • Cache hits: recorded cached decisions divided by all records in the window, not current cache occupancy or a count of API calls. Bypassed/disabled-cache decisions still count in the denominator. Legacy records without a decision source use the existing live default.
  • Other outcomes: process-exit-only and unattributed known outcomes, plus active and unknown counts. Active takes precedence over unknown, so the outcome groups partition the records without double-counting.

Rates with no eligible observations display n/a, not 0%. The JSON report uses schema_version: 1, storage, window (limit, order, has_older_records), totals, and a tier-keyed tiers map. Rates are fractions from 0 to 1, or null when their denominator is zero. verified, manual, process_exit, and unattributed each contain successes and failures; active and unknown are separate counts. Output excludes task text, run IDs, feedback notes, execution commands, and connection URLs; historical tier labels are included.

These are descriptive, potentially small or biased samples—not a model ranking, a controlled benchmark, or proof that adaptive routing improves results. No cost savings are estimated because token/cost telemetry is not recorded.

Harness adapters

Preview-first setup

jevia init leaves harness selection to you. Configure your installed agent with an explicit argument template and one model mapping for every configured tier:

jevia harness setup agent --command my-agent \
  --arg=run --arg=--model --arg='{model}' --arg='{task}' \
  --model fast=provider/small \
  --model balanced=provider/standard \
  --model strong=provider/frontier \
  --verify-command cargo --verify-arg=test

This is a generic example, not a provider preset: substitute your agent's actual executable, argument syntax, and accessible model IDs. Repeat the same command with --apply after reviewing its TOML preview. Setup never launches either program, calls Jev, opens storage, or checks provider credentials/model access. It works offline, including when a configured database is unavailable. There is no interactive prompt or automatic agent installation. Quote placeholders as shown and use --arg=--flag / --verify-arg=--flag for leading-hyphen arguments.

  • Preview changes no files. Apply shares a configuration lock with database setup, saves a private exact-byte backup in ignored .jevia/config-backups/, then atomically replaces the config after checking for concurrent edits. It preserves unrelated settings, harnesses, and comments, and rejects symlink configs. Stop concurrent manual config editing; the lock only coordinates Jevia setup commands.
  • Changing an existing harness also requires --replace. Reapplying identical settings does not rewrite the config or make another backup (apply may create the config lock sidecar). The selected harness entry is rewritten when changed.
  • Omitted verifier options preserve an existing verifier. Use --no-verification to explicitly remove it; supplying --verify-command replaces its whole command and argument list. Without verification, process success alone is not eligible learning evidence. Missing/duplicate/unknown tier mappings and unsupported template placeholders are rejected before config replacement.
  • Commands, arguments, and model IDs appear in previews and committed config. Never put credentials in these flags or templates; let the agent inherit its credentials from the environment. Protect retained config backups, especially with appropriate directory ACLs on Windows. Nothing is shell-expanded by Jevia.

Local preflight

jevia harness check agent
jevia harness check agent --json

Preflight validates the project config and selected adapter, renders its templates for every configured tier, rejects NUL arguments, and checks file candidates for the agent and optional verifier. It requires no Jev/provider key or database connection, does not read history/cache, and creates no files or locks. It never executes even a --version probe. Missing executables, model mappings, or valid templates produce a failing exit status. An absent verifier is a warning, not a failure; process success alone still is not learning evidence.

The human report escapes the requested harness name. JSON reports use schema_version: 1, harness, scope: "static", ok, checks (stable id, status, code, and explanatory message), and limitations. Once a project is found, failed checks also produce JSON and exit nonzero. CLI argument errors and missing projects retain normal CLI diagnostics. Reports omit configured command paths, arguments, model IDs, credentials, and raw parse/driver errors.

Lookup checks explicit paths or the inherited PATH; it does not expand shell aliases, variables, ~, or PATHEXT. Unix relative paths/PATH entries are checked against the project root, with regular-file and execute-bit checks. On Windows, bare names may omit .exe; non-.exe extensions must be explicit. Preflight requires absolute explicit paths and absolute PATH entries on Windows, and warns that it does not search extra system/application directories. This intentionally conservative check is not a complete reproduction of OS executable resolution; use an absolute path if lookup is ambiguous. Windows batch wrappers get a warning because Rust launches them through cmd.exe.

An ok result means static checks passed, not that an agent is authenticated or will successfully launch. Binary format, interpreters, mount/ACL restrictions, agent-specific flags, provider model access, and task correctness are not tested; files and environment may change afterward. Preflight does not change jevia run or the existing jevia check live routing probe.

Manual configuration

Harness adapters are shell-free process templates. Add a harness to .jevia/config.toml and map every capability tier to a concrete model:

[harnesses.agent]
command = "my-agent"
args = ["run", "--model", "{model}", "{task}"]

[harnesses.agent.models]
fast = "provider/small"
balanced = "provider/standard"
strong = "provider/frontier"

[harnesses.agent.verification]
command = "cargo"
args = ["test", "--workspace", "--all-features"]

A complete ready-to-copy configuration is available at examples/jevia.toml.

Then route and run a task through that adapter:

jevia run agent "investigate the failing integration test"

Extra harness arguments must follow -- and are appended without shell interpretation:

jevia run agent "update the parser" -- --verbose

Templates support {task}, {model}, {tier}, and {run_id}. Jevia requires the task and model placeholders, rejects unknown placeholders, launches the configured executable directly, and mirrors its exit code. A non-zero harness exit records failure and skips verification. Without a configured verifier, a zero harness exit records success for backward compatibility.

When verification is configured, Jevia runs it only after the harness succeeds and uses its exit status as the final outcome. A verifier that cannot start leaves the outcome unknown, preventing an environment problem from incorrectly training the router. Verification arguments support the same placeholders and are also launched directly without shell interpretation.

Completed harness runs also record the concrete model, harness name, duration, process exit code, and verification evidence. This data appears in jevia runs --json and is supplied with relevant outcomes on later routing requests, so model changes do not erase which implementation actually produced a verified result.

Run lifecycle

Execution progress is separate from task outcome. New records track routed, running, verifying, completed, launch_failed, or interrupted, with start and finish timestamps. A completed process may still have a failed task outcome.

jevia runs show <run-id>
jevia runs recover <run-id>

show prints the complete record as JSON. recover explicitly marks a formerly running/verifying execution as interrupted only if no Jevia supervisor holds its per-run lease. It leaves the task outcome unknown and never reruns or terminates processes. After a supervisor crash, inspect any surviving child processes and workspace changes before starting new work. Legacy unknown outcomes are not assumed to represent interrupted executions. Feedback on active runs is refused.

New and updated records use schema version 3; versions 1 and 2 remain readable. Older CLI versions refuse version 3 rather than silently discard new metadata. The ignored run-leases/ sidecars are retained so concurrent processes always coordinate on the same lock file.

Bounded non-interactive execution

For a headless harness, opt into owned process-tree supervision:

jevia run agent "fix the parser" --non-interactive --timeout-seconds 300 --verification-timeout-seconds 120

Each deadline applies only to its execution phase, not the Jev routing request. Both flags require --non-interactive and accept 1–86400 seconds. Unspecified deadlines are unlimited. This mode disables stdin and uses a Unix process group or Windows job object; stdout/stderr still stream normally. Ctrl-C (and SIGTERM on Unix) stops the owned group/job and records cancelled; a deadline records timed_out. Outcomes remain unknown, failed/cancelled harnesses skip verification, and verification cancellation preserves the harness evidence. Exit codes are 130 for cancellation and 124 for timeout. Cleanup errors record interrupted instead of claiming the process tree was stopped.

Without this flag, existing interactive terminal behavior remains unchanged. This is not a sandbox: descendants that deliberately escape a process group/job, SIGKILL of Jevia, and machine crashes cannot be handled reliably. Use explicit recovery and inspect the workspace in those cases; no work is automatically retried.

Outcome provenance

Run records distinguish process_exit, verification, and manual evidence. Process-only success/failure remains visible, but only known outcomes from a completed verifier or explicit human feedback are supplied to Jev as learning evidence. Legacy outcomes without provenance are not silently promoted; confirm them with feedback if you want them used in routing. runs reports the source and whether the result is eligible for learning.

jevia feedback <run-id> success
jevia feedback <run-id> failure --reason "The integration test still fails"
jevia runs show <run-id>

Changing an already-known outcome requires a nonempty --reason. Every feedback operation retains the prior outcome/source, timestamp, and optional reason in a audit trail in the selected backend; original execution evidence is preserved. Reasons are limited to 4096 bytes and are never sent to Jev. Setting the outcome to unknown removes it from learning evidence. These records are not a tamper-proof audit log.

Routing cache

Jevia caches equivalent routing decisions locally so repeated work does not always require another network request. The default policy keeps up to 256 decisions for 15 minutes:

[cache]
enabled = true
ttl_seconds = 900
max_entries = 256

A cache key is a SHA-256 fingerprint over the exact task, Jev endpoint and model, routing policy, tier definitions, selected harness mapping, and the recent completed evidence actually sent to Jev. A new success, failure, verification result, policy change, model change, or harness change therefore produces a miss automatically. Pending outcomes do not invalidate an otherwise equivalent decision.

Cache files contain the fingerprint and decision signal, not task text. Every hit receives a fresh run ID and timestamp, and run records expose source=live or source=cache. Use --no-cache on jevia route or jevia run when a forced live decision is needed.

Cache errors never block routing: Jevia reports the problem and falls through to a live request. API errors are never cached, expired decisions are never used as an offline fallback, and jevia cache clear provides an explicit recovery path for a damaged cache.

Concurrent equivalent cache misses normally share one live routing request. Waiters recheck both the cache and current learning evidence before using a decision; they still receive independent run IDs. Coordination uses up to 256 stable lock stripes in the ignored cache-leases/ directory, so lock files do not grow per task. Unrelated requests can occasionally share a stripe and wait. No global history/cache lock is held during network calls. An OS lease is released if its owner exits; failures are not cached, so another caller can try.

Waiting is bounded to the configured Jev timeout plus one second (at most 30 seconds). On expiry or a coordination error, routing proceeds live; duplicate requests are possible in that fallback. --no-cache skips coordination too.

Storage

JSONL remains the default. SQLite and PostgreSQL are opt-in alternatives; changing the backend does not synchronize or automatically move existing history. The normal route, run, runs, feedback, doctor, and check commands use the selected backend. These options require v0.1.2 or newer.

SQLite: local database, no server

The guided CLI path avoids editing TOML by hand (run jevia init first):

jevia storage setup sqlite --import-jsonl
# Stop all Jevia writers/supervisors using this workspace, then:
jevia storage setup sqlite --import-jsonl --apply --confirm-stopped
jevia storage check
jevia stats

The first command previews without creating files or contacting a database. --path .jevia/custom.db chooses another local file; paths are resolved from the discovered project root even when invoked from a subdirectory. Protect and ignore custom paths outside .jevia yourself. An empty JSONL project can omit --import-jsonl; a nonempty one must include it to avoid silently abandoning existing evidence. The source JSONL file is never deleted or rewritten.

Or configure manually:

Add to .jevia/config.toml:

[storage]
backend = "sqlite"
url = "sqlite://.jevia/jevia.db"

Then explicitly initialize and optionally import your old JSONL history:

jevia storage init
jevia storage check
jevia storage import-jsonl
jevia storage import-jsonl --apply
jevia runs

Relative file paths are resolved from the project root, not the current working directory. SQLite is bundled into the binary. It uses WAL, full synchronous writes, a five-second busy timeout, and private file permissions on Unix for new databases. Use a local disk, not a shared/network filesystem. Default .db files, WAL/SHM sidecars, and run locks under .jevia are ignored after init/storage init. For custom paths/extensions, protect the directory and add your own ignore rules; on Windows, protect the directory with the appropriate filesystem ACLs.

PostgreSQL: bring your own database

Provision a dedicated PostgreSQL database and put its connection URL in your secret manager or environment as JEVIA_DATABASE_URL. Do not put passwords in the project config or CLI arguments.

jevia storage setup postgres --project my-project --import-jsonl
# Stop all Jevia writers/supervisors using this workspace, then:
jevia storage setup postgres --project my-project --import-jsonl --apply --confirm-stopped
jevia storage check

--url-env MY_DATABASE_URL selects a different environment variable name, not a URL value. Preview does not resolve that variable or test connectivity. On apply, the existing TLS and timeout rules apply; --allow-insecure-localhost is available only for loopback development databases. The command creates the Jevia schema and project, not a PostgreSQL server, database, or user.

The equivalent manual configuration is:

[storage]
backend = "postgres"
url_env = "JEVIA_DATABASE_URL"
project = "my-project"

Run jevia storage init once with schema-creation permissions, then jevia storage check. Normal operation needs read/write access to the jevia_projects and jevia_runs tables and read access to jevia_schema, not permission to create databases. Remote connections require certificate and hostname verification (sslmode=verify-full); sslrootcert, sslcert, sslkey, and application_name URL options are supported. Only local development can opt into plaintext using allow_insecure_localhost = true and a loopback host.

Use a direct or session-pooled connection, not a transaction-mode pooler: execution guards use PostgreSQL session advisory locks. Each CLI invocation uses a small pool; running a harness also holds a dedicated guard connection.

Use the same project value across trusted workspaces to share evidence. This namespace is not authorization or tenant isolation: anyone with access to the database tables can access other projects. Separate database roles/databases or a future authenticated managed API are needed for mutually untrusted users.

Setup safety and recovery

storage setup is preview-first. Applying requires both --apply and --confirm-stopped: stop all source writers and supervisors, including scheduled jobs and other workspaces using the source file. Recover any active run records before retrying; this command does not stop processes or recover runs for you.

Apply backs up the exact old config to a new .jevia/config-backups/config-*.toml file, initializes/checks the destination, imports requested history transactionally, then atomically replaces config last. Routing, privacy, cache, harness settings, and unrelated TOML comments are preserved. Config permissions are retained; new backups are private on Unix and added to local ignore rules. Backups are not automatically removed. On Windows, protect the directory with appropriate ACLs.

Active, duplicate, malformed, unsupported, or conflicting imported records cause failure. Identical destination records are skipped for safe retries. Setup does not replace config on connection, schema, permission, or import failure. It serializes other setup invocations and checks for changes to the source/config before switching, but cannot prevent an editor or already-running supervisor from writing: the stop-writers requirement is not optional.

The database and filesystem are not one atomic transaction. A failed setup can leave an initialized database, a config backup, or (if the final config save fails) imported records. Inspect config, keep the original JSONL and backup, and retry only after reconciling concurrent changes. A crash after replacement may mean config was already switched; verify with jevia storage check. Never blindly restore old config once new work has written to the database, since histories can diverge. No automatic synchronization, rollback deletion, or backend fallback is performed.

Once configured, repeat the same setup command without --import-jsonl to initialize/check the same target without rewriting config or adding another backup. Old JSONL files may be stale, so importing them from an already-SQL project needs the separate explicit storage import-jsonl command. Changing between SQL targets or back to JSONL is not supported by guided setup; use explicit export/import and review the configuration change yourself. Changing the value of the PostgreSQL URL environment variable can independently change the destination; setup cannot detect which database it previously named.

Guarantees and current limits

  • Database writes are transactional. Feedback history and its current outcome change together; project-scoped write locks prevent lost updates. Retention holds the same lock while saving recovery files; schedule it during a quiet period.
  • Recent history and eligible evidence use indexed, bounded queries in append order. Complete versioned records preserve execution and feedback provenance.
  • storage check verifies schema and CRUD permissions with a rolled-back probe; it does not insert fake evidence. doctor/check include this access check. SQL records are not individually decoded by the default access check.
  • storage check --deep instead inspects the complete selected history without a write probe, automatic repair, Jev request, or cache access. JSONL validates record schemas and nonempty/unique run IDs under the shared history lock, streaming records while retaining an ID set (memory grows with the IDs). SQL uses 200-row pages in one consistent read snapshot to validate record schemas, indexed run IDs, learning flags against current evidence rules, and positive append ordinals bounded by the project's append counter. Gaps left by retention are valid; the counter need not equal the newest retained ordinal. Only the configured PostgreSQL project is inspected. Ordinary SQL writers can continue, though a long scan may delay database cleanup/WAL recycling.
  • A deep-check failure exits nonzero and identifies the line or append-position where possible, without printing task text, IDs, or database credentials. Keep the current history and backups and investigate locally before making changes; no records or indexes are silently rewritten. Success means the inspected snapshot passed these logical checks, not that write permissions, physical database integrity, or task-outcome correctness were verified. Run the default access check separately when needed; database-native integrity checks and backups remain the operator's responsibility. Missing storage is not initialized.
  • Database/record schema versions are checked; unknown versions are rejected. Driver errors are redacted and database operations have five-second timeouts. An outage never silently switches history back to local JSONL.
  • Imports preview by default and commit all-or-nothing with --apply. Identical run IDs are skipped; conflicting records, duplicate source IDs, active runs, or malformed/unsupported records abort the import. Stop source writers first. Keep the unchanged source as your backup; no automatic bidirectional sync or background replication is provided.
  • storage import-jsonl validates and streams the source into a private unnamed temporary file before taking a database write lock. It holds the source's shared JSONL lock during capture, then imports only the captured records in one database transaction. Later changes to the source are not included; preview and apply capture independently. Both modes need temporary disk space for the normalized history in the OS temporary directory (use protected directory ACLs on Windows). Memory grows with the run-ID set plus the largest record, not all task bodies; the ID set is released before database writes. Snapshot failures prevent writes; later read errors or conflicts roll back all inserts and their ordering counter. The temporary file is removed on close/process exit, not kept as a backup. Imports still normalize known fields and omit unknown additive fields. Large imports hold the project write lock until commit/rollback (SQLite serializes all database writers); this is not a resumable or chunk-committed import. Guided storage setup --import-jsonl still captures its migration source in memory.
  • jevia storage export --output .jevia/snapshot.jsonl writes a new private snapshot in append order. It streams one JSONL record or a bounded SQL page at a time, rather than loading the entire history. JSONL holds its shared history lock; SQL uses one consistent read snapshot across all pages (PostgreSQL repeatable-read/read-only, SQLite WAL snapshot) without taking the project write lock. SQL changes committed after the snapshot begins appear in a later export, not partway through this one. Very large records still require memory, and a long SQL snapshot can delay database cleanup/WAL recycling.
  • Export writes to a private temporary file beside the destination, validates all records, flushes/syncs the file, and publishes without overwriting any existing path, including symlinks. Handled read/write failures do not publish a partial destination. The parent directory is synced on Unix; if that final sync fails, the error says the complete file was already created. A process crash can leave a private .jevia-export-*.tmp file. Protect and ignore exports and their output directory; they may contain task text. On Windows, use appropriate directory ACLs. Exports normalize known record fields, omit unknown additive fields, and are logical record snapshots, not exact-byte or physical database backups.
  • The decision cache and cache-miss coordination remain local. Every routing attempt fetches current eligible evidence before computing its cache key, so new shared outcomes invalidate affected decisions. Cross-machine request deduplication and offline write queues are not included.
  • SQLite run locks sit beside the canonical database path. PostgreSQL guards block recovery while the supervisor's database session is alive. Because a lost session does not prove its subprocess stopped, PostgreSQL recovery also requires jevia runs recover <id> --confirm-stopped after inspecting and stopping the original supervisor and any surviving processes. Recovery is terminal and fences late writes from that supervisor; it never reruns work. There is no automatic lease expiration or remote process termination.
  • runs archive supports all three backends with preview-first, backup-first retention (see below). runs repair remains JSONL-only: database integrity repair and physical backups require database-native tooling.
  • Managed hosting, managed credentials, and a dashboard are not part of this integration. Data is stored locally or in the user's own database.

Default JSONL data

Project configuration lives in .jevia/config.toml and is intended to be reviewed and committed. Run history lives in .jevia/runs.jsonl and is ignored by the project-local .jevia/.gitignore because prompts and outcomes may be sensitive. Jevia coordinates concurrent readers and writers through the ignored .jevia/runs.lock sidecar so parallel agents cannot overwrite one another's evidence.

Routing decisions live in the ignored .jevia/cache.jsonl file and use the same locking and atomic-replacement guarantees through .jevia/cache.lock.

By default Jevia stores task text in the selected backend so it can supply useful examples to future decisions. Set store_task_text = false under [privacy] to retain only routing metadata.

In JSONL mode, jevia doctor validates the complete history and reports malformed records without deleting or rewriting them.

History maintenance

Both maintenance commands preview by default. Inspect the report before repeating with --apply; --json provides counts and saved paths for automation.

jevia runs repair
jevia runs repair --apply
jevia runs archive --keep 1000
jevia runs archive --keep 1000 --apply

Repair is JSONL-only. It handles an incomplete, unterminated final JSON line after an interrupted write, or a valid final record missing its newline. It refuses malformed middle lines, complete invalid records, unsupported schemas, and duplicate IDs. It does not guess at missing fields or rewrite individual outcomes.

Archival works with JSONL, SQLite, and PostgreSQL. It keeps the most recently appended --keep eligible terminal records (minimum one), plus every active, routed/pending, or legacy-unknown record. SQL also retains any record with an execution owner, even if its recorded lifecycle appears terminal. This command does not recover runs, stop processes, or infer that old work has finished.

Older eligible records move to a separate JSONL archive. They no longer appear in runs or stats, accept feedback, or inform routing. Routing fetches current evidence before cache lookup, so removing relevant evidence changes the cache key; archival itself does not clear or rewrite the local decision cache. Choose a retention window large enough for the evidence you need. This is explicit maintenance, not automatic pruning.

All backends save recovery files under the invoking project's .jevia/history-backups/ and .jevia/history-archives/ on the CLI machine, including when PostgreSQL is remote. Apply recomputes its plan under the history lock. Preview (and a no-op apply) removes no records and creates no recovery files.

  • JSONL: repair and archival back up the exact original file before atomic replacement. Archived record bytes, including additive metadata, are preserved.
  • SQL: archival holds the selected project's write lock, validates all records in bounded pages, and saves a full project-record snapshot plus an archive of the selected rows before any deletion. A private temporary journal bounds memory while deletion batches commit in one transaction. Saved JSON preserves additive fields but flattens physical line breaks into JSONL; it is not an exact-byte or physical database backup. SQL project/ordinal/owner metadata and other projects are not included. There is no database schema change.

SQL rejects malformed/unsupported records and mismatched indexed IDs, rechecks the snapshot against its plan, and conditions deletions on the saved row values. Jevia writers serialize with retention; long operations can make other commands hit their database timeout. Coordinate external SQL writers too, since they may bypass Jevia's project lock. A snapshot failure prevents deletion. A deletion failure rolls back all batches and leaves any finalized recovery files. If a connection fails while committing, the result may be ambiguous: inspect active history and the reported files before retrying or restoring. Never assume a failed response means nothing committed.

These directories are ignored local data and may contain sensitive prompts. New snapshot files/directories use private permissions on Unix; on Windows, protect the project directory with appropriate filesystem ACLs. Jevia syncs files before deleting, and also syncs snapshot directories on Unix. Backups and archives are never overwritten or automatically removed. Total disk use can increase; SQL archival does not vacuum or compact the database.

For SQL restoration, first stop writers, export the current state to a new file, and review the chosen archive before explicitly importing it:

jevia storage export --output .jevia/before-restore.jsonl
# Replace sql-runs-UUID.jsonl with the archive path printed by `runs archive`.
jevia storage import-jsonl --from .jevia/history-archives/sql-runs-UUID.jsonl
jevia storage import-jsonl --from .jevia/history-archives/sql-runs-UUID.jsonl --apply

Import keeps run IDs, outcomes, and known provenance, skips identical records, and aborts on conflicts. It appends restored records as newest, not at their original SQL positions, which can change the routing evidence window. Unknown additive JSON fields remain in the archive but are not retained by typed import. A full pre-archive snapshot can contain active records and is not suitable for blind import. For JSONL restoration, stop writers and save current history before manual replacement; an older backup would otherwise discard newer runs. SQL snapshots do not replace a database-native disaster-recovery backup strategy.

Repository structure

  • crates/jevia-core contains configuration, typed API contracts, policy, and outcome records.
  • crates/jevia-cli contains JSONL/SQLite/PostgreSQL persistence and terminal commands.
  • website contains the Farm.js product site and getting-started guide.

Dashboard code does not belong in this repository. The managed dashboard is a separate private project with a separate security boundary.

Development

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-features

Run the website separately:

cd website
pnpm install
pnpm dev

The site serves /install.sh and uses the current page's origin in its copyable install command: localhost during development and the deployed domain in production. The script downloads the pinned GitHub release binary, verifies its SHA-256 checksum, and installs it to ~/.local/bin by default. It does not need Rust or Cargo and does not modify shell configuration. Run pnpm test in website to check the installer without installing anything.

See CONTRIBUTING.md for the contribution and commit conventions and docs/architecture.md for component boundaries and routing invariants.

License

MIT