ankiclaw
AnkiClaw
A from-scratch personal agentic AI assistant — file access, terminal control, browser automation, and modular tools via MCP — with production-style guardrails: permissions, diff previews, logging, cost tracking, session persistence, and memory.
Built to demonstrate real agent engineering: the tool-calling loop, sandboxed permissions, context management under token budgets, and operational observability. Config lives in your user home (~/.ankiclaw), not inside each project.
Table of contents
- How it works
- Requirements
- Install
- Quick start
- CLI usage
- Agent home
- Features
- Interactive slash commands
- Configuration reference
- Local development
- Project layout
- License
How it works
At its core AnkiClaw is a loop:
- Build context (SOUL.md, memory, conversation, live plan).
- Call the model with a set of tool definitions.
- If the model requests a tool, run it under the permission policy.
- Feed the result back; repeat until the model responds with text only.
┌─────────────────────────────────────────────┐
│ CLI / TUI (ankiclaw start) │
└───────────────┬─────────────────────────────┘
│
┌───────────────▼─────────────────────────────┐
│ Agent core │
│ context → model → tool_use → execute → … │
└───────────────┬─────────────────────────────┘
│
┌───────────┼────────────┬─────────────┐
▼ ▼ ▼ ▼
Files Terminal Browser MCP
│ │ │
Permissions · Diff preview · Approval prompts
Cross-cutting: Plan · Cost · Logs · Interrupt · Sessions · Memory
Policy (what the agent may do) is separated from mechanism (how tools run). Edit SOUL.md and permissions.yaml without touching application code.
Requirements
- Node.js 20+
- An API key for at least one provider: Anthropic, OpenAI, or Google Gemini
- Optional: Playwright Chromium (installed via postinstall; see Browser)
Install
Requires Node.js 20+.
Global (recommended)
npm install -g ankiclaw
ankiclaw init # interactive setup → ~/.ankiclaw
ankiclaw start # interactive TUI from any directory
Without a global install
npx ankiclaw init
npx ankiclaw start
Platform notes
| Platform | Notes |
|---|---|
| macOS / Linux | Agent home is ~/.ankiclaw. After install, which ankiclaw should resolve on your PATH. |
| Windows | npm installs an ankiclaw.cmd shim. Agent home is %USERPROFILE%\.ankiclaw. |
If browser tools fail after install:
npx playwright install chromium
Quick start
- Run
ankiclaw initand enter at least one API key; pick a default model. - Run
ankiclaw start. - Ask it to do something concrete, e.g. “List files in the workspace and summarize README.”
- Approve terminal or file changes when prompted; press Esc to interrupt a running turn.
- Use
/costto see token usage;/quitto save and exit.
Shell tools use your current working directory, so you can cd into a repo and operate on it. File writes default to the sandboxed workspace/ under the agent home unless you approve paths outside it.
CLI usage
ankiclaw init [--force] Interactive setup (~/.ankiclaw)
ankiclaw start Start the interactive agent (alias: start_agent)
ankiclaw "one-shot prompt" Run a single prompt and exit
ankiclaw help
| Command | Behavior |
|---|---|
init |
Copies templates into the agent home, writes .env, patches config.yaml / permissions.yaml. Use --force to re-run over an existing home. |
start |
Fullscreen TUI REPL with slash commands, live plan, cost meter, and Esc interrupt. |
| oneshot | Non-interactive: one user prompt, agent loop runs to completion, then exits. |
Override the agent home with ANKICLAW_HOME (absolute path or relative to cwd). Useful for development and isolated profiles.
Agent home
Default location: ~/.ankiclaw (Windows: %USERPROFILE%\.ankiclaw).
~/.ankiclaw/
├── .env # API keys (never commit)
├── SOUL.md # Persona + hard behavioral rules
├── config.yaml # Provider, model catalog, memory settings
├── permissions.yaml # Terminal / filesystem / browser policy
├── skills/
│ ├── git_workflow/SKILL.md
│ └── web_research/SKILL.md
├── tools/
│ └── mcp_registry.json # External MCP servers
├── workspace/ # Default file sandbox
│ ├── scratch/ # Low-friction drafts (often always_allow)
│ └── secrets/ # Blocked from agent writes by default
├── sessions/ # Saved chat snapshots
├── plans/session_<id>/ # Live todo checklists
├── memory/
│ ├── long_term/memory.jsonl
│ └── episodic/ # Archived full transcripts
├── logs/
│ ├── tool_calls_<date>.jsonl
│ ├── tool_calls_<date>.log
│ └── cost_<date>.jsonl
└── mcp-oauth/ # OAuth tokens for remote MCP servers
ankiclaw init seeds this tree from the package templates/ directory.
Features
1. Multi-provider models
AnkiClaw talks to Anthropic, OpenAI, and Google through a shared provider interface. The catalog in config.yaml lists available models; the TUI /model command switches at runtime.
Defaults (from the shipped template):
| Model id | Provider |
|---|---|
claude-sonnet-5, claude-haiku-4-5 |
Anthropic |
gpt-4.1, gpt-4.1-mini |
OpenAI |
gemini-3.5-flash, gemini-3.5-flash-lite, gemini-3.5-pro |
Environment overrides (win over config.yaml):
ANKICLAW_PROVIDER=google
ANKICLAW_MODEL=gemini-3.5-flash
API keys live in ~/.ankiclaw/.env (written by init):
ANTHROPIC_API_KEY=...
OPENAI_API_KEY=...
GEMINI_API_KEY=...
2. SOUL.md and skills
SOUL.md is the system prompt: identity, tone, and hard rules (“never delete outside the workspace,” “rely on diff/approval before mutating files”). Keeping this as markdown separates policy from code.
Skills are on-demand workflows under skills/<name>/SKILL.md. Each file may include YAML frontmatter (name, description). The agent sees a catalog of skill names/descriptions and calls load_skill to pull the full workflow into context when relevant.
Shipped skills:
| Skill | Purpose |
|---|---|
git_workflow |
Safe local git inspection and commit-message drafting |
web_research |
Search → browse → note-taking into the workspace |
Add your own by dropping a new folder with a SKILL.md into skills/.
3. File tools and sandbox
Native tools:
| Tool | Role |
|---|---|
read_file |
Read UTF-8 text, or extract text from PDF, DOCX, XLSX, CSV |
create_file |
Create a new file (fails if it already exists) |
edit_file |
Replace contents of an existing file |
delete_file |
Delete a file |
Sandboxing: every path is resolved to an absolute path against the agent home, checked for ../ traversal and symlink escapes, then matched against permissions.yaml.
filesystem:
workspace_root: "./workspace"
allow:
- "workspace/**"
deny:
- "workspace/.env"
- "workspace/secrets/**"
outside_workspace: ask # or "deny"
Diff preview: create / edit / delete compute a unified diff first. The CLI shows it; the same three-tier rules as terminal commands decide whether to auto-approve, ask, or block:
file_edits:
always_allow:
- "workspace/scratch/**"
ask:
- "workspace/**"
always_block:
- "workspace/.env"
- "workspace/secrets/**"
Approved writes are logged (hashes, diff, timestamp) for audit.
4. Terminal permissions
Tool: run_terminal_command.
Three-tier policy in permissions.yaml:
terminal:
always_allow:
- "pwd"
- "ls *"
- "git status"
- "git diff *"
always_block:
- "rm -rf /*"
- "sudo *"
default: ask
Commands are normalized and matched with globs. On ask, the TUI shows the exact command and waits for approval. Denied commands return a tool result the model can adapt to (it should not retry the same forbidden action).
Stdout/stderr are captured, truncated for the model context when huge, and fully preserved in the tool-call logs. The shell runs in your current working directory, so AnkiClaw can operate on whatever repo you launched it from.
5. Plan tracking
Tool: update_plan.
For multi-step work the agent maintains a live checklist (JSON internally, rendered as markdown for you):
~/.ankiclaw/plans/session_<id>/todo.md
Each item has status: pending | in_progress | done | paused. The plan is reinjected into context on later turns and shown in the TUI when updated. On interrupt, in-progress items become paused so a resumed session knows where it left off.
6. Interrupt / cancel
Press Esc during a busy turn to request an interrupt:
- Between tool calls: the loop stops before the next dispatch.
- Mid tool call: in-flight work (terminal, browser, search) is aborted via
AbortSignal; partial results may return withinterrupted: true. - The plan is marked paused rather than completed.
This is the control surface that makes long agent runs feel like a real tool instead of an unstoppable script.
7. Sessions and chats
Each interactive run is a session with an id like sess_a36f380c. After turns, AnkiClaw snapshots:
- Working message history
- Plan reference
- Workspace root
- Cost summary
- Status (
active/paused/completed)
Snapshots live under sessions/. In the TUI:
| Command | Action |
|---|---|
/chat new |
Save current chat and start a fresh one |
/chat load |
Pick or select a saved chat to resume |
/chat delete |
Delete a saved chat |
/clear |
Clear in-memory history for the current session |
/quit |
Save and leave |
The agent can also call load_chat with a session_id (e.g. from memory search) to pull a prior transcript into context.
8. Memory and compaction
Configured under memory: in config.yaml:
memory:
compaction:
token_threshold: 24000
keep_recent_messages: 12
long_term:
max_inject: 8
episodic:
enabled: true
| Layer | What it is | Tools / behavior |
|---|---|---|
| Working context | Messages sent to the API each turn | Built automatically |
| Compaction | When estimated tokens cross the threshold, older turns are summarized; recent N kept verbatim | Transparent; plan stays pinned |
| Long-term | Distilled facts in memory/long_term/memory.jsonl |
remember, auto-distill on session end; injected on new sessions |
| Episodic | Full archived transcripts under memory/episodic/ |
search_memory (keyword), then load_chat for the full thread |
Retrieval is keyword/recency based — enough for durable preferences and “what did we do last time?” without a vector DB.
9. Browser and web search
Headless Playwright Chromium plus a search helper.
| Tool | Behavior |
|---|---|
web_search |
Discover URLs and snippets (Brave if BRAVE_API_KEY is set; otherwise DuckDuckGo HTML) |
browser_navigate |
Open an http(s) URL; returns title + accessibility-tree snapshot (not raw HTML) |
browser_click |
Click by CSS selector |
browser_type |
Type into a field |
browser_get_text |
Re-snapshot the current page |
browser_screenshot |
Full-page PNG under workspace/scratch/screenshots/ (path returned; image not sent to the model) |
Browser actions respect permissions.yaml:
browser:
enabled: true
navigate: ask
interact: always_allow
search: always_allow
If Chromium is missing: npx playwright install chromium.
10. MCP (modular tools)
AnkiClaw is an MCP client. Servers listed in tools/mcp_registry.json are connected at startup; their tools are merged into the model schema as mcp_<server>_<tool>. Adding a capability is a config change, not a code change.
Example registry entry shape:
{
"name": "gmail",
"enabled": false,
"transport": "http",
"url": "https://gmailmcp.googleapis.com/mcp/v1",
"oauth": {
"clientIdEnv": "GOOGLE_MCP_CLIENT_ID",
"clientSecretEnv": "GOOGLE_MCP_CLIENT_SECRET",
"redirectUri": "http://127.0.0.1:8765/oauth/callback"
}
}
Google Workspace MCP (Developer Preview)
Overview: Configure Google Workspace MCP servers.
- In Google Cloud: enable product APIs + MCP APIs; configure OAuth consent.
- Create an OAuth Web application client.
- Authorized redirect URI (exact):
http://127.0.0.1:8765/oauth/callback - Put credentials in
~/.ankiclaw/.env(or re-runankiclaw init):
GOOGLE_MCP_CLIENT_ID=...
GOOGLE_MCP_CLIENT_SECRET=...
- In
tools/mcp_registry.json, set"enabled": trueon the servers you want (gmail,drive,calendar,people,chat). - Run
ankiclaw start. On first connect, a browser opens for Google sign-in; tokens are stored undermcp-oauth/.
You can also register stdio or other HTTP MCP servers in the same registry format used by the hub.
11. Logging and cost
Tool-call logs (every file, terminal, browser, and MCP invocation):
| File | Format |
|---|---|
logs/tool_calls_<date>.jsonl |
One JSON object per line (args, permission tier, approval, duration, truncation) |
logs/tool_calls_<date>.log |
Human-readable mirror for skimming |
Cost tracking: each API response’s token usage is appended to logs/cost_<date>.jsonl and priced with approximate public rates (including cache read/write when the provider reports them). Use /cost in the TUI for a session summary: call count, tokens by type, estimated USD, cache hit rate.
A live cost meter also appears in the TUI status area during a session.
Interactive slash commands
Type / in the TUI for a hierarchical palette:
| Command | Description |
|---|---|
/chat |
Expand into chat management |
/chat new |
Save current chat and start a new one |
/chat load |
Load a saved chat |
/chat delete |
Delete a saved chat |
/model |
Expand into model commands |
/model list |
Show current model and catalog |
/model change <id> |
Switch model for this session |
/cost |
Session token usage and estimated cost |
/clear |
Clear conversation history for this session |
/quit |
Save current chat and exit |
Esc — interrupt the active turn.
↑ / ↓ · Enter — navigate pickers (sessions, models).
Configuration reference
config.yaml
| Key | Meaning |
|---|---|
provider / model |
Default provider and model id |
max_tokens |
Generation cap per model call |
models |
Catalog entries (id, provider, label) |
memory.compaction.token_threshold |
Trigger summarization when working context grows |
memory.compaction.keep_recent_messages |
Verbatim window after compaction |
memory.long_term.max_inject |
Max long-term facts injected into new context |
memory.episodic.enabled |
Archive full transcripts on session end |
permissions.yaml
| Section | Controls |
|---|---|
terminal |
always_allow / always_block / default |
filesystem |
workspace_root, path allow/deny, outside_workspace |
file_edits |
Path-scoped allow / ask / block for mutations |
browser |
enabled, navigate, interact, search |
Environment variables
| Variable | Purpose |
|---|---|
ANKICLAW_HOME |
Override agent home directory |
ANKICLAW_PROVIDER / ANKICLAW_MODEL |
Override default model selection |
ANTHROPIC_API_KEY / OPENAI_API_KEY / GEMINI_API_KEY |
Provider credentials |
BRAVE_API_KEY |
Prefer Brave Search for web_search |
GOOGLE_MCP_CLIENT_ID / GOOGLE_MCP_CLIENT_SECRET |
Google Workspace MCP OAuth |
See .env.example / templates/env.example for a full commented template.
Local development
Clone this repo, then:
npm install
npm run start_agent # ANKICLAW_HOME=<repo>/.agent via scripts/run-dev.mjs
npm test
npm run build
node bin/ankiclaw.js help
| Script | Role |
|---|---|
npm run start_agent / npm run dev |
Run TypeScript via tsx against the repo’s .agent home |
npm test |
Node test runner over test/**/*.test.ts |
npm run build |
Compile src/ → dist/ |
npm run typecheck |
tsc --noEmit |
Contributor agent home (.agent/) holds checked-in policy (SOUL.md, config.yaml, permissions.yaml, skills, MCP registry). Runtime dirs (logs/, sessions/, memory/, workspace/) are gitignored — put API keys in a local .env (also gitignored).
For a clean user-style install from a local checkout:
npm run build
npm link # or: npm pack && npm install -g ./ankiclaw-*.tgz
ankiclaw init
ankiclaw start
Project layout
ankiclaw/
├── bin/ankiclaw.js # CLI entry
├── src/
│ ├── agent.ts # Tool loop + native tool definitions
│ ├── cli.ts / tui.ts / ui.ts
│ ├── permissions.ts # Path + terminal + browser policy
│ ├── files.ts / terminal.ts / browser.ts / web-search.ts
│ ├── plan.ts / session.ts / interrupt.ts
│ ├── cost.ts / logger.ts
│ ├── soul.ts # SOUL.md + skills loader
│ ├── init.ts / paths.ts
│ ├── model/ # Anthropic, OpenAI, Google providers
│ ├── memory/ # Compaction, long-term, episodic
│ └── mcp/ # Hub, registry, OAuth
├── templates/ # Seeded into ~/.ankiclaw by init
├── test/
├── scripts/run-dev.mjs # Local ANKICLAW_HOME=.agent runner
└── PROJECT_DESIGN.md # Architecture notes and original phased plan
For deeper design rationale (permission philosophy, why dual logging, portfolio framing), see PROJECT_DESIGN.md.
License
MIT — see LICENSE.