A self-hosted AI harness for technical work — the chat UI and the coding agent in one local tool.
--- **At a glance** - **Run ten things at once and lose none of them.** Keep many conversations and background jobs going in parallel. Ziya tells you when one is ready for input, and switching back costs nothing because each thread keeps its own files, model and history. - **Point it at a repo and ask for a change.** You get validated diffs to review, apply with a click, and undo if they're wrong. Your editor stays your editor. - **Ask a structural question, get a picture.** Dependency graphs, sequence and state diagrams, charts, typeset math and packet layouts render inline, and broken diagram syntax from the model is repaired before you see it. - **Drop in the real material.** PDFs (including very large ones), Word, Excel, PowerPoint, images and packet captures go straight into context. - **Keep the conversation.** Threads persist, fork and resume weeks later, and Ziya tells the model what changed in the project while you were away. When a thread gets long, fork it or hand it off with an editable summary; the continuation keeps a link back, so the model can go read what it's missing instead of forgetting it. - **Point it at a terminal, not just a repo.** `ziya shadow ssh prod-42` wraps a terminal so a chat can read what happened there, and, if you allow it, run commands there under the same allowlist, with a confirm keystroke at that terminal for anything that writes. - **Use any model, and switch mid-thread.** Bedrock, Anthropic, OpenAI, Gemini, z.ai, or a local model through Ollama or LM Studio with no cloud account at all. - **Trust what the tools report.** Tool results are signed and fabricated tool output is rejected. Safe work runs without prompts, and anything riskier needs a signed approval the model can't produce. `pip install ziya`, then run `ziya` in your project and open `localhost:6969`. [Quick start](#quick-start) · [Coming from another tool?](#coming-from-another-tool) · [Design Philosophy](Docs/DesignPhilosophy.md) --- ## Why Ziya Most AI tools make you pick one of two halves. A chat UI gives you a comfortable browser window and any model you like, but it only sees the files you upload, and it can show you a change without being able to make it. A coding agent can edit your files, but it lives in one terminal or one editor sidebar, runs one thread at a time, and forgets everything when you close it. **Ziya is both halves in one local tool.** It reads your project straight from disk, proposes changes as diffs you apply with a click, runs shell tools, draws the answer as a diagram when a diagram is the answer, and keeps every conversation so you can pick it back up next month. It runs on your machine with your model and your credentials. No account, no telemetry, MIT licensed. People who try it tend to say it doesn't fit the existing categories, and the reason is the interaction itself rather than any one feature: every turn can come back as text *and* a rendered picture, several threads run at once with the ones you set aside kept for you, and the same model behaves differently here than in a plain chat because the prompt around it was built for the way it actually works. It is closer to a workbench than to a chat window or a terminal agent. **It's built for how you actually work: on many things at once.** If your day is a dozen threads in flight, a migration in one, a production investigation in another and a design doc in a third, Ziya is organised around that instead of fighting it. Background work tells you when it's ready, nothing you set aside gets lost, and a thread you haven't touched in months picks up where it left off. See [Working on a dozen things at once](#working-on-a-dozen-things-at-once). **It has been used hard.** Two years and several thousand hours of development, and hundreds of engineers at a large technology company use it every day. The diff engine is hardened against the patches models actually write, including miscounted hunk headers, drifted context and half-applied changes, so click-to-apply works on real output and not just on tidy examples. The tool layer assumes the model will sometimes make things up: every tool result is cryptographically signed, and when the model pretends it ran a tool, Ziya catches it and rejects the output before it can poison the rest of the session. **It's built for big, long, messy work.** A 10,000-page PDF, a very deep repository or a large packet capture is normal input. Open several windows on the same conversation, each with its own files in context or its own model answering. Send a long job to the background, keep working, and get notified when it's done. Mute a turn that went nowhere and it stops costing tokens without disappearing. A hundred-turn session stays coherent because nothing is summarised away behind your back. **It stays out of your way.** It isn't an editor and doesn't want to be one. Keep the editor you have, and use Ziya next to it for the work that doesn't fit in a sidebar: architecture, long investigations, reviewing diffs, visual debugging, and reading the documents and captures that explain the code. Safe operations run without prompting, so the few approval requests you do see are worth reading. **It's a good base for experiments.** The interface wasn't copied from an IDE plugin, a chat window or a plan/act wizard. It was designed for this kind of work over two years. That makes Ziya a practical base for trying your own ideas about agents, memory and context curation. Providers, MCP servers, skills and plugins all plug in without forking the core. If you want to know whether Ziya fits the way you think, [Design Philosophy](Docs/DesignPhilosophy.md) will tell you more than the feature list. It also explains why this scaffolding is worth building even though future models will absorb some of it (*On the Bitter Lesson*). Ziya started as a usable front end for AWS Bedrock. Contributors are listed in [CONTRIBUTORS.md](CONTRIBUTORS.md). --- ## Working on a dozen things at once Ziya doesn't make you choose one way to organise parallel work. Open a new browser window for each project, or for each thread inside a project. Run a separate server per project if you want them fully apart. Or keep everything in one view: the thread you're working in up front, with your other active threads and background tasks visible beside it, so you always know what's still running and what you can go back to. So you can follow a thought as far as it goes. When a second idea pulls you in another direction, start that one too, and then a third, and keep stacking them. Each runs on its own. You get a green check mark when one finishes or needs more input from you, and the mark stays until you look at it. Leave a side task running, forget about the whole project for two months, and when you come back the marks are still there: here's what Ziya finished for you since your last input, and here's what's waiting for a decision. Nobody follows every branch, and Ziya doesn't expect you to. It keeps track of the roads you don't take. When a conversation forks into sub-tasks, or you set something aside, it records that branch in a background task tree, so you have a backlog to go back through and pick up the things you forgot about. Long threads don't end in amnesia. When a conversation gets heavy, or you want to chase a tangent, you fork it: the fork knows where it came from. When context pressure gets high, Ziya starts maintaining a handoff summary you can read and edit, and the next segment opens with it plus a link back to the segment it replaced; the model can search and read its predecessors (and any other conversation you point it at) when the summary turns out to be missing something. Mute what no longer matters to reclaim room. The author runs conversations to the model's full context window and then prunes or forks, on projects with well over ten thousand conversations, and has deleted almost none of them in two years. Coming back months later works because Ziya tracks the files each conversation works with: the ones in its context, plus every file it writes. A small file the conversation changes joins its context automatically; a large one is tracked without its content, and the model is told when it changes on disk. Reopen an old thread and the model is told how long it's been, which of those files you've changed in the meantime, and so whether the changes you talked about were applied, without rewriting any of the conversation. (A file the conversation neither holds nor wrote isn't tracked; add it to context if you want the model to notice what happens to it.) It can also search your other conversations and your persistent memory, so if you worked out a better version of an idea somewhere else and it never made it into this code, that work is still within reach. --- ## What's actually in it **Long answers don't get guillotined.** Every model has an output ceiling, and the usual failure mode is a response that stops mid-function or mid-table with no way forward but "continue" and a prayer. Ziya detects when a generation is about to hit the limit, rewinds to the last clean break point — never splitting a code block, a table, or a markdown structure down the middle — and continues seamlessly from there, so a long refactor or a big generated document comes back whole instead of truncated. You get the complete answer without babysitting it across the boundary. **Every serious model, and you switch mid-conversation.** Claude, GPT and the o-series, Gemini, Nova, DeepSeek, Qwen, Kimi, MiniMax, GLM, Llama, Mistral — across AWS Bedrock, Anthropic, OpenAI, Google, and z.ai, or anything local through Ollama. You're not picking one at setup and living with it: change models in the middle of a thread and Ziya rebuilds the agent chain around the new one, so you can reason with a frontier model and hand the grunt work to a cheap one *in the same conversation*. Thinking and reasoning effort are per-request dials, not account settings. And on models that support it, prompt caching is wired through with live cache-hit tracking — long stable contexts get replayed from cache instead of re-billed and re-processed every turn, which is what makes hundred-turn sessions economical instead of eye-watering. **The prompt is built for the model that's answering.** There is no single system prompt. It is assembled per request from the endpoint, the model family, the specific model version, the tools actually available on this install, the active skills, and the state of the conversation, so per-release quirks are handled where they arise instead of leaking into every session. Alongside it, Ziya does quiet post-prompting and inline hinting the model is told not to comment on: what changed in a file since the last turn, that a diff it cited was never emitted, that it is narrating a tool call instead of making one. New users notice this before they can name it: the same model feels different here than in a bare chat or a terminal agent. **Context you control, so auto-compaction is never necessary.** You pick which files are in context from a tree, fork to explore alternatives, and drop files when you're done. The piece that makes long sessions work: mute any turn that's no longer relevant — a debugging detour that dead-ended, a file dump you've moved past — and it stops counting against your token budget *without being lost*. It's still there, still searchable, one click from being folded back in; it just isn't spent on the model anymore. That's how you reclaim your own context space deliberately, instead of letting a recency-weighted compactor silently throw away the early messages that established the whole objective. Sessions run comfortably past thirty, fifty, a hundred turns without the degradation people warn about, because nothing important gets summarized away behind your back — you decide what still matters, turn by turn, and the machine never guesses. **Inline visualizations.** Ten-plus renderers — Mermaid, Graphviz, Vega-Lite, DrawIO, D3, JointJS, KaTeX, HTML mockups, packet frame diagrams, and more, plus a pluggable server-side LaTeX path for circuits, chemistry, plots and music notation — each with a preprocessing pass that fixes the broken syntax models tend to produce. The model picks the format. A deadlock investigation comes back as a dependency graph showing the cycle. A queueing-theory question comes back as derivations in typeset math plus a chart of arrival rate vs. queue depth. A protocol question comes back as a bit-level frame layout. It turns out the right answer is visual surprisingly often, once visual is actually possible without leaving the conversation. On macOS, with the optional drag extra installed, a rendered diagram or table can be dragged straight out of the chat and dropped into Slack as an image. **It reads your real documents, not just your code.** Drop in a PDF, a Word doc, an Excel sheet, a PowerPoint deck, an image, or a packet capture and Ziya extracts it into context — no conversion step, no separate uploader. Scanned PDFs are rendered to page images and handed to vision-capable models, and very large PDFs get a local page-level search index so the model can pull the right pages instead of drowning in the whole file. This is what "point it at your material" actually means: the architecture review reads the design doc, the data question reads the spreadsheet, the network investigation reads the capture — all in the same conversation. **Many things in flight at once.** The conversation is the durable thing, not the window. Attach several windows to the *same* conversation — each with its own active file context, each pointed at a *different* backend provider — and move between them freely; which model answers next is decoupled from where you're sitting. Open a Claude window and a GPT window on the same thread and let them take turns. Multiple windows naturally carry different conversations and projects, and jumping between them is cheap because context travels with the conversation, not the window. Fire off long-running work in the background, keep working on something else, and get notified the moment a thread is ready for you — then drop straight back into its full context. The cumulative effect is a working surface that assumes you have several lines of inquiry going at once and refuses to make you serialize them. **Set it down for a month. Pick it up like you never left.** Because conversations are the durable artifact, you can walk away from a thread for weeks and come back to it whole — every message, every file, every visualization still there. And it doesn't just remember: when you return, Ziya diffs your project against where it was when you last spoke and tells the model *what changed in the meantime* — which files moved, what's new, what was edited — so you don't waste a turn re-explaining. The same bookkeeping runs between every turn, not only after a long absence: every message carries a timestamp, and the code in context is annotated line by line with what changed since the conversation began and since the previous turn, so the model can tell "the user edited this" from "I suggested this and it was never applied". You resume the thought; the harness handles the "here's what's different since." Few tools let you abandon a line of work and rejoin it a month later without friction; this is one that does. **The conversation is editable, not append-only.** Every thread is something you can operate on, not just scroll. Fork a conversation at any point to chase a "what if" down a branch without losing the trunk. Edit any past message and resubmit — rewrite a bad prompt in place instead of starting over or letting the mistake sit in context forever. Export whole conversations to JSON or Markdown to archive, share, or hand off, and import them back. Everything persists locally across restarts, so nothing lives at the mercy of a browser tab. Treating history as mutable is what makes the long-running, high-turn sessions actually workable — you prune and redirect instead of accumulating cruft. **MCP tools, with paranoia about hallucinated results.** Standard MCP servers plug in. Tool results are HMAC-signed per session — unsigned results are rejected before the model sees them. The text stream is scanned for the model narrating tool execution instead of actually calling the tool, and when fabrication is detected the conversation is truncated and a corrective message is injected; after three strikes the stream ends. This sounds excessive until you've had a 30-turn session where one fabricated `ls` at turn 6 poisoned everything that came after. **Tool supply-chain defense.** MCP is a plugin ecosystem, which means it's an attack surface, and Ziya treats it like one. When a server connects, its tool definitions are scanned for prompt-injection patterns — instructions hidden in a tool's own description trying to exfiltrate files or hijack the model. Tools that shadow the names of already-trusted tools are flagged before they can impersonate them. And every tool is fingerprinted with a SHA-256 hash on first sight, so a server that quietly changes its tool definitions *after* you've come to trust it — the "rug pull" — gets caught instead of silently taking effect. You get the openness of a plugin ecosystem without blindly trusting every server in it. **Safe work is never gated — on purpose.** Ziya lets safe operations run without asking by default: reads, allowlisted shell commands, writes to scratch space, tools you've configured. That's a considered usability decision, not a gap. When a tool gates everything, people approve every prompt without reading it, or switch approvals off, and the gate stops protecting anyone. When safe work goes through without prompting, the rare approval request gets real attention. Anything past the safe floor (a new command, a wider write path) needs an out-of-band signed escalation the model cannot produce, so the prompts you do see are the ones worth reading. The reasoning is in [Design Philosophy](Docs/DesignPhilosophy.md#security-is-load-bearing). **Parallel agents, when warranted.** Large tasks can be decomposed into a swarm of delegates with dependency ordering, memory crystals between them, and crash-resilient checkpointing. The delegate system currently requires an AWS Bedrock endpoint. Current models can't stay on task indefinitely, so this is mostly useful for legitimately parallelizable work — multi-module migrations, large test sweeps, broad refactors. It's not a substitute for the user holding the plan in their head; it's a way to fan out the parts that are clearly fan-outable. **Task cards for durable cross-session work.** Composable Task / Repeat / Parallel blocks anchored to a chat. Launch one, navigate away, come back hours or days later — the conversation list shows a distinct gear affordance for "task running", the inspector replays the full event history (not just what arrived after you returned), and an audit-trail snapshot records exactly what permissions the run was launched with so a failed task is reconstructable after the fact. Each block carries its own scoped writable paths, allowed tools, and shell grants, surfaced in the agent's prompt so it knows what it can do before it tries; in interactive chat the shell allowlist is global, but a card can grant per sub-task, and any grant above the safe floor has to be signed out of band. Cards can run on a schedule or headless from the command line (`ziya task`), which is how a nightly report gets produced without anyone watching, and they export as a portable JSON file so a card written against one project can be handed to someone else. A loop can also be marked *self-improving*: between iterations a judge looks at the outcome and, if a concrete improvement to the task text exists, revises it and records the lesson. The author uses this on Ziya itself: a card walks every diagram renderer, generates deliberately difficult inputs for each, records what failed to render or rendered wrong, clusters the failures, writes the test cases, and fixes them. **Memory that earns its place.** Ziya extracts durable facts from your conversations and carries them across sessions — but nothing lands in long-term memory unquestioned. The model proposes; you approve, or a fact sits on probation until it has proven itself by being useful, and extraction, collation and de-duplication run as separate passes on different timescales, so memory sharpens over time instead of silting up with noise. Give it a few cycles and it starts surfacing the related thing you should have considered, unprompted. It's stored locally, and it can be encrypted at rest through the enterprise security layer. **It can watch your terminals, and drive them if you let it.** `ziya shadow` wraps any terminal — your shell, or `ssh prod-42` — in a transparent PTY and journals it locally, with passwords masked and known credential shapes redacted before anything touches disk. Nothing is installed on the far end; the observation is of your own authorised session. A chat can then read that terminal ("why did that deploy fail?"), be attached to it so the terminal shows who is watching, and, on a session started with `--allow-control`, run commands in it under the same allowlist that governs the local shell: read-only diagnostics flow, anything that writes or is off the list asks for a keystroke at the terminal itself, and the human can revoke control at any moment. One conversation can hold several terminals at once and compare what they say. The chat cannot approve its own requests; the person at the terminal is the authority. **Skills and beads.** Skills are reusable instruction bundles — standing expertise you mix and match per conversation, scoped to a project so the right context loads itself. Beads are a lightweight, always-on task tree the harness keeps in the background: when a conversation forks into sub-tasks or you set a thread aside, beads remember the branches you haven't followed yet, so nothing quietly falls on the floor when you're juggling ten things. **Enterprise-grade plugin architecture.** Ziya has a clean open-core / closed-plugin split with defined extension points for policy enforcement, encryption, and access control. With no plugins present every hook is a no-op and the open-source tool is fully functional — nothing is crippled or held back. When an organization needs governance — application-level encryption of memory and session data, policy gates on tools, access controls — the same hooks let closed-source plugins layer it on without forking the core. This isn't theoretical: it's the architecture that lets hundreds of engineers run Ziya inside a company that takes security seriously. Ziya itself ships no web-tier login or user authentication — the local API trusts the host process's credentials — so access control is one of those closed-plugin extension points, not a built-in feature. **Open and extensible by construction.** Providers are abstracted behind a clean boundary, so bringing a new model is small, isolated work rather than surgery. Model behavior lives in a declarative config — token limits, output caps, vision, thinking/reasoning, context caching, and model family are capability flags, not scattered special cases — and each provider is a thin wrapper implementing one interface. Adding a model is usually a config entry; adding a whole provider is a wrapper plus a config block, with nothing else in the harness needing to know. The same openness runs through the rest of the system: MCP servers plug in, skills are drop-in instruction bundles, and the plugin hooks let closed-source extensions layer on without touching the core. It's architected so the harness keeps up with a field that changes every few weeks. **Code intelligence.** AST indexing with cross-file reference tracing, symbol search, and importer/caller queries — used both directly through the UI and as tools the model can call, so "who calls this?" and "what breaks if I change this signature?" are answered from a real index rather than guessed. **Same backend in browser and terminal.** The web UI at `localhost:6969` is the primary surface, but the CLI shares everything: `ziya chat` for an interactive session, `ziya ask "explain this"` for one-shots, `ziya review --staged` for git review, `git diff | ziya ask "review this"` to pipe in arbitrary input, `ziya task --card