- Go 79.7%
- Python 7.8%
- TypeScript 6.2%
- Svelte 4.1%
- CSS 1.7%
- Other 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Review fixes for forge PR #68 (merge |
||
| bench/harnesses | ||
| benchmarks | ||
| cmd | ||
| docs | ||
| examples/plugins | ||
| internal | ||
| nix | ||
| runtime | ||
| scripts | ||
| sdk | ||
| web | ||
| .gitignore | ||
| .goreleaser.yaml | ||
| AGENTS.md | ||
| flake.lock | ||
| flake.nix | ||
| go.mod | ||
| go.sum | ||
| LICENSE.md | ||
| README.md | ||
Yazi
A durable coding-agent runtime for work that outlives a terminal, context window, or machine.
Yazi gives coding agents a persistent place to work. Sessions keep running after the UI closes. Python state, background processes, child agents, queues, goals, and transcripts remain available when you reconnect. Local and remote tools run behind explicit permissions while model credentials stay with the daemon.
Yazi is a standalone Go application with a fast terminal UI, a SQLite-backed runtime, and portable binaries for macOS and Linux.
Note
Yazi is under active development. Core daily-use workflows are implemented, but platform coverage and packaging are still evolving.
Why Yazi?
Most coding-agent sessions are tied to one terminal and one context window. Long tasks expose the limits quickly: a terminal disconnects, context is compacted, a test keeps running, or parallel work becomes hard to coordinate.
Yazi treats agent work as durable runtime state instead:
- Detach without stopping work. A local daemon owns sessions, not the TUI.
- Outgrow the context window. Complete transcripts stay durable while agents search compacted-away history on demand.
- Resume the whole workspace. Restore transcripts, Python state, process handles, queues, goals, and the child-agent tree.
- Run tools without handing over the host. Native sandbox backends and typed permissions keep execution fail-closed.
- Delegate real work. Child agents have independent context, runtimes, artifacts, and model settings.
- Keep authority local. Remote machines execute tools; the local daemon keeps credentials, approvals, history, and provider traffic.
- Build workflows that improve over time. Durable memories, prompt notes, skills, and subagent specifications form a continual harness around the model.
What makes Yazi different
The first features below are work introduced or substantially extended in Yazi, not a restatement of the Prime Agent feature set.
Revisioned task state and bounded episodes
Yazi is building toward agents that can start a fresh context without pretending their chat transcript is the source of truth.
- Specs, tasks, acceptance criteria, and user constraints have explicit identity.
- Working checkpoints use revision-checked updates, so stale workers cannot silently overwrite newer state.
- Verified claims retain evidence and workspace versions.
- Failed approaches, unresolved items, and next actions are first-class state.
- External actions have durable intent, status, and reconciliation records.
- Scoped FTS5 evidence search discovers supporting material without granting it authority or leaking data across tasks.
- Cold-resume diagnostics test whether work can continue from canonical state without smuggling the old transcript into the next context.
Bounded episodes remain experimental and fail closed at incomplete tool or side effect boundaries. See bounded episodes and spec-driven development.
Effectively unlimited searchable context
Yazi separates durable history from the model's working context. The complete active-branch transcript remains in SQLite as a session grows. The model receives a bounded summary and recent suffix, then searches the original history when an older detail matters:
hits = await history.search("why we rejected the first migration plan")
context = await history.context(hits[0]["entry_id"], before=2, after=2)
Search is session-scoped, read-only, and bounded. It uses an FTS5 index over textual projections instead of loading the whole transcript; binary image bodies are excluded. This keeps provider input, latency, and cost bounded while letting one durable session continue far beyond a model's context window.
“Effectively unlimited” describes session history, not the size of one model request: each provider call still obeys the selected model's context limit, and compaction remains lossy until the agent retrieves the original detail.
Read less, know more
Reading a large file to find out what is in it is the most common way an agent
wastes its context. The index tool answers the structural question instead:
it returns the file's skeleton — imports, types, fields, functions, and the line
range of each — so the model can then read only the ranges that matter. The
same outline is a CLI verb and a model tool.
$ yazi index internal/tool/file/read.go
skeleton internal/tool/file/read.go (go, 233 lines)
imports: [4-17]
context, encoding/json, errors, fmt, io, os, path/filepath, strings, unicode/utf8,
src.krea.to/kreato/yazi/internal/tool, src.krea.to/kreato/yazi/internal/tool/toolout
consts:
MaxReadBytes [22]
vars:
readSchema [55]
types:
type Config struct [24-38]
Cwd string
AllowOutsideCwd bool
MaxOutput int
MaxReadBytes int
IndexThreshold int
type Read struct [40]
config Config
func (r *Read) Definition() tool.Definition [57-64]
func (r *Read) Invoke(ctx context.Context, in tool.Invocation, _ tool.UpdateSink) (tool.Result, error) [159-233]
fns:
func NewRead(config Config) *Read [42-53]
func resolve(cwd, name string, allowOutside bool) (string, error) [70-112]
func within(base, path string) bool [115-124]
func readRegular(path, name string, limit int) ([]byte, bool, error) [129-157]
Outlines are exact for Go (the standard library parser), and structural for
Rust, C, C#, Python, TypeScript/JavaScript, Shell, Terraform, Nix, HTML, CSS,
YAML, Markdown, and JSON.
An HTML file's inline <script> and <style> blocks are outlined in their own
language. read applies the outline itself above 400 lines, so the agent does
not have to remember to ask; full: true still returns the whole file.
/preview <file> shows the same outline in the TUI without involving the model.
Unsupported file types
are refused with a hint to read the file, and nothing is guessed: a file that
cannot be parsed says so. See code index.
Recovery is part of the protocol
Yazi does more than save messages. It makes runtime recovery explicit:
- authoritative reconnect snapshots plus bounded event replay;
- restored Python state and durable background-process handles;
- immediate TUI attachment while a restored runtime activates;
- per-session failure isolation instead of daemon-wide failure;
- idempotent receipts for mutating daemon requests;
- per-session leases that stop two daemons from driving one session;
- compaction that preserves complete tool exchanges and active work.
The interface can disconnect and model context can compact while the underlying work remains durable and auditable.
Fail-closed execution and permissions
Yazi separates model decisions from execution authority.
- Native macOS Seatbelt and managed rootless Linux
runcbackends. - Typed permissions with transactional replacement and explicit denial state.
- Deny-default filesystem and network policy.
- Private per-project home, cache, and temporary state on macOS.
- Credentials, provider calls, audit state, and approval logic remain outside worker environments.
- Unsupported policy shapes fail closed instead of falling back to host access.
- Ambiguous operations and external side effects are never blindly retried.
Sandboxing reduces risk; it is not a claim of perfect containment. Read the sandbox contract before working with untrusted repositories.
Local authority, remote execution
Named SSH endpoints move the complete tool environment to another Linux machine: shell, files, Python, images, background processes, cancellation, and stdio MCP. The local daemon retains credentials, history, provider traffic, and approval authority.
yazi endpoint add buildbox user@buildbox --remote-cwd /home/user/project
yazi endpoint test buildbox
yazi --endpoint buildbox
SSH uses the system client and normal known_hosts verification. Provider keys
and authority are not copied to the worker.
Steering and follow-ups are separate
Long tasks need more than a single prompt queue. Yazi distinguishes instructions that should affect active work from requests that should run next. Both queues are durable and ordered. The TUI shows active work, queued instructions, tool output, reasoning, diffs, and child-agent activity together.
Conservative provider retries
Request retries are session settings rather than unconditional transport loops.
Yazi retries only classified transient failures before visible output, respects
backoff and Retry-After, and never retries cancellation, permanent failures,
ambiguous tool actions, or external side effects.
Durable sessions
Closing the terminal does not end the job. Reconnect to a running or completed session with its history and runtime state intact.
# Start interactively
yazi
# Detach, then return later
yazi --continue
yazi --resume <session-id>
The legacy terminal controller and its YAZI_TUI=legacy fallback were removed;
the default TUI is the only interactive surface.
SQLite stores conversations, branches, queues, goals, usage, and agent state. Large immutable results live in an atomic artifact store.
A persistent Python control plane
Yazi gives the model an IPython-compatible runtime with top-level await.
Variables, imports, functions, the working directory, and environment survive
across tool calls and restored sessions.
h = bash("go test ./...")
print(h.pid, h.running)
print(h.tail(20))
# Do other work while the command runs.
result = await h
Shell commands are asynchronous process objects. They support incremental output, bounded waits, cancellation, completion notifications, and durable handles.
Recursive agent teams
Split independent work across child agents without flattening everything into one context window.
reviewer = await rlm.spawn(
"Review the storage changes and report concrete regressions.",
name="storage-reviewer",
)
Each child gets its own context, history, Python runtime, artifacts, and model settings. Agents can run concurrently, send scoped messages, publish progress, and survive parent compaction. Completion is event-driven, so the parent does not need to waste turns polling.
A continual harness around the model
Yazi can retain useful operating knowledge without hiding it in an ever-growing chat transcript:
- durable memories and prompt notes;
- Markdown and Python-backed skills;
- reusable subagent specifications;
- project context and prompt templates;
- refinement history and installable capability packages.
It is explicit, inspectable, and scoped. A local entry belongs to one
conversation (keyed by the session that wrote it, so a child agent's memory is
neither its parent's nor every other session's) and only that session's prompt
sees it; a global entry reaches every session's system prompt. The agent
itself may write global entries through harness.put - cross-session memory is
a deliberate agent feature, not a plugin one, and a plugin is refused it. A
corrupt harness.json is moved aside to harness.json.corrupt-<ts> and the
daemon starts empty, but only Open recovers: a write path that meets a corrupt
file returns the error and leaves the file alone rather than overwriting every
memory with empty state. The harness complements the transcript instead of
replacing it.
Goals, schedules, and bounded autonomy
Yazi supports explicit goals with token budgets, scheduled prompts, user-owned and agent-owned heartbeats, bounded autonomous continuation, completion gates, and safe wake-ups from child agents and background processes.
Integrations without schema overload
Yazi supports HTTP and stdio MCP, but remote tools do not all need to be injected into every model request. The Python control plane can discover and call them on demand:
connections = await mcp.list_connections()
tools = await mcp.list_tools("github")
result = await mcp.call_tool(
"github",
"search_repositories",
{"query": "language:go durable agents"},
)
An MCP account reports one of missing, disconnected, unverified,
connected, error or recovery-required, plus login_pending while a
sign-in is in flight. unverified is a credential that exists but has not been
checked against the server yet; disconnected is a record with no usable
credential. error is a credential that can no longer be used - a
rejected refresh, or a failed verification - and it carries a fixed, non-secret
last_error ("MCP sign-in expired; sign in again" or "MCP verification failed") so the UI asks for a new sign-in instead of offering Connect again. A
remote server's own error text never enters that field. recovery-required
means a write was interrupted and the private attempt and nonce are still held
for a retry.
It also supports generic API-key and OAuth provider flows, compatible model endpoints, multimodal content, and permission-gated Computer Use (optional, macOS only — see Computer Use).
Extend the harness with plugins
Python plugins run out of process over a versioned JSONL protocol. They can add model tools and slash commands, rewrite or block hooks, render declarative UI, provide native or host-proxied model providers, and call the daemon through generated capability facades:
yazi plugin init hello --dir /tmp/plugins
yazi plugin install /tmp/plugins/hello --yes
yazi plugin status hello
yazi plugin enable hello
Installs are local and transactional, Python plugins get a private venv and a
self-contained SDK, and sandboxing is the default; --trust and unsafe are
explicit. The /plugins panel exposes the same ledger. See
Plugins for the authoring guide, Plugin API
for the generated method registry, and Install and trust
for environments, permissions, signing, and updates.
Quick start
With Nix
Run directly from the repository:
nix run .#
Install both yazi and its sibling yazi-runtime:
nix profile install .#
yazi
The Nix package also includes portable Linux/macOS runtime helpers for managed SSH endpoints. Managed endpoints upload the matching OS/architecture helper; remote hosts do not need Yazi, Go, or Nix preinstalled.
Open a development shell with Go, gopls, SQLite, and native build dependencies:
nix develop
Build from source
A normal build uses the portable pure-Go SQLite driver:
git clone <repository-url> yazi
cd yazi
go build -o yazi ./cmd/yazi
go build -o yazi-runtime ./cmd/yazi-runtime
./yazi
Keep both executables in the same directory. For a native SQLite/FTS5 build:
CGO_ENABLED=1 go build -tags 'yazi_sqlite_cgo sqlite_fts5' -o yazi-runtime ./cmd/yazi-runtime
See Install and update for release layout and updater details.
Configure a model provider
Environment credentials take precedence over the owner-only auth store.
export YAZI_PROVIDER=openai
export OPENAI_API_KEY=...
export OPENAI_MODEL=gpt-4.1
yazi
OPENAI_API_KEY is the key for OpenAI, not a general provider key. It is
used for openai and openai-compatible and for nothing else, so a machine that
merely exports it does not send it to Anthropic, Mistral, or any other provider —
each of those reads its own variable (ANTHROPIC_API_KEY, GOOGLE_API_KEY /
GEMINI_API_KEY, COMMAND_CODE_API_KEY, OPENCODE_API_KEY) or its stored
/login credential.
Choose a provider and model for one launch:
yazi --provider anthropic --model claude-sonnet-4-5
Or use an OpenAI-compatible endpoint:
yazi --provider openai-compatible --base-url http://127.0.0.1:8000/v1 --model local-model
Command Code uses its Provider API and live model catalog:
export COMMAND_CODE_API_KEY=...
yazi --provider commandcode --model deepseek/deepseek-v4-flash
Named custom OpenAI-compatible providers can coexist in config.json:
{
"provider": "local",
"model": "my-model",
"providers": {
"local": {
"name": "Local Gateway",
"base_url": "http://127.0.0.1:8000/v1",
"headers": { "X-Client": "yazi" }
}
}
}
Store the key with /login or under the matching provider ID in auth.json.
Do not put secrets in headers; these settings are normal configuration.
A ChatGPT Plus or Pro plan also pays for Codex usage, and yazi can spend that
plan instead of an API key. Sign in with /login openai-codex; the browser flow
returns to a loopback port on this machine, and the page's "Authorization
complete" is the whole sign-in: yazi checks the reply's state against the one it
sent and exchanges the code itself. On a remote or headless box the loopback port
is not reachable from the browser, so pick Sign in on another device instead
and type the short code it prints on whatever machine has a browser. If you would
rather paste the redirect by hand, the panel accepts the full callback URL or
Anthropic's code#state; a bare code is refused, because the state is what binds
it to this sign-in:
yazi --provider openai-codex --model gpt-5.3-codex
The credential is an OAuth token set, not a key: it is renewed when it nears
expiry and the rotated tokens are stored, so a long session keeps working. The
model list comes from the subscription's own catalog; the bundled Codex models
are the fallback when that read fails. The list is read live, so a model the
plan gains appears without a yazi release, and the reasoning levels it offers
come from the backend too: a level yazi has no name for (the backend's
reasoning.effort is sent as the backend spells it) is still selectable. If one
model in the list cannot be represented at all, yazi keeps every other model and
logs the skipped one by name - yazi: openai-codex/gpt-6.1-sol: model skipped: ... - instead of dropping the whole list back to the bundled three. A plan
whose usage window is spent reports the backend's own message rather than being
retried. When ChatGPT refuses the stored login for good
(invalid_refresh_token), yazi logs ChatGPT login expired: run /login openai-codex, shows the provider as needing a sign-in, and stops trying that
login on every start until you sign in again (see "What starts after
listening" in docs/profiling.md).
Reasoning models such as gpt-6.1-sol return their thinking as encrypted
items that yazi sends back on the next request. Each item is replayed on its
own and always carries its summary list (empty when the model kept no summary).
Before this was fixed, a turn whose thinking had no summary, or that produced
several thinking items, made every later request in that session fail with
HTTP 400 (Missing required parameter: 'input[N].summary' or
invalid_encrypted_content). Sessions started after the fix are unaffected;
an older session that already shows one of these errors keeps failing, because
the bad item is in its history - start a new session (see
docs/codex-reasoning-replay.md).
Yazi has native protocol-family support for OpenAI, Anthropic, Google, Amazon Bedrock, Mistral, and compatible services. Model catalogs carry capabilities such as reasoning levels, image support, and service tiers.
Everyday commands
# Interactive or one-shot work
yazi
yazi -p "inspect this repository and run its tests"
# Continue, resume, or fork durable sessions
yazi --continue
yazi --resume
yazi --resume <session-id>
yazi --resume <session-id> --fork
# Inspect and control active work
yazi agents
yazi list
yazi attach <session-id>
yazi send <session-id> "summarize progress and continue"
yazi stop <session-id>
# Export a durable session
yazi session export <session-id>
# Remote execution
yazi endpoint list
yazi endpoint add <name> <user@host>
yazi endpoint test <name>
yazi endpoint set-default <name|local>
# Integrations and operations
yazi sandbox prune --older-than 30d # dry run: stopped containers + unused project storage
yazi mcp list
yazi package list
yazi plugin list
yazi config
yazi schedule list
yazi status
yazi doctor
yazi shutdown
# Public machine-readable protocols
yazi --mode rpc
yazi --mode acp
Run yazi help <command> for exact flags and subcommands.
yazi doctor is also a health gate: it prints its report, then exits non-zero
when any check has severity error — a group- or world-readable state directory,
or a *manifest*.json under it that does not parse — naming the failed checks on
stderr. --json prints the same valid report and still exits non-zero, so a
script can parse the checks and branch on the status. --fix repairs
permissions and stale artifacts; it does not rewrite a manifest it cannot read,
so that error survives the run.
How it works
Terminal UI / CLI / RPC / ACP
│
local framed protocol
│
Yazi daemon
┌──────────┼───────────┐
│ │ │
session SQLite provider clients
actors │ │
│ │ └─ model APIs
├─ persistent Python
├─ async process handles
├─ child agents
├─ queues and goals
├─ MCP connections
├─ supervised plugin processes
└─ local sandbox or SSH endpoint
One actor serializes changes for each session. Sessions and child agents run concurrently. SQLite is the source of truth for runtime state; large immutable objects use an atomic artifact store.
This architecture separates three things that are often coupled:
- The interface can disconnect and reconnect.
- The model context can compact or restart.
- The work remains durable and auditable.
Read current architecture for implementation details and invariants.
Configuration
Active Yazi overrides include:
YAZI_CONFIG
YAZI_STATE_DIR
YAZI_DB_PATH
YAZI_SOCKET_PATH
YAZI_PROVIDER
YAZI_PYTHON
YAZI_UV
YAZI_PYTHON_VERIFY
YAZI_PLUGIN_DIR
YAZI_SANDBOX_BACKEND
YAZI_SANDBOX_SOCKET
YAZI_SANDBOX_IMAGE
The default OCI sandbox image is ghcr.io/kreatoo/yazi-docker:latest.
Set YAZI_SANDBOX_IMAGE or sandbox_image to override it.
Local Linux runc sessions accept sandbox_bindings for filesystem and
loopback host-port mappings, and sandbox_port_relay for the relay assets.
extra_dns sets Docker-like custom DNS servers for the sandbox resolver.
MCP connections can set bind_to_sandbox to expose a loopback HTTP(S) endpoint
inside the sandbox. See Sandboxed execution, including
Reclaiming disk for yazi sandbox prune.
The flake also exports a typed Home Manager module for providers, custom model catalogs, MCP servers, plugins, packages, sandbox settings, and secret-file integration. See Home Manager.
Security principles
- The host daemon owns credentials and provider traffic.
- Model-generated code and repository content are treated as untrusted.
- Credential, daemon, container-engine, and SSH-agent sockets are not mounted into sandboxes.
- Host operations are exact, argv-based, one-shot, and audited.
- Permissions are typed, scoped, and transactionally replaced.
- Plugins are sandboxed by default; trust and
unsaferequire explicit user consent, and raw credentials stay host-side. - Remote execution uses standard SSH host-key verification.
- Updates use signed metadata, exact checksums, serialized activation, and rollback-safe installation.
Platform status
Release builds target:
| Platform | Architectures |
|---|---|
| Linux | amd64, arm64 |
| macOS | amd64, arm64 |
A successful cross-build does not certify every OS version, terminal, or sandbox backend. Native sandbox behavior differs by platform. See platform notes.
Development
go test ./...
go test -race ./...
go vet ./...
python3 -m unittest discover -s runtime/python/tests
Useful technical references:
- Current architecture
- Sandbox contract
- How yazi finds bash - where the shell is looked for locally and on an endpoint, why there is no
shfallback, the exit-127 record, and the PATH rule that stops a project file namedbashfrom running - Remote execution
- Endpoints - running a session on another machine: workspaces, the connect phases and their progress, cancelling an attempt, and the security rules for endpoint values
- Runtime reload - the daemon half of
/reload - Interactive reload - the client half
- Model refresh - what
/refreshre-reads, the six-hour model-list cache, why a start does not ask, and what happens when a live list carries a model or reasoning level yazi cannot represent - Model picker order - why
/modelputs the current model first, the recent history next, and what happens when the model you pick is not signed in - Reasoning replay with ChatGPT/Codex models - how yazi sends a reasoning model's encrypted thinking back, the two HTTP 400 errors that used to break a session for good, and what to do with a session that already shows one
- Queued follow-ups and selection - how queued messages wait for their turn, and why drag-selection only copies the transcript
- Keybindings - where
keybindings.jsonlives, the key-name syntax, how a listed action replaces its defaults, and the full default table - The @ file menu - how the composer finds project files, the 8000-entry walk cap, and typing a path to search inside a large folder
- Autonomous completion gates
- Bounded episodes
- Project files - the
.yazi/skillsand.yazi/promptsa project carries, and why.primestill works - Spec-driven development
- Workspace context - the AGENTS.md block the model gets, why it is not a chat message, and
/workspace-context - Dead code - what the sweep deleted, and what is kept on purpose
- Automatic refinement - the review loop that edits the harness: when it runs, the defaults, cost, the log line, undo
- Footer statistics - the numbers under the transcript, and why they follow the branch you are on
- Profiling -
yazi daemon timings,yazi daemon profile, cold-start profiles, and opt-in request tracing (Jaeger/OpenTelemetry) - Harness benchmarks - how Yazi is compared with other coding-agent harnesses (start-up, CPU, memory, streaming), how to rerun it, and what it does not control for
- Computer Use - the optional macOS screen-control adapter: where it lives, why you can delete it to save space, and how to get it back
Research and project lineage
Yazi is based on Prime Agent, created by Prime Intellect. Prime Agent established the RLM coding-agent harness, interactive workflow, recursive delegation model, and much of the product surface from which Yazi began. Yazi is an independent Go implementation and has since developed its own runtime, recovery, sandboxing, remote-execution, task state, and bounded-episode work. We are grateful to the Prime Agent authors and contributors for the foundation.
The architecture was also informed by these papers:
- Prime Agent: A Self-Improving RLM Harness — Seth Karten, Alvin L. Zhang, Kevin Thomas, Sebastian Müller, Elie Bakouch, David Auras, Leonard Senghaas, Fares Obeid, Kristian Dunas, Johannes Hagemann, and Sami Jaghouar. It describes the recursive language-model harness and self-improvement approach behind the project Yazi was based on.
- MemGPT: Towards LLMs as Operating Systems — Charles Packer, Sarah Wooders, Kevin Lin, Vivian Fang, Shishir G. Patil, Ion Stoica, and Joseph E. Gonzalez. Its hierarchical-memory model inspired Yazi's separation of durable state from disposable model context.
These works are credited as inspiration and lineage, not as claims that Yazi implements every system or result described in them.
Project status
Yazi is an independent implementation focused on durable, recoverable, and
permissioned agent execution. Historical compatibility and parity material
lives under docs/; it is not the product roadmap. New work is evaluated by
whether it makes long-running agent work safer, clearer, faster, or easier to
resume.