{"id":49972000,"url":"https://github.com/sanjeev23oct/zap","last_synced_at":"2026-05-26T09:01:13.591Z","repository":{"id":358603065,"uuid":"1240556206","full_name":"sanjeev23oct/zap","owner":"sanjeev23oct","description":"1. Skill-First Approach — Context That Earns Its Place Most AI coding agents front-load a massive system prompt every request — language conventions, architecture notes, team rules, API patterns, all of it, whether it's relevant or not. zap replaces that wall with a skill system: markdown files that are injected surgically, only when needed","archived":false,"fork":false,"pushed_at":"2026-05-26T07:45:42.000Z","size":2873,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-26T09:00:15.918Z","etag":null,"topics":["agentic","ai-agent","ai-coding","anthropic","cli","coding-assistant","developer-tools","llm","mcp","ratatui","rust","skill-system","terminal","tui"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sanjeev23oct.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-16T09:23:50.000Z","updated_at":"2026-05-26T07:42:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sanjeev23oct/zap","commit_stats":null,"previous_names":["sanjeev23oct/zap"],"tags_count":84,"template":false,"template_full_name":null,"purl":"pkg:github/sanjeev23oct/zap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanjeev23oct%2Fzap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanjeev23oct%2Fzap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanjeev23oct%2Fzap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanjeev23oct%2Fzap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sanjeev23oct","download_url":"https://codeload.github.com/sanjeev23oct/zap/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sanjeev23oct%2Fzap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33512326,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agentic","ai-agent","ai-coding","anthropic","cli","coding-assistant","developer-tools","llm","mcp","ratatui","rust","skill-system","terminal","tui"],"created_at":"2026-05-18T09:00:59.332Z","updated_at":"2026-05-26T09:01:13.573Z","avatar_url":"https://github.com/sanjeev23oct.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ⚡ zap\n\n\u003e An AI coding agent built in Rust — skill-first context injection, a hard security boundary, and a single binary with no runtime.\n\n```\n  ╭────────────────────────────────────────────────────────────────────╮\n  │                                                                    │\n  │   _____     _     ___                                              │\n  │    ___/    /_\\   | _ \\   fast AI coding agent  v0.12.5            │\n  │   /       / _ \\  |  _/                                            │\n  │  /_____  /_/ \\_\\ |_|                                              │\n  │                                                                    │\n  ├──────────────────────────────────────┬─────────────────────────────┤\n  │  model     claude-sonnet-4-6         │  Tips for getting started   │\n  │  backend   Anthropic API             │    Tab  ↑↓  autocomplete    │\n  │  mode      ask                       │    /          commands      │\n  │                                      │    /provider  switch LLM    │\n  │  ~/my-project                        │    /help      all commands  │\n  ╰──────────────────────────────────────┴─────────────────────────────╯\n```\n\n---\n\n## The Problem Every AI Coding Agent Has\n\nOpen any popular AI coding agent and inspect the raw request it sends to the LLM. You'll find hundreds — sometimes thousands — of lines of system prompt sent on **every single turn**, regardless of what you're actually doing.\n\nWe measured this. Here's what Gemini CLI and OpenCode send when you ask them to write a Spring Boot service vs. a React component — two completely different languages, frameworks, and conventions:\n\n| | Gemini CLI | OpenCode | zap |\n|---|---|---|---|\n| Spring Boot request | **4,096 tokens** | **2,003 tokens** | 1,889 tokens |\n| React request | **4,096 tokens** | **2,003 tokens** | 1,661 tokens |\n| Prompts identical? | ✅ Yes — same bytes | ✅ Yes — same bytes | ❌ No — different skill injected |\n| Java conventions in prompt? | ❌ None | ❌ None | ✅ 650 tokens |\n| React conventions in prompt? | ❌ None | ❌ None | ✅ 422 tokens |\n\n**Gemini CLI sends the same 4,096-token prompt for both.** The word \"java\" does not appear anywhere in its 68,410-character prompt file. Neither does \"react\", \"kotlin\", or any other language. The LLM writing your Spring Boot service and the LLM writing your React component receive identical instructions. ([source](https://github.com/google-gemini/gemini-cli/blob/main/packages/core/src/prompts/snippets.ts))\n\n**OpenCode uses a single static string constant** — `baseAnthropicCoderPrompt` — sent verbatim on every turn, every task type. Zero mentions of Java, TypeScript, Rust, Python, React, or any specific language. ([source](https://github.com/opencode-ai/opencode/blob/main/internal/llm/prompt/coder.go))\n\nThis isn't just waste. It's why these agents give inconsistent output — the model has no language-specific guidance, so it invents its own conventions turn by turn.\n\nzap sends a **different prompt for different tasks** — the Java skill fires for Spring Boot, the React skill fires for components — and a greeting costs 12 tokens, not 2,000–4,000.\n\n\u003e Full methodology, raw token counts, and source links: [`content/evidence/system-prompt-comparison.md`](content/evidence/system-prompt-comparison.md)\n\u003e Medium series: [Introducing ZAP — The Open-Source AI Coding Agent That Doesn't Bloat Your LLM Context](content/overview/medium.md)\n\n---\n\n## Context Quality is Supreme\n\nEvery design decision in zap follows one principle: **every token in the LLM's context window must earn its place.** Context that doesn't improve output quality is waste — it dilutes attention, burns budget, and produces inconsistent results.\n\nThis principle drives everything:\n\n| Mechanism | What it ensures |\n|---|---|\n| **Skill injection** | Only language- and task-specific guidance is sent, not a one-size-fits-all monolith |\n| **AST code index** | The agent knows what exists *before* it decides what to create — no blind writes |\n| **`/init` command** | Auto-generates project-specific context files so every session starts informed |\n| **Context files** | `ZAP.md`, `.zap/understanding.md`, `.zap/context.md`, `.zap/session_log.md` — maintained automatically, loaded on demand |\n| **Casual-turn detection** | Greetings cost ~31 tokens, not 2,000–4,000 |\n| **Lazy MCP** | Server tool schemas stay out of context until the model explicitly connects them |\n| **Token-cost display** | Every turn shows exactly what went into context — skills, message, system, and estimated $ |\n\n### What gets updated and when\n\nzap maintains four project context files, each updated at a specific time to keep the agent current without polluting the context window:\n\n| File | Updated when | What it contains | Loaded when |\n|---|---|---|---|\n| `ZAP.md` | `/init` (manual, once) | Project overview, build commands, architecture, do-not-touch list | Every session (on-demand) |\n| `.zap/understanding.md` | `/init` (manual, once) | Deep technical map: modules, data flows, patterns, constraints | Every session (on-demand) |\n| `.zap/context.md` | End of every session (auto) | Last session: goal, files touched, what's next | Session start (on-demand) |\n| `.zap/session_log.md` | Every session (auto) | History of all past sessions, indexed by date | On request (on-demand) |\n\nThese files are never pre-loaded into the context window — the model reads them *only when relevant*, using `read_file`. This means a session about fixing a typo doesn't pay the cost of loading the entire project architecture.\n\n### The result\n\n- **First session:** `/init` analyses your repo and bootstraps all project knowledge in ~30 seconds\n- **Returning sessions:** The agent already knows what you were working on, which files changed, and what was left unfinished\n- **Every turn:** Skills inject only what's relevant, the index tells the agent what exists, and casual messages skip the overhead entirely\n\n---\n\n## What makes zap different\n\n### 1. Skill-First Approach — Context That Earns Its Place\n\nMost AI coding agents front-load a massive system prompt every request — language conventions, architecture notes, team rules, API patterns, all of it, whether it's relevant or not. zap replaces that wall with a **skill system**: markdown files that are injected surgically, only when your message triggers them.\n\n**Two kinds of skills:**\n\n| Kind | When injected | Example |\n|---|---|---|\n| **Always-on** | Every turn, baked into the base system prompt | `karpathy-guidelines` — Andrej Karpathy's 4 coding principles |\n| **Triggered** | Only when your message matches keywords | `rust` fires on \"cargo\", \"fn \", \"trait \"; `git` fires on \"commit\", \"push\" |\n\n**Built-in skills** (compiled into the binary, zero config):\n\n| Skill | Type | Triggers on |\n|---|---|---|\n| `karpathy-guidelines` | always-on | every turn |\n| `rust` | triggered | rust, cargo, crate, async fn, clippy… |\n| `python` | triggered | python, pip, pytest, dataclass… |\n| `typescript` | triggered | typescript, tsx, interface, npm… |\n| `react` | triggered | react, component, jsx, hook, useState… |\n| `go` | triggered | go, goroutine, chan, go.mod… |\n| `git` | triggered | commit, branch, merge, pull request… |\n| `code-review` | triggered | review, pr review, lgtm, critique… |\n| `debugging` | triggered | debug, error, crash, panic, stacktrace… |\n| `security` | triggered | auth, password, token, jwt, xss, sql injection… |\n\nStack auto-detection fires the right language skill on startup — Rust project with `Cargo.toml` gets the `rust` skill loaded automatically.\n\n**Example** — a Rust project, custom `api-conventions` skill also loaded:\n\n| You type | Skills injected | Base + skills |\n|---|---|---|\n| `\"refactor this async fn to use channels\"` | karpathy + rust | ~2.4k tokens |\n| `\"commit these changes\"` | karpathy + git | ~2.0k tokens |\n| `\"add a new REST endpoint\"` | karpathy + api-conventions | ~2.2k tokens |\n| `\"explain what this function does\"` | karpathy only | ~1.8k tokens |\n\n\u003e **Honest baseline:** the always-on karpathy-guidelines skill and the base system prompt together run ~1.8k tokens — much leaner than Claude Code (~10k) or Gemini CLI (~8k), but not the \"200 token\" figure you might see in older docs.\n\n**Custom skills override built-in ones** of the same name. Write a skill once and zap injects it exactly when needed:\n\n```markdown\n---\nname: api-conventions\ndescription: REST endpoint conventions for this project.\ntrigger: [\"endpoint\", \"route\", \"handler\", \"REST\"]\ntokens: ~400\n---\nAll endpoints must validate input with ValidateRequest(), return structured\nerrors as {\"error\": \"...\", \"code\": N}, and use snake_case JSON keys.\n```\n\n**Always-on skill** (no `trigger:` field — injected every turn):\n\n```markdown\n---\nname: our-principles\ndescription: Team engineering principles.\n---\nWe ship small, reversible changes. Every PR needs a test. No console.log in prod.\n```\n\n**Where to put them:**\n\n| Path | Scope | Priority |\n|---|---|---|\n| `.zap/skills/` | project — check into git, team-shared | highest |\n| `~/.zap/skills/` | personal — all projects | middle |\n| binary | built-in defaults | lowest |\n\nOn first launch zap writes all built-in skills to `~/.zap/skills/` automatically — open any file there to read or edit it. Same-name files you create override the built-in version on the next run.\n\n```\n/skill list              # see all skills with source and always-on/triggered label\n/skill show \u003cname\u003e       # preview content + description + license\n/skill export \u003cname\u003e     # re-export a built-in to ~/.zap/skills/ (if you deleted it)\n/skill export --all      # re-export every built-in skill\n/skill create \u003cname\u003e     # scaffold a new skill in .zap/skills/\n/skill capture \u003cname\u003e    # extract instructions from this session into a reusable skill\n```\n\n---\n\n### 2. AST Code Index — Understands Your Code, Not Just Text\n\nMost agents navigate code the same way a shell script does — grep for a string, hope the result is what you meant. zap builds a real **AST symbol index** at startup using tree-sitter + SQLite, giving the model genuine structural understanding of your codebase.\n\n#### The problem: agents that write without looking\n\nAsk most coding agents to \"add all the API layers for user management\" in an existing project and you'll see a predictable set of mistakes:\n\n- **Duplicate files created** — `src/user_repository.rs` already exists, but the agent creates `src/repositories/user_repo.rs` alongside it because it never checked\n- **Existing patterns ignored** — the project uses a `Repository\u003cT\u003e` trait with a specific error type; the agent invents its own DB access style from scratch\n- **Scaffolding over existing code** — `src/routes/`, `src/models/`, `src/db/` already exist with boilerplate; the agent recreates them\n- **Missed abstractions** — a `BaseRepository` or shared `AppError` type already exists; the agent writes a duplicate\n\nThese aren't model failures — they're context failures. The agent is writing blind because its context window never contained the files it needed to check.\n\n#### How the index fixes it\n\nWhen you ask zap the same question, before writing a single line it queries the index:\n\n```sql\n-- Does a user repository already exist?\nSELECT path, line, kind FROM symbols WHERE name LIKE '%UserRepo%' OR name LIKE '%UserStore%';\n\n-- What repository pattern does this project use?\nSELECT name, path, line, signature FROM symbols WHERE kind = 'trait' AND name LIKE '%Repository%';\n\n-- What's already in the db/ directory?\nSELECT name, kind, line FROM symbols WHERE path LIKE '%/db/%' ORDER BY path, line;\n```\n\nThis runs in milliseconds against the local SQLite index — no file reads, no grep, no context stuffing. The model knows what exists before it decides what to create. It adds to `src/user_repository.rs` instead of creating a new one. It implements the existing `Repository\u003cT\u003e` trait instead of inventing a new pattern.\n\nWhen you ask zap to \"refactor the `UserStore` struct\", it doesn't search for the string `\"UserStore\"` — it looks up the symbol in the index, finds the exact file and line number, reads only that section, and makes a precise edit. No false matches, no reading entire files to find one function.\n\nThe index is **incremental** — on subsequent runs, only files that changed since the last session are re-parsed. A background indexer runs every 120s during interactive sessions so the index stays fresh as you edit. Cold-indexing a 50k-line repo takes a few seconds; warm starts are near-instant.\n\n**Always current during edits** — every time zap writes a file, it immediately reindexes that file before the next LLM turn. The model never queries a stale index for files it just changed.\n\n**Index usage is logged per turn** — every time a tool call is answered by the index (rather than falling back to grep), zap logs it to `~/.zap/zap.log` and `~/.zap/audit.jsonl`:\n\n```\n[INDEX] hit · find_definition · 'UserRepository' · 3 result(s)\n[INDEX] hit · code_map · 'src/db/' · 42 symbol(s)\n[INDEX] miss · find_definition · 'legacy_fn' · grep fallback\n```\n\nThis makes it auditable — you can see exactly when the index was used vs. when the agent had to fall back to text search.\n\n**Supported languages:** Rust, Python, TypeScript, JavaScript, Go, Java\n\n**Powered tools:**\n\n| Tool | What it does |\n|---|---|\n| `code_map` | Structural outline of any file or directory — functions, structs, classes, enums, with line numbers |\n| `find_definition` | Jump directly to where a symbol is defined — AST index first, ripgrep fallback |\n| `find_references` | Every call site of a symbol across the entire codebase |\n\nThe model is instructed to always use `code_map` or `find_definition` before reaching for `read_file` — so it reads only the lines it actually needs, not whole files.\n\n**How the index powers every LLM turn:**\n\n```\nYou: \"refactor the UserStore struct\"\n\n  zap (tool call)  →  find_definition(\"UserStore\")\n  SQLite index     →  src/db/user_store.rs:42  ← instant, no file scan\n  zap (tool call)  →  read_file(\"src/db/user_store.rs\", offset=40, limit=60)\n  zap (tool call)  →  edit_file(...)            ← precise edit, right lines\n\nWithout index: grep entire repo → read 3 wrong files → hallucinate location\nWith index:    SQLite lookup → read 20 lines → done\n```\n\nEvery index hit is logged so you can see exactly when the index was used vs. when the agent fell back to search:\n\n```\n[INDEX] hit  · find_definition · 'UserStore'    · 1 result\n[INDEX] hit  · code_map        · 'src/db/'      · 38 symbols\n[INDEX] miss · find_definition · 'legacy_fn'    · grep fallback\n```\n\n**Code quality report** — the same SQLite index powers `/index quality`, a human-readable health report run directly in the TUI:\n\n```\nCode Health  ·  27 files  ·  1043 symbols  ·  ⚡ 74/100\n────────────────────────────────────────────────────────────\n\nFile sizes  (lines)\n────────────────────────────────────────────────────────────\n  ⚠ 2382  src/session/commands.rs    ████████████████████  37 sym\n  ⚠ 2266  src/tui/render.rs          ████████████████████  48 sym\n  ⚠ 1789  src/session/mod.rs         █████████████         45 sym\n  ⚡ 1177  src/tui/mod.rs             ████████\n  ·   527  src/tui/app.rs             ███\n  ·   312  src/code_index.rs          ██\n\n  ⚠ \u003e1000 lines   ⚡ 500–1000   · healthy\n\nGod objects  (\u003e15 methods — split candidates)\n────────────────────────────────────────────────────────────\n  Session                        45 methods  (mod.rs)\n  ToolRegistry                   18 methods  (tool_registry.rs)\n\nDead code candidates  (pub fn, ≤1 reference)\n────────────────────────────────────────────────────────────\n  export_skill                   (skill_manager.rs:599)\n```\n\nLine counts are read from disk; symbol counts and coupling metrics come from SQLite. Reference counts are computed in one O(source_size) pass at the end of every `/index` run — no call graph required.\n\n#### Why zap indexes when Claude Code deliberately doesn't\n\nClaude Code (Anthropic's own CLI) has **no built-in code indexing**. No tree-sitter, no SQLite, no ctags. It uses pure agentic search — grep + glob + read, chosen at runtime by the model. This was a deliberate, tested decision.\n\nBoris Cherny (Claude Code's creator) confirmed publicly that Anthropic built and benchmarked a RAG/vector-index approach early on and dropped it because agentic search won \"by a lot.\" The reasons:\n\n- Grep finds exact matches; embeddings introduce false positives\n- No index to build or maintain\n- Index drift — code changes constantly during editing sessions\n- Simpler architecture with fewer failure modes\n\n\u003e Sources: [Claude Code Doesn't Index Your Codebase — vadim.blog](https://vadim.blog/claude-code-no-indexing) · [Building Claude Code with Boris Cherny — Pragmatic Engineer](https://newsletter.pragmaticengineer.com/p/building-claude-code-with-boris-cherny) · [Official Claude Code docs](https://docs.anthropic.com/en/docs/claude-code/overview)\n\nThe community has noticed the gap — multiple open-source MCP servers exist to bolt indexing onto Claude Code:\n- [colbymchenry/codegraph](https://github.com/colbymchenry/codegraph) — tree-sitter + SQLite FTS5\n- [cocoindex-io/cocoindex-code](https://github.com/cocoindex-io/cocoindex-code) — AST-based search\n- [zilliztech/claude-context](https://github.com/zilliztech/claude-context) — vector search MCP\n\nAnd open feature requests asking Anthropic to add this natively: [#4556](https://github.com/anthropics/claude-code/issues/4556) · [#9277](https://github.com/anthropics/claude-code/issues/9277)\n\n**zap makes the opposite bet.** Agentic search solves semantic questions well (\"find code related to payment processing\"). A persistent AST index solves structural questions better — \"what already exists in this module?\", \"which files implement this pattern?\", \"is there already a `UserRepository`?\" These are exactly the questions that matter when an agent is about to *write* new code. Without an index, the agent can only search for what it knows to look for. With an index, it knows what exists before it decides what to create.\n\nThe two approaches solve different failure modes. Agentic search avoids index drift. AST indexing avoids blind writes into a codebase the agent hasn't fully read.\n\n---\n\n### 3. Built in Rust — One Binary, No Runtime\n\nzap is written entirely in Rust and ships as a single statically-linked binary.\n\n- **No Python venv.** No Node.js. No Docker. No dependency hell.\n- **Instant startup** — cold start in milliseconds, not seconds.\n- **Low memory footprint** — the process sits at ~20 MB idle.\n- **Memory-safe by construction** — no buffer overflows, no use-after-free, no data races.\n- **Compile once, run anywhere** — drop the binary on your PATH and it works.\n\n```bash\ncargo build --release\ncp target/release/zap ~/.local/bin/zap\n# that's it\n```\n\n---\n\n### 4. MCP Support — Lazy-Loaded, Cross-Agent Compatible\n\nMCP (Model Context Protocol) is an open standard. **Any MCP server you configure in zap also works in Claude Code, Cursor, Kiro, and other agents** — the config format is shared. zap adds two optional fields (`description`, `toolsHint`) that other agents silently ignore, so your config file is fully portable.\n\n#### Config file locations\n\n| File | Scope |\n|---|---|\n| `~/.zap/mcp.json` | Global — applies to every session |\n| `.mcp.json` (project root) | Project-local — checked into git, takes precedence |\n\n#### How lazy loading works\n\nMost agents connect to every configured server at startup and dump all tool schemas into the LLM's context on every turn. Ten servers × five tools each = 10 000+ wasted tokens per request, whether you use them or not.\n\nzap keeps every server in a **pending** state at startup. Instead of their tool schemas, the LLM gets one lightweight stub:\n\n```\nmcp_connect(server)\n  - filesystem: Read/write files in /tmp and the project  [tools: read_file, write_file, list_directory…]\n  - fetch: Fetch web pages as markdown                    [tools: fetch]\n  - memory: Persistent knowledge graph                    [tools: create_entities, search_nodes…]\n```\n\nWhen the LLM decides it needs a server, it calls `mcp_connect(\"filesystem\")`. zap spawns the process, runs the handshake, fetches the real `tools/list`, and registers those tools — all within the same agentic turn. The very next LLM call sees the full tool schema and can invoke the tools directly. Once a server is connected, `mcp_connect` no longer appears for it.\n\n| Stage | Other agents | zap |\n|---|---|---|\n| Startup | Spawns all server processes | Reads config only — zero processes |\n| LLM tool list per turn | All tool schemas, always | One `mcp_connect` stub until needed |\n| First use of a server | Already connected | Spawns process on demand, ~200 ms |\n| After first use | — | Real schemas in context, `mcp_connect` gone |\n\n#### Sample `~/.zap/mcp.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/tmp\", \"/home/user/project\"],\n      \"description\": \"Read and write files inside /tmp and the project directory\",\n      \"toolsHint\": \"read_file, write_file, edit_file, list_directory, search_files\"\n    },\n    \"fetch\": {\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-server-fetch\"],\n      \"description\": \"Fetch any URL and return it as clean markdown\",\n      \"toolsHint\": \"fetch\"\n    },\n    \"memory\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol/server-memory\"],\n      \"description\": \"Persistent knowledge graph — entities and relations survive across sessions\",\n      \"toolsHint\": \"create_entities, create_relations, search_nodes, read_graph\"\n    },\n    \"github\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol/server-github\"],\n      \"env\": { \"GITHUB_TOKEN\": \"ghp_your_token_here\" },\n      \"description\": \"GitHub repos, issues, pull requests, and code search\",\n      \"toolsHint\": \"create_issue, create_pull_request, search_code, list_commits\"\n    }\n  }\n}\n```\n\n#### Fields\n\n| Field | Required | Portable | Description |\n|---|---|---|---|\n| `command` | yes | yes | Executable to spawn (`npx`, `uvx`, `node`, absolute path) |\n| `args` | yes | yes | Arguments passed to the command |\n| `env` | no | yes | Extra environment variables (API keys, tokens) |\n| `description` | no | yes* | What this server does — shown in `mcp_connect` stub so the LLM knows when to connect it |\n| `toolsHint` | no | zap-only | Comma-separated key tool names — lets the LLM plan without connecting |\n| `disabled` | no | yes | Set `true` to skip this server entirely |\n| `autoApprove` | no | yes | Tool names to auto-approve (Claude Code convention, parsed but not yet enforced) |\n\n\\* `description` is a zap extension. Other agents that don't know the field simply ignore it.\n\n#### MCP commands\n\n```\n/mcp list              list all servers — connected, pending, or failed\n/mcp edit              open ~/.zap/mcp.json in $EDITOR\n/mcp edit project      open .mcp.json (project-level config)\n/mcp path              print both config file paths\n```\n\n#### Installing public MCP servers\n\nThe two most useful zero-config servers:\n\n```bash\n# filesystem — read/write local files (requires Node)\n# add to mcp.json: \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/your/allowed/path\"]\n\n# fetch — fetch any URL as markdown (requires Python + uv)\n# add to mcp.json: \"command\": \"uvx\", \"args\": [\"mcp-server-fetch\"]\n```\n\nBoth install automatically on first connect via `npx -y` / `uvx` — no manual `npm install` needed.\n\n---\n\n### 5. Security is a First-Class Concern\n\nzap handles your source code, credentials, and shell — so it treats security as a core feature, not an afterthought.\n\n#### The agent cannot execute anything destructive without your explicit approval\n\nIn the default `ask` mode, every write operation and shell command is blocked until you approve it. Read-only tools — `read_file`, `search_code`, `code_map`, `find_definition`, `git_status` — are never gated and run freely. Only the tools that can cause damage require your sign-off:\n\n| Tool class | Ask mode | Auto mode | Deny mode |\n|---|---|---|---|\n| `read_file`, `search_code`, `code_map`, `git_status` | ✓ always allowed | ✓ | ✗ blocked |\n| `edit_file`, `write_file`, `batch_edit` | prompt | ✓ | ✗ |\n| `shell` | prompt | ✓ | ✗ |\n| `spawn_agent` | prompt | ✓ | ✗ |\n\nWhen the model wants to run multiple tools in one turn, zap shows **one grouped prompt** covering all of them — you approve or deny the batch, not each individually.\n\n**\"Always\" grants** — type `always` once at a prompt and that tool class is auto-approved for the rest of the session. Granting `edit_file` also grants `write_file` and `batch_edit` — semantically identical operations share a grant class so you're not re-prompted for the same action with a different tool name.\n\n**Three modes, your choice:**\n\n| Mode | When to use |\n|---|---|\n| `ask` *(default)* | Any interactive session — you stay in control |\n| `auto` | Sandboxed CI, scripts, or headless runs where you control the environment |\n| `deny` | Completely read-only — the agent can read and reason but cannot write a single byte or run any command |\n\nSwitch at any time: `/permissions ask`, `/permissions auto`, `/permissions deny`.\n\n#### Secret scanner — 25+ patterns, blocks before sending\n\nBefore any content is sent to a cloud LLM, zap scans it for secrets. It checks for:\n\n- **API keys**: Anthropic (`sk-ant-`), OpenAI (`sk-proj-`), Stripe live and test keys\n- **VCS tokens**: GitHub personal access tokens (`ghp_`, `ghs_`, `github_pat_`), GitLab tokens (`glpat-`)\n- **Cloud credentials**: AWS access keys (`AKIA`), AWS secret key fields, GCP service account JSON\n- **Cryptographic material**: PEM private key blocks (`-----BEGIN`), JWT tokens (base64 header prefix)\n- **Generic credential fields**: `password=`, `api_key=`, `secret=`, `access_token=` in config files\n\nMatches are blocked and you're warned with the line number and a redacted preview — content is never silently forwarded.\n\n#### Full audit trail\n\nEvery tool call is appended to `~/.zap/audit.jsonl` as a structured JSON record with a timestamp, tool name, and outcome. You have a complete, machine-readable record of everything the agent did — useful for debugging, compliance, or just reviewing what changed.\n\n```bash\n/audit 20       # show last 20 audit entries in the TUI\n```\n\n#### Undo for every edit\n\nBefore modifying any file, zap snapshots the previous content in memory. If the agent makes a wrong edit, you can restore it instantly:\n\n```\n/undo src/main.rs      # restore file to its pre-edit state\n```\n\nThe model can also undo its own edits via the `undo_edit` tool — useful in autonomous `/goal` runs where the agent detects it made a mistake mid-task.\n\n---\n\n### 6. `/init` — Zero to Context-Aware in 30 Seconds\n\nMost agents start every session blind. They don't know your project structure, your build commands, your architecture, or what you worked on last time — unless you tell them. And you tell them again. And again.\n\n`/init` fixes this once, permanently.\n\n```\n/init\n```\n\nHere's what happens:\n\n1. **Auto-detects your stack** — identifies the language/framework from your repo (the same mechanism that fires the right skill at startup)\n2. **Indexes the codebase** — builds the AST symbol index so the agent can navigate structurally from turn one\n3. **Creates `ZAP.md`** — asks the LLM to read your source files and fill in: project overview, build/test commands, architecture layout, key files, and a do-not-touch list\n4. **Creates `.zap/understanding.md`** — a deeper technical summary: module map, data flows, non-obvious patterns, constraints\n5. **Writes `.zap/project.json`** — persisted project config (language, index state)\n\nTotal time: ~30 seconds. From that point forward, every session starts informed — the agent knows your project.\n\n**What `ZAP.md` looks like after `/init`:**\n\n```markdown\n## Overview\nOrder service — handles order lifecycle (create, fulfil, cancel).\n\n## Build \u0026 Test\nmvn clean install\nmvn test\nmvn spring-boot:run\n\n## Architecture\n- OrderController  → REST handlers (controller/)\n- OrderService     → business logic, calls OrderRepository\n- OrderRepository  → JPA, Postgres via spring-data\n\n## Important Files\n- OrderService.java     — core domain logic, start here\n- application.yml       — all config including Kafka brokers\n\n## Do Not Touch\n- LegacyOrderMapper.java — deprecated, backwards compat only\n```\n\n**When context files get updated:**\n\n| File | Updated | By |\n|---|---|---|\n| `ZAP.md` | Once, during `/init` | LLM (reads project, fills template) |\n| `.zap/understanding.md` | Once, during `/init` | LLM (deep structural analysis) |\n| `.zap/context.md` | Every session end | Auto (goal, files touched, what's next) |\n| `.zap/session_log.md` | Every session | Auto (date-indexed history) |\n| `.zap/project.json` | `/init` + on index changes | Auto |\n\nThe key insight: `/init` is not just a template generator — it's the bridge between \"the agent knows nothing about your project\" and \"the agent starts every session with full structural knowledge.\" Combined with the skill system and AST index, it means context quality is built in from the very first turn.\n\n---\n\n## Features at a glance\n\n| | |\n|---|---|\n| **TUI** | Ratatui terminal UI — streaming output, sidebar with token counts, diff viewer (Ctrl+G), file browser (Ctrl+F), syntax highlighting |\n| **Providers** | LM Studio, Ollama, Anthropic, OpenAI, Gemini, DeepSeek, Groq, Mistral, xAI, Together AI, Perplexity, Cohere + any OpenAI-compatible endpoint; per-provider settings persisted in `~/.agent.toml` |\n| **Tools** | 15 built-in — read, edit, write, batch-edit, undo, shell, search, glob, code-map, find-def, find-refs, web-fetch, web-search, spawn-agent |\n| **Languages** | AST index: Rust, Python, TypeScript, JavaScript, Go, Java |\n| **Code quality** | `/index quality` — god objects, coupling, dead code candidates, quality score (0–100); reference counts computed in one O(source-size) pass |\n| **Index usage logging** | Every tool call answered by the AST index is logged to `~/.zap/zap.log` and `audit.jsonl` — hit/miss per turn, auditable |\n| **Permission modes** | `ask` (grouped prompt per destructive op), `auto` (approve all), `deny` (fully read-only); \"always\" grant auto-approves a tool class for the session |\n| **Skills** | 23 built-in; always-on + keyword-triggered; user skills in `~/.zap/skills/` or `.zap/skills/`; SKILL.md standard compatible with Claude Code and Cursor |\n| **Skill trace** | `/skill log` — see which skills fired (or why they didn't) for every turn this session |\n| **Skill capture** | `/skill capture \u003cname\u003e` — extract session rules into a reusable skill file |\n| **Skill scope** | `/skill scope` — pin or restrict which domain skills are active for a session without editing files |\n| **Deploy** | `/deploy` — builds and installs zap with live streamed output; no shell timeout |\n| **Context mgmt** | Skill injection, casual-turn optimization (~20 tokens for greetings), sliding history window, tool-result pruning, `/compact` in-place summarisation, Anthropic prompt caching |\n| **Project init** | `/init` — auto-detects stack, indexes codebase, and generates `ZAP.md` + `.zap/understanding.md` filled with project-specific architecture, build commands, and constraints; ~30 seconds to full context awareness |\n| **Project intelligence** | `.zap/context.md` session handoff (last goal, files touched, what's next); `.zap/understanding.md` LLM-maintained project knowledge; `.zap/session_log.md` session history — read on demand, not pre-loaded |\n| **Sessions** | Every conversation persisted; `/sessions` fuzzy picker to resume any |\n| **Branching** | `/branch` forks a conversation like a git branch; `/switch` to move between them |\n| **Sub-agents** | `spawn_agent` runs parallel sub-agents with their own tool loop; multiple spawns in one turn run in parallel |\n| **Autonomous loop** | `/goal \u003ccondition\u003e` runs turns automatically until the model signals done or a turn limit is reached |\n| **Extended thinking** | `/think [on\\|off\\|N]` — Anthropic extended thinking with configurable token budget |\n| **MCP (lazy-loaded)** | Standard `.mcp.json` format — works in Claude Code, Cursor, Kiro; servers connect on demand, zero cost until first use |\n| **Workflows** | Declarative YAML multi-step pipelines in `.zap/workflows/` — versioned with your repo |\n| **Hooks** | `PreToolUse` / `PostToolUse` / `SessionStart` / `SessionEnd` / `UserPromptSubmit` — shell commands that run on agent events |\n| **Remote control** | `/remote` starts a local HTTP server + public tunnel; drive the session from any browser or phone |\n| **Images** | `/attach \u003cpath\u003e` or `/paste` clipboard — multimodal on supported models |\n| **Audit log** | Every tool call written to `~/.zap/audit.jsonl` |\n| **Secret scanner** | 25+ patterns — Anthropic/OpenAI/Stripe keys, GitHub/GitLab tokens, AWS/GCP credentials, private keys, JWTs, generic password/api_key/secret fields — blocked before sending to any cloud LLM |\n| **Cost display** | Token breakdown per turn — skills, message, context, estimated $ |\n\n---\n\n### Token efficiency — smart context detection\n\nPure greetings and social messages use a minimal 31-token prompt with no tools, even mid-conversation. Everything else gets the full context injection:\n\n| Message | After model asks a question? | Result |\n|---|---|---|\n| \"hi\", \"hello\", \"hey\" | yes | ~31 tokens (casual) |\n| \"thanks\", \"thank you\", \"ty\" | yes | ~31 tokens (casual) |\n| \"good morning\", \"how are you\" | yes | ~31 tokens (casual) |\n| \"yes\" | yes | full context |\n| \"go ahead\" | yes | full context |\n| \"ok\", \"cool\", \"sounds good\" | yes | full context |\n| any technical question | — | full context |\n\nAfter the model asks a clarifying question, short replies like \"yes\", \"ok\", \"go ahead\" are treated as answers and receive the full context. Pure social messages always stay casual.\n\n---\n\n## Install\n\n| Platform | Status |\n|---|---|\n| macOS ARM (Apple Silicon) | Available |\n| Windows x86_64 | Available |\n| macOS Intel | Coming soon |\n| Linux x86_64 | Coming soon |\n\n### macOS ARM — Apple Silicon\n\n1. Download `zap` from the [latest release](https://github.com/sanjeev23oct/zap/releases/latest)\n\n2. Make it executable and move it onto your PATH:\n\n```bash\nchmod +x zap\nmv zap ~/.local/bin/zap\n```\n\n3. If `~/.local/bin` is not already on your PATH, add it:\n\n```bash\necho 'export PATH=\"$HOME/.local/bin:$PATH\"' \u003e\u003e ~/.zshrc \u0026\u0026 source ~/.zshrc\n```\n\n4. Copy the example config:\n\n```bash\ncurl -o ~/.agent.toml \\\n  https://raw.githubusercontent.com/sanjeev23oct/zap/main/agent.toml.example\n```\n\n5. Run:\n\n```bash\nzap\n```\n\n\u003e **macOS Gatekeeper note:** On macOS 15+ you may see `zsh: killed zap` on first run.\n\u003e Fix: `codesign --sign - ~/.local/bin/zap`\n\n### Windows x86_64\n\n1. Download `zap-windows-x86_64.exe` from the [latest release](https://github.com/sanjeev23oct/zap/releases/latest)\n\n2. Rename and move it somewhere on your PATH, e.g.:\n\n```powershell\nMove-Item zap-windows-x86_64.exe C:\\Users\\You\\bin\\zap.exe\n```\n\n3. Run:\n\n```powershell\nzap\n```\n\n### Build from source\n\nRequires [Rust](https://rustup.rs) 1.75+.\n\n```bash\ngit clone https://github.com/sanjeev23oct/zap\ncd zap\ncargo build --release\ncp target/release/zap ~/.local/bin/zap\necho 'export PATH=\"$HOME/.local/bin:$PATH\"' \u003e\u003e ~/.zshrc \u0026\u0026 source ~/.zshrc\n```\n\n---\n\n## Configuration\n\nAll settings live in `~/.agent.toml`. Environment variables always take precedence.\n\nUse `/provider` inside zap to switch interactively — settings are saved automatically per provider, so switching back restores your previous key and model.\n\n```toml\n# ~/.agent.toml — managed by zap /provider\n\nprovider        = \"anthropic\"   # active provider slug\npermission_mode = \"ask\"         # ask | auto | deny\n\n[providers.anthropic]\nkind     = \"anthropic\"\nmodel    = \"claude-sonnet-4-6\"\napi_key  = \"sk-ant-...\"\n\n[providers.lm_studio]\nkind     = \"openai\"\nmodel    = \"gemma-4-e4b-it\"\nbase_url = \"http://localhost:1234/v1/chat/completions\"\n\n[providers.groq]\nkind     = \"openai\"\nmodel    = \"llama-3.3-70b-versatile\"\nbase_url = \"https://api.groq.com/openai/v1/chat/completions\"\napi_key  = \"gsk_...\"\n```\n\nEach `[providers.\u003cslug\u003e]` block stores settings independently — switching providers never overwrites another provider's key.\n\n### Environment variable overrides\n\n```bash\nAGENT_PROVIDER=anthropic \\\nAGENT_API_KEY=sk-ant-... \\\nAGENT_MODEL=claude-sonnet-4-6 \\\nzap\n```\n\n`ANTHROPIC_API_KEY` and `OPENAI_API_KEY` are also read automatically.\n\n---\n\n## Usage\n\n```bash\nzap                                        # interactive REPL\nzap --goal \"add tests for src/lib.rs\"      # single-shot\nzap --goal \"...\" --output-format json      # JSON output (for piping)\nzap --auto --goal \"...\"                    # skip all permission prompts (CI)\nzap --sdk                                  # JSON-lines remote control (stdin/stdout)\n```\n\n### Slash commands\n\n| Command | Description |\n|---|---|\n| `/help` | Show all commands |\n| `/config` | Show active provider, model, URL, sub-agent depth |\n| `/cost` | Token usage and estimated cost for this session |\n| `/history` | Show message count |\n| `/clear` | Clear conversation history |\n| `/compact` | Model summarises history in-place to free context |\n| `/sessions [N]` | Browse and resume old sessions (fuzzy picker) |\n| `/model \u003cid\u003e` | Switch model mid-session |\n| `/models` | List models on your LM Studio / Ollama server |\n| `/provider` | Switch provider interactively |\n| `/permissions ask\\|auto\\|deny` | Change permission mode for this session |\n| `/index [path\\|stats]` | Reindex AST code symbols |\n| `/index quality` | Code quality report: god objects, coupling, dead code, quality score |\n| `/deploy [--check]` | Build and install zap with live streaming output, no timeout |\n| `/undo [file]` | Undo the last file edit |\n| `/init` | Create a `CLAUDE.md` for this project (auto-filled by the agent) |\n| `/run \u003cworkflow\u003e` | Run a `.zap/workflows/\u003cname\u003e.yaml` pipeline |\n| `/workflow new \u003cname\u003e` | Scaffold a new workflow file |\n| `/tasks` | Browse and execute structured task sessions from `.zap/tasks/` |\n| `/attach \u003cpath\u003e` | Stage an image for the next message |\n| `/paste` | Paste an image from the clipboard |\n| `/memory list\\|get\\|set\\|del` | Manage persistent key-value memory |\n| `/skill list\\|show\\|create\\|log` | Manage skills; `log` shows which skills fired per turn |\n| `/skill scope` | Show or change which domain skills are active for this session |\n| `/hooks` | List all configured hooks and their trigger events |\n| `/branch \u003cname\u003e` | Fork the current conversation |\n| `/branches` | List all conversation branches |\n| `/switch \u003cname\u003e` | Switch to a different branch |\n| `/audit [N]` | Show last N audit log lines |\n| `/exit` | Quit |\n\n---\n\n## Tools\n\n| Tool | What it does |\n|---|---|\n| `read_file` | Read with optional offset/limit, output prefixed with line numbers |\n| `edit_file` | Surgical find-and-replace (rejects ambiguous matches) |\n| `batch_edit` | Multiple edits to one file in a single validated call |\n| `write_file` | Write or overwrite a file |\n| `undo_edit` | Restore a file to its pre-edit snapshot |\n| `shell` | Run a shell command (approval required in `ask` mode) |\n| `git_status` | Git status + recent log |\n| `search_code` | Ripgrep (falls back to grep) with file-type filter and context lines |\n| `list_directory` | `ls -la` |\n| `glob_read` | List/preview files matching a glob pattern |\n| `code_map` | AST-backed structural outline — functions, structs, classes, line numbers |\n| `find_definition` | Jump to where a symbol is defined (AST index → ripgrep fallback) |\n| `find_references` | All call sites of a symbol across the codebase |\n| `web_fetch` | Fetch a URL, strip HTML, return readable text |\n| `web_search` | DuckDuckGo search — no API key required |\n| `spawn_agent` | Spawn a parallel sub-agent with its own tool loop |\n\n---\n\n## CI / Headless Mode\n\nzap runs fully non-interactively. Add `--auto` (or `AGENT_PERMISSION_MODE=auto`) to skip all permission prompts:\n\n```bash\n# single-shot — clean for scripts\nzap --auto --goal \"review staged changes and write a summary to REVIEW.md\"\n\n# environment variable alternative\nAGENT_PERMISSION_MODE=auto zap --goal \"run cargo test and fix any failures\"\n```\n\n### GitLab CI example\n\n```yaml\n# .gitlab-ci.yml\nai-review:\n  image: ubuntu:24.04\n  variables:\n    ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY   # set in CI/CD → Variables\n  before_script:\n    - curl -L https://github.com/sanjeev23oct/zap/releases/download/latest/zap-linux-x86_64\n        -o /usr/local/bin/zap \u0026\u0026 chmod +x /usr/local/bin/zap\n  script:\n    - zap --auto --goal \"review the diff since origin/main, identify bugs or missing tests,\n        and write a report to ai-review.md\"\n  artifacts:\n    paths: [ai-review.md]\n    expire_in: 1 week\n```\n\n### GitHub Actions example\n\n```yaml\n- name: AI code review\n  env:\n    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}\n  run: |\n    zap --auto --goal \"read the changed files, add docstrings where missing, and commit\"\n```\n\n---\n\n## SDK / Remote Control Mode\n\n`--sdk` turns zap into a **JSON-lines server** — stdin carries prompts, stdout carries responses. It keeps session state across turns, so context accumulates.\n\n```bash\nzap --sdk          # stdin → stdout, --auto implied, no banner\n```\n\n### Protocol\n\n**stdin** (one JSON object per line):\n```json\n{\"type\":\"user\",\"text\":\"refactor the auth module to use JWT\"}\n{\"type\":\"user\",\"text\":\"now write tests for the new auth module\"}\n{\"type\":\"quit\"}\n```\n\n**stdout** (one JSON object per line):\n```json\n{\"type\":\"assistant\",\"text\":\"I've refactored the auth module...\",\"turn\":1,\"ctx_pct\":12,\"usage\":{\"input_tokens\":1842,\"output_tokens\":487}}\n{\"type\":\"assistant\",\"text\":\"I've written tests for...\",\"turn\":2,\"ctx_pct\":24,\"usage\":{\"input_tokens\":3210,\"output_tokens\":612}}\n```\n\nAll terminal noise (tool call boxes, spinners) goes to **stderr** — stdout is clean JSON for machine consumption.\n\n### Remote control over SSH\n\n```bash\nssh user@dev-server 'ANTHROPIC_API_KEY=sk-ant-... zap --sdk' \u003c\u003c 'PROMPTS'\n{\"type\":\"user\",\"text\":\"run cargo test and fix any failures\"}\n{\"type\":\"quit\"}\nPROMPTS\n```\n\n### Python script example\n\n```python\nimport subprocess, json\n\nproc = subprocess.Popen(\n    [\"zap\", \"--sdk\"],\n    stdin=subprocess.PIPE,\n    stdout=subprocess.PIPE,\n    env={**os.environ, \"ANTHROPIC_API_KEY\": \"sk-ant-...\"},\n)\n\ndef ask(prompt: str) -\u003e dict:\n    proc.stdin.write(json.dumps({\"type\": \"user\", \"text\": prompt}).encode() + b\"\\n\")\n    proc.stdin.flush()\n    return json.loads(proc.stdout.readline())\n\nreply = ask(\"add input validation to src/api.rs\")\nprint(reply[\"text\"])\n\nproc.stdin.write(b'{\"type\":\"quit\"}\\n')\nproc.stdin.flush()\nproc.wait()\n```\n\n---\n\n## CLAUDE.md support\n\nPlace a `CLAUDE.md` in your project root — or any parent directory up to `$HOME` — for persistent project context. A global `~/.claude/CLAUDE.md` is also loaded. All matching files are stacked; innermost directory wins.\n\nRun `/init` to create a template the agent fills in automatically by reading your repo.\n\n---\n\n---\n\n## Skills\n\nSkills are markdown files (`.md`) with YAML frontmatter. They follow the [SKILL.md standard](https://github.com/multica-ai/andrej-karpathy-skills) — compatible with Claude Code, Cursor, and other agents.\n\n**Triggered skill** — injected only when keywords match:\n\n```markdown\n---\nname: conventional-commits\ndescription: Enforce Conventional Commits format on all git operations.\ntrigger: [\"commit\", \"git log\", \"stage\", \"push\"]\ntokens: ~400\n---\nAlways use Conventional Commits format: \u003ctype\u003e(\u003cscope\u003e): \u003cdescription\u003e\nTypes: feat, fix, docs, style, refactor, perf, test, chore\n```\n\n**Always-on skill** — no `trigger:` field, injected every session:\n\n```markdown\n---\nname: team-principles\ndescription: Engineering principles applied to every task.\n---\nShip small. Write tests first. No magic numbers. Document the why, not the what.\n```\n\n**Where to place skills:**\n\n```\n~/.zap/skills/          personal, applies to all projects  ← written here on first launch\n.zap/skills/            project-local, check into git for team sharing\n```\n\nOn first launch zap writes all built-in skills to `~/.zap/skills/`. Open any file there, edit it, and your version takes effect on the next run. Files are never overwritten — only new ones are added when you update zap.\n\nIf you delete a file or want to reset a skill to its default, re-export it:\n\n```\n/skill export rust              # restore rust.md from the built-in\n/skill export --all             # restore every built-in skill\n/skill export rust --overwrite  # force-overwrite even if the file exists\n```\n\n**All commands:**\n\n```\n/skill list                      list all skills (grouped: always-on / triggered)\n/skill show \u003cname\u003e               preview content, description, license\n/skill log                       show which skills fired (or why they didn't) per turn this session\n/skill scope                     show which domain skills are active this session\n/skill scope add \u003cname\u003e          add a skill to the active scope\n/skill scope remove \u003cname\u003e       remove a skill from the active scope\n/skill scope reset               restore default scope\n/skill export \u003cname\u003e             re-export a built-in to ~/.zap/skills/\n/skill export --all              re-export every built-in skill\n/skill create \u003cname\u003e             scaffold a new skill in .zap/skills/\n/skill create \u003cname\u003e --global    scaffold in ~/.zap/skills/\n/skill capture \u003cname\u003e            extract rules from this session into a skill file\n/skill capture \u003cname\u003e --global   save captured skill globally\n```\n\n**Skill trace** — `/skill log` lets you audit which skill fired (or didn't) for every turn this session. If a skill you expected to fire didn't, the log shows \"no match\" or \"casual\" with the turn preview so you can tune the trigger keywords:\n\n```\n  turn #3  \"refactor the async fn to use channels\"    → rust, karpathy-guidelines\n  turn #4  \"commit these changes\"                     → git, karpathy-guidelines\n  turn #5  \"hey thanks\"                               → (casual)\n  turn #6  \"add an endpoint for POST /users\"          → (no match)  ← missing api-conventions skill?\n```\n\nSame-name skills override lower-priority ones: `.zap/skills/` \u003e `~/.zap/skills/` \u003e built-in.\n\n---\n\n## Workflows\n\nDeclarative multi-step pipelines in `.zap/workflows/\u003cname\u003e.yaml`. Run with `/run \u003cname\u003e`.\n\n```yaml\nname: ship-feature\ndescription: Review → test → commit → changelog\nsteps:\n  - prompt: \"Review all staged changes and flag anything blocking\"\n    requires_approval: true\n  - skill: test-runner\n    prompt: \"Run the test suite, fix any failures\"\n  - prompt: \"Commit with a conventional commit message\"\n  - prompt: \"Append a one-line entry to CHANGELOG.md\"\n```\n\n---\n\n## Code Index\n\nSee [AST Code Index — Understands Your Code, Not Just Text](#2-ast-code-index--understands-your-code-not-just-text) above for the full explanation, including the blind-writes problem, SQL query examples, per-write reindex guarantee, index usage logging, and the comparison with Claude Code's agentic search approach.\n\n**Quick reference:**\n\n| Command | What it shows |\n|---|---|\n| `/index` | Reindex manually |\n| `/index stats` | File count, symbol count by kind, top files by density |\n| `/index quality` | God objects, large files, high coupling, dead code candidates, quality score |\n\n---\n\n## Session Management\n\nEvery conversation is persisted locally. Use `/sessions` to browse and resume any previous session with an interactive fuzzy picker.\n\n---\n\n## Sub-agents\n\nWhen `agent_depth \u003e 0` (default: 3), the model can call `spawn_agent` to delegate independent tasks. Multiple spawns within a single LLM turn run in parallel, each with its own message history and tool access.\n\n---\n\n## Developer Journeys\n\nReal scenarios — what actually happens at each stage.\n\n---\n\n### Journey 1 — First time opening a project\n\n**Scenario:** You've just cloned a Java microservice you've never seen before. Twelve services, Spring Boot, Maven, no docs.\n\n```bash\ncd order-service\nzap\n```\n\nzap starts in under a second. But the agent has no knowledge of this project yet — it's a blank slate. The right move is `/init`.\n\n```\n/init\n```\n\nHere's what happens step by step:\n\n```\n◌ Detected project type: java\nLanguage(s) for this project: java        ← confirm or correct\n\n◌ Indexing lets zap find symbols instantly without reading every file.\nIndex this project now? (recommended, ~10s)  Y\n\n  Indexing src/ ...\n  ✓ tree-sitter · java · 847 symbols across 63 files\n\n✓ .zap/project.json written.\n✓ Created ZAP.md for java project.\n⚡ Asking the agent to analyse the repo and fill in ZAP.md…\n```\n\nThe agent now reads the source files and fills in `ZAP.md` — a persistent project knowledge file loaded into every future session:\n\n```markdown\n## Overview\nOrder service — handles order lifecycle (create, fulfil, cancel).\nPublishes events to Kafka on state transitions.\n\n## Build \u0026 Test\nmvn clean install        # full build\nmvn test                 # unit tests only\nmvn spring-boot:run      # local dev server on :8080\n\n## Architecture\n- OrderController  → REST handlers (src/main/java/.../controller/)\n- OrderService     → business logic, calls OrderRepository\n- OrderRepository  → JPA, Postgres via spring-data\n- KafkaProducer    → publishes OrderCreated / OrderFulfilled events\n\n## Important Files\n- OrderService.java     — core domain logic, start here\n- application.yml       — all config including Kafka brokers\n- schema.sql            — DB schema\n\n## Do Not Touch\n- LegacyOrderMapper.java — deprecated, kept for backwards compat, do not edit\n```\n\nAt the same time, it writes `.zap/understanding.md` — a deeper technical summary covering entry points, data flows, non-obvious patterns, and constraints. This file is loaded silently into every future session so the agent always starts with structural knowledge of the project.\n\n**Total time: ~30 seconds.** From zero to a fully context-aware agent.\n\n---\n\n### Journey 2 — Returning to a project\n\n**Scenario:** You worked on the order service last week. You open zap today to continue.\n\n```bash\ncd order-service\nzap\n```\n\nCold start. But zap is not starting blind. Before your first message, it has already loaded:\n\n| File | What it contains |\n|---|---|\n| `ZAP.md` | Project overview, build commands, architecture, do-not-touch list |\n| `.zap/understanding.md` | Module map, data flows, patterns, constraints |\n| `.zap/context.md` | Last session: goal, files touched, what's next |\n| `.zap/session_log.md` | History of all previous sessions |\n\nThe agent's first response reflects all of this — it already knows what you were working on, which files changed, and what was left unfinished. You don't re-explain the project. You just continue:\n\n```\nyou:  \"what were we working on last time?\"\n\nzap:  Last session you were adding pagination to GET /orders.\n      You updated OrderController.java and OrderService.java.\n      The service method was done but the controller test was still failing\n      — that was left as the next step.\n```\n\nNo re-reading files. No re-explaining the stack. The session handoff is automatic.\n\n---\n\n### Journey 3 — Understanding unfamiliar code\n\n**Scenario:** A colleague wrote the `FulfilmentService` six months ago. You need to understand it before touching it.\n\n```\n\"explain how FulfilmentService works — what it does, what it calls, what could go wrong\"\n```\n\n```\n→ java skill fires (class keyword matched)\n→ find_definition looks up FulfilmentService in the index — found at\n  src/main/java/.../service/FulfilmentService.java:34\n→ code_map outlines all methods: fulfil(), rollback(), notifyWarehouse()\n→ reads only the relevant sections, not the whole file\n→ traces the call chain: fulfil() → OrderRepository.save() → KafkaProducer.publish()\n→ flags: rollback() has no test coverage, notifyWarehouse() blocks on HTTP with no timeout\n```\n\nYou get a structural explanation in seconds — including the non-obvious risks — without reading 400 lines of Java yourself.\n\n**Drill deeper:**\n\n```\n\"show me every place FulfilmentService.fulfil() is called\"\n→ find_references scans the index\n→ 3 call sites: OrderController.java:88, OrderSaga.java:142, FulfilmentTest.java:67\n```\n\n```\n\"what does the data flow look like from the REST call to Kafka publish?\"\n→ traces: POST /fulfil → FulfilmentController → FulfilmentService.fulfil()\n         → OrderRepository.save() (Postgres) → KafkaProducer.publish() (Kafka)\n→ notes: the Kafka publish happens inside the DB transaction — risky if Kafka is down\n```\n\n---\n\n### Journey 4 — Adding a feature to an existing codebase\n\n**Scenario:** You need to add a `GET /orders/{id}/history` endpoint to the existing order service.\n\nWithout zap (what most agents do): the agent creates `src/main/java/.../controller/HistoryController.java`, `src/main/java/.../service/HistoryService.java`, `src/main/java/.../repository/HistoryRepository.java` — duplicating the structure that already exists, ignoring the patterns already in use.\n\nWith zap:\n\n```\n\"add a GET /orders/{id}/history endpoint that returns the state change log\"\n```\n\n```\n→ java skill fires\n→ index query: WHERE name LIKE '%Order%' AND kind = 'class'\n  finds: OrderController, OrderService, OrderRepository, OrderHistory (entity — already exists!)\n→ index query: WHERE name LIKE '%Repository%' AND kind = 'interface'\n  finds: OrderRepository extends JpaRepository\u003cOrder, Long\u003e — this is the pattern to follow\n→ index query: WHERE path LIKE '%controller%' ORDER BY line\n  finds: all existing controllers — sees they all extend BaseController, use @RestController\n\nzap:  OrderHistory entity already exists at OrderHistory.java:12.\n      I'll add a findByOrderId() method to OrderRepository, a getHistory() method\n      to OrderService, and a new endpoint to OrderController — no new files needed.\n      Shall I proceed?\n```\n\nOne file touched in `OrderController`, one method added to `OrderRepository`, one to `OrderService`. No duplicate classes. Follows the existing `JpaRepository` pattern. Uses `BaseController` like every other controller.\n\n**This is the core difference.** The agent knew what existed before it decided what to create.\n\n---\n\n### Journey 5 — Fixing a bug\n\n**Scenario:** Orders are occasionally being marked as fulfilled even when the warehouse notification fails.\n\n```\n\"orders are being fulfilled even when notifyWarehouse() throws — trace why\"\n```\n\n```\n→ debugging skill fires\n→ find_definition locates fulfil() at FulfilmentService.java:67\n→ reads the method — sees notifyWarehouse() is called AFTER OrderRepository.save()\n→ the save() commits to DB before the warehouse call — if warehouse throws, order\n  is already marked fulfilled in the DB with no rollback\n→ finds: @Transactional annotation is present but notifyWarehouse() is an HTTP call\n  outside the transaction boundary — @Transactional won't roll it back\n\nzap:  Root cause: the DB commit happens before the warehouse HTTP call.\n      @Transactional covers the DB write but not the external HTTP call.\n      Fix: move notifyWarehouse() before the save(), or wrap it in a try/catch\n      that explicitly rolls back via OrderRepository.updateStatus().\n      Which approach do you prefer?\n```\n\nYou pick the approach, zap makes the surgical edit, shows you the diff, asks for approval before writing.\n\n---\n\n### Journey 6 — Checking and improving code quality\n\n**Scenario:** The team suspects the service is getting harder to change. You want data before the next sprint planning.\n\n```\n/index quality\n```\n\n```\n◎ code quality — 63 files · 847 symbols                          score: 61/100\n────────────────────────────────────────────────────────────────────────────\n\n⚠ god objects  (impl with \u003e15 methods — split recommended)\n  OrderService          34 methods  ██████████████  src/.../service/OrderService.java\n  FulfilmentService     18 methods  ███████         src/.../service/FulfilmentService.java\n\n⚠ large files  (\u003e50 symbols)\n    91 sym  ████████████████████  OrderService.java\n    67 sym  ██████████████        OrderController.java\n\n✦ high coupling  (referenced in many places — risky to change)\n  OrderService.fulfil()     29×   FulfilmentService.java:67\n  OrderRepository.save()    24×   (multiple callers)\n\n◌ dead code candidates  (public method, 0 external references)\n  LegacyOrderMapper.toDto()    LegacyOrderMapper.java:44\n  OrderUtils.formatId()        OrderUtils.java:18\n\n→ OrderService has 34 methods — consider splitting into OrderLifecycleService + OrderQueryService\n→ 2 public methods never referenced — confirm they can be removed\n```\n\nNow you have concrete data for the sprint discussion. `OrderService` is the riskiest file to change — 29 places call `fulfil()`. The two dead methods are candidates for deletion. Score is 61 — room to improve before it becomes painful.\n\n```\n\"which methods in OrderService are safe to extract to a new OrderQueryService?\"\n→ queries index for all methods in OrderService with kind=method\n→ cross-references call sites — methods only called from read endpoints are safe to extract\n→ lists: findById(), findByStatus(), findByDateRange(), getOrderSummary() — all query-only, no writes\n```\n\n---\n\n### Journey 7 — Wrapping up and handing off\n\nAt the end of any session:\n\n```\n\"we added pagination to GET /orders and fixed the fulfilment race condition —\n update context.md with what we did and what's still left\"\n```\n\nzap writes `.zap/context.md`:\n\n```markdown\n## Last updated\n2026-05-25 — Session #42\n\n## What was being worked on\nAdded cursor-based pagination to GET /orders endpoint.\nFixed race condition in FulfilmentService where DB commit preceded warehouse HTTP call.\n\n## Files touched\n- OrderController.java\n- OrderService.java\n- FulfilmentService.java\n- OrderControllerTest.java\n\n## What's next\n- Pagination test for edge case: empty cursor on last page\n- Consider splitting OrderService (34 methods — see /index quality output)\n```\n\nTomorrow's session picks this up automatically. No re-explaining. No lost context.\n\n---\n\n## Roadmap — Skill Ecosystem\n\nzap's bet is on **skills as a platform**, not on being a better terminal agent. The goal: turn team knowledge into code, make it shareable, composable, and cross-compatible with other agents.\n\n| # | Feature | Status | What it enables |\n|---|---|---|---|\n| `/skill install github:user/repo/path` | Pull a skill from any GitHub path | planned | One-command community skill install |\n| Skill extends / composition | `extends: [rust, code-review]` in frontmatter | planned | Composable skill layers |\n| Semantic skill routing | Embedding similarity instead of keyword match | planned | Intent-based matching, no keyword guessing |\n| Public skill directory | `zap.sh/skills` — browse, search, install | planned | Discoverable ecosystem |\n| Stack auto-detection expansion | Detect more stacks: Ruby, Swift, Kotlin, C++ | planned | Zero-config for more users |\n| Cross-agent compatibility | Test skill files against Claude Code, Cursor | planned | Write once, use anywhere |\n\nThe skill format is already compatible with Claude Code (`CLAUDE.md`-style) and the [multica-ai SKILL.md standard](https://github.com/multica-ai/andrej-karpathy-skills). Skills you write for zap work in other agents today.\n\n---\n\n## Contributing\n\nContributions are welcome — bug fixes, new providers, language support, skill improvements, or anything that makes zap more useful.\n\n**Reporting bugs**\nOpen an issue at [github.com/sanjeev23oct/zap/issues](https://github.com/sanjeev23oct/zap/issues). Include your OS, model/provider, the command you ran, and what you expected vs what happened. Attach the relevant lines from `agent_audit.jsonl` if the problem is tool-related.\n\n**Feature requests**\nOpen an issue with the `enhancement` label. Describe the use case, not just the feature — it helps prioritise.\n\n**Pull requests**\n1. Fork the repo and create a branch from `main`\n2. Keep changes focused — one PR per fix or feature\n3. Run `cargo check` and `cargo clippy` before submitting — zero warnings expected\n4. Update the README if you're adding a visible feature\n\n**Adding a built-in skill**\nBuilt-in skills live in `src/default_skills/`. Each is a markdown file with YAML frontmatter (name, trigger keywords, token estimate). If you have good conventions for a language or framework not yet covered, a skill PR is one of the easiest contributions to make.\n\n**Adding a provider**\nProvider switching lives in `src/session.rs` (`cmd_provider`). All providers speak the OpenAI wire format — adding one is usually just a new entry in the picker with a `base_url` and default model.\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanjeev23oct%2Fzap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsanjeev23oct%2Fzap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsanjeev23oct%2Fzap/lists"}