Metadata-Version: 2.5
Name: zad-cli
Version: 0.1.0
Summary: Make clearing your coding agent's context safe: persist the plan, decisions, dead ends and constraints that the code cannot describe.
Project-URL: Homepage, https://github.com/e7aiq/zad
Project-URL: Repository, https://github.com/e7aiq/zad
Project-URL: Issues, https://github.com/e7aiq/zad/issues
Project-URL: Changelog, https://github.com/e7aiq/zad/blob/main/CHANGELOG.md
Project-URL: Documentation, https://github.com/e7aiq/zad/blob/main/docs/schema.md
Author: zad contributors
License: MIT License
        
        Copyright (c) 2026 zad contributors
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: claude-code,coding-agent,context-window,cursor,developer-tools,handoff,llm,tokens
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Documentation
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.9
Provides-Extra: tokenizer
Requires-Dist: tiktoken>=0.5; extra == 'tokenizer'
Description-Content-Type: text/markdown

<div align="center">

# zad

**Make clearing your coding agent's context window safe.**

[![CI](https://github.com/e7aiq/zad/actions/workflows/ci.yml/badge.svg)](https://github.com/e7aiq/zad/actions/workflows/ci.yml)
[![Python](https://img.shields.io/badge/python-3.9%20%7C%203.11%20%7C%203.13-blue)](https://github.com/e7aiq/zad)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](https://github.com/e7aiq/zad/blob/main/LICENSE)
[![Runtime dependencies](https://img.shields.io/badge/runtime%20dependencies-0-brightgreen)](#guarantees)
[![Tests](https://img.shields.io/badge/tests-464%20passing-brightgreen)](https://github.com/e7aiq/zad/tree/main/tests)

[Quick start](#quick-start) · [How it works](#how-it-works) · [Any agent](#any-agent) · [Case study (العربية)](https://github.com/e7aiq/zad/blob/main/CASE-STUDY.ar.md) · [Portfolio write-up](https://github.com/e7aiq/zad/blob/main/docs/portfolio.ar.md)

</div>

---

Coding agents are stateless. Every turn resends the entire conversation, so cost
grows quadratically and answers get worse as the window fills. The fix is to
clear the context — but clearing destroys everything the agent learned.

`zad` makes clearing safe. It keeps one plain Markdown file in your repository
holding the four things a `/clear` would otherwise delete forever: the plan, the
decisions, the approaches that already failed, and the constraints you stated out
loud but never wrote down.

It stores nothing else. Not the architecture, not the file layout, not what your
functions do — the agent re-reads all of that from the repository for free.

```bash
pipx install zad-cli
```

> **بالعربية:** [دراسة الحالة التقنية](https://github.com/e7aiq/zad/blob/main/CASE-STUDY.ar.md) — القرارات المعمارية
> والأخطاء والأرقام المقيسة · [رحلة البناء](https://github.com/e7aiq/zad/blob/main/docs/portfolio.ar.md) — سرد المشروع
> من المشكلة إلى النشر.

---

## Before

The ritual, every time the context filled up:

1. Notice the agent is repeating itself and the replies are getting worse
2. Scroll back and try to remember which decisions actually mattered
3. Type a summary into the chat and hope it covers the dead ends
4. `/clear`
5. Paste the summary back and spend three turns re-explaining what it left out

Step 3 is where the loss happens. You remember what you built. You do not
remember, at 1 a.m., the thing you tried at 11 p.m. that did not work.

## After

```bash
zad handoff     # prompt is on your clipboard — paste it, then /clear
```

The agent updates `.ctx/handoff.md` itself and you clear with nothing lost. The
file is committed, so it survives the session, the machine, and you.

---

## Quick start

```bash
pipx install zad-cli
cd your-project
zad init
```

The distribution is `zad-cli` because `zad` was already taken on PyPI by an
unrelated DNS tool. The command you run is `zad`.

`zad init` finds your agent instruction files (`CLAUDE.md`, `AGENTS.md`,
`.cursorrules`, `.cursor/rules/`, `.github/copilot-instructions.md`), appends one
marker-delimited block telling the agent to read the handoff first, and creates
`.ctx/handoff.md`. It never touches a byte outside its own markers, and running
it twice changes nothing.

Then, whenever the window is filling up:

```bash
zad status      # how full is it, and what is filling it
zad handoff     # copy the prompt, paste it, /clear
```

That is the whole tool. Four commands, one of which you will never run:

| command | what it does |
| --- | --- |
| `zad init` | wire zad into this repo's agent instruction files |
| `zad status` | measure the current session — read-only, changes nothing |
| `zad handoff` | put the update prompt on your clipboard |
| `zad uninstall` | remove the marker block; leaves `.ctx/` alone |
| `zad adapters` | what zad can read on this machine, and how to teach it more |

---

## The file

`.ctx/handoff.md`, committed to your repository, hand-editable:

```markdown
# zad handoff
<!-- generated by zad — safe to edit by hand -->

## Plan
- [x] 1. Authentication
- [ ] 2. Authorization  <- current
- [ ] 3. Audit log

## Decisions
- JWT over server sessions — frontend is decoupled
  Rejected: server sessions (complicates deployment)

## Never again
- Pre-indexing on boot — added 12s to startup
- Roles inside the token — grows unbounded

## Constraints
- Do not change the folder structure
- Node 18, no upgrade
```

Four sections and no schema beyond that. Add your own sections, prose or notes;
zad carries anything it does not understand through untouched. Full details and
the format guarantee are in [docs/schema.md](https://github.com/e7aiq/zad/blob/main/docs/schema.md).

---

## How it works

**The code describes itself.** That single idea is why zad is a few thousand
lines instead of a platform.

After a context clear, the agent re-reads your repository. It recovers the
architecture, the module layout, the function signatures, the test names, the
dependency list — every "what exists" fact — at no cost to you, because it was
going to read those files anyway. Writing any of that into a handoff file means
paying tokens to duplicate something already available for free, and then paying
again to keep the duplicate current.

So zad refuses to store it. What is left is exactly the set of things the
repository cannot tell you:

- **the plan** — done and next. Git history shows what changed, not what is next.
- **the decisions** — and the alternatives that were rejected. The code shows JWT;
  it does not show that server sessions were considered and why they lost.
- **the dead ends** — the expensive one, see below.
- **the constraints** — "Node 18, no upgrade" lives in your head and in one
  message from three weeks ago.

### The append-only rule

Negative knowledge — *we tried X and it failed* — exists in no file anywhere.
The failed attempt was deleted. The branch was thrown away. The code that
remains describes only what worked.

That is why an agent, an hour after a clear, proposes with total confidence the
exact approach that failed at lunchtime, and why you pay for that discovery
twice.

So the **`## Never again` section is append-only**. Nothing in zad removes,
edits, reorders, deduplicates or summarises an entry there. Not `merge()`, not
`init`, not any other code path. `merge()` verifies the invariant on its own
output and refuses to write if it was ever violated. There is a test named after
it. The generated prompt tells your agent the same thing in capital letters.

Only you, editing the file by hand, can take a line out. That is your call to
make, not the tool's.

---

## `zad status`

Read-only measurement of the session you are in right now.

```
zad status — claude-code
  session  ad1fd7d2-49a1-4221-8031-4667b6f2a98e
  project  /Users/macbook/Desktop/زاد-حل ازمة نافذة السياق

Context      309,273 tokens  ████████████████████ 155% of 200,000
             exact — reported by the API for the last turn
             over the assumed window — pass --window to match your model
Growth       +1,595 tokens per turn over 163 turns

Breakdown    estimate (tiktoken o200k_base)
  conversation     102,698   76.0%
  thinking          11,464    8.5%
  tool output       20,991   15.5%
  total            135,153
  this covers the message text in the transcript only. The system prompt, tool
  definitions and anything the transcript does not record are not in it, which is
  why this total is smaller than the context figure above.

Arabic       3,965 Arabic characters (measured on the first 400k characters)
             tiers are cumulative in order; zad changes nothing
  tier 1 safe           invisible and legacy characters        87 found  ~70 tokens
  tier 2 judgment call  letter unification                    322 found  ~0 tokens
  tier 3 risky          diacritic removal                     211 found  ~226 tokens

→ '4. `zad status` and the session adapter layer' is done and context is about
  155% full — this might be a good place to run 'zad handoff' and /clear before
  starting '5. `zad handoff` and release readiness'
```

*Real output, from zad measuring the session that built zad. The per-tier caveat
lines are elided here for width; the tool always prints them.*

It also reports files read more than once with no change in between (content
hash comparison, so an edit makes a re-read legitimate), and `--json` for
scripting.

`status` is the only command that reads anything outside your repository, and it
never writes. If no supported agent is installed it says so and exits 0.

### It will not guess

Transcript formats are undocumented and change without notice, so zad scores how
much of one it actually recognised and shows the evidence. It prints token
numbers only when a **verified field mapping** recognised the file — a mapping a
person checked against a real installation on a date recorded in the descriptor.

Otherwise it tells you what it found, says plainly that it is unverified, and
stops. No numbers, in the text output or in `--json`, where the measured keys are
absent rather than null so a script cannot read a zero and believe it.

A wrong context size is worse than no context size, because you act on it.

### Any agent

What zad knows about a format is a **JSON descriptor**, not code. Adding an agent
is a JSON file dropped in `~/.config/zad/adapters/` — no Python, no fork, no
release. Claude Code ships verified; a shape-inference fallback reads transcripts
nobody has described yet, well enough to tell you they are there.

```bash
zad adapters list      # what zad knows, and when each mapping was verified
zad adapters detect    # where zad looked, and what was actually there
zad adapters report    # anonymized structure to paste into an issue
```

`zad adapters report` describes the *shape* of your transcripts — key paths,
types, counts, string lengths — and never their contents. No messages, no file
paths, no code, no value strings at all. That is what makes it safe to paste into
a public issue, and it is checked by a test that fills a fixture with sentinel
values and asserts none of them survive.

Full schema and a worked example: [docs/adapters.md](https://github.com/e7aiq/zad/blob/main/docs/adapters.md).

### Arabic

Arabic costs about **2.5 characters per token** where English costs about 4.0
(measured over 1.4 MB of real transcripts against `o200k_base`; on `cl100k_base`
Arabic is 1.55). So the usual `len(text) / 4` estimate is accurate to within a
percent for English and **underestimates Arabic by 36%** — worse than useless for
the people whose windows fill fastest. zad estimates per script instead; on
held-out data its worst-case error is 3.4%. Method and numbers:
[docs/session-formats.md](https://github.com/e7aiq/zad/blob/main/docs/session-formats.md#tokenizer-calibration).

Invisible junk is correspondingly expensive, so `status` reports it — in three
tiers that are never merged into one number:

| tier | what | safety |
| --- | --- | --- |
| 1 | tatweel, presentation forms, zero-width marks, non-standard spaces | safe — renders identically |
| 2 | `أ إ آ ٱ → ا`, `ى → ي`, `ة → ه` | judgment call — changes spelling, wrong for proper nouns |
| 3 | diacritics | risky — meaningful in poetry, religious and ambiguous text |

There is deliberately no "optimize" button. A single figure across all three
tiers would be a button that quietly corrupts Quranic text to save tokens.
`status` reports; nothing in zad rewrites your text.

---

## Guarantees

- **Zero runtime dependencies.** Standard library only. `tiktoken` is the single
  optional extra (`pipx install "zad-cli[tokenizer]"`) and only `status` uses it.
- **No network. Ever.** No API keys, no model calls, no telemetry, no analytics.
  `zad handoff` calls no model — the agent in front of you *is* the model, and it
  already has the whole session in its context.
- **Python 3.9+**, macOS, Linux and Windows, tested on all nine combinations.
- **Never a traceback.** Failures print one line and exit non-zero.

Each of these is enforced by a test, not by good intentions:
`tests/test_constraints.py` walks the AST of every module to check the version
floor, the dependency list, and that no networking module is imported anywhere.

---

## Non-goals

zad is deliberately small. It is:

- **not a prompt compressor** — it does not rewrite, shorten or re-encode your prompts
- **not a memory database** — no index, no embeddings, no store; one Markdown file in your repo
- **not a RAG system** — it retrieves nothing and ranks nothing
- **not a proxy** — it sits nowhere in the request path and makes no network calls
- **not a project planner** — it records the plan you already have; it does not produce one

The value is in what it refuses to do. Every feature it does not have is context
it does not spend.

---

## Contributing

The most useful thing you can add is an adapter for another agent — Cursor,
Codex, Aider, Zed. `zad status` supports Claude Code today because that is the
only transcript format anyone has sat down and observed. See
[CONTRIBUTING.md](https://github.com/e7aiq/zad/blob/main/CONTRIBUTING.md).

MIT licensed. `zad` is Arabic for the provisions you pack for a journey.
