Ag 47 elementics

Persistent AI coding agent with memory

Agents that remember beat agents that re-learn.

Plan-first REPL, persistent memory, checkpoints, result refs. ~130kB, zero deps, any model.

$npx @elementics/ag

A hackable agent
you fully control

ag is a tool-calling loop with bash, built as a persistent AI coding agent. Started as 60 lines of code, grew to ~9500 lines as persistent memory, guardrails, permissions, plans, skills, checkpoints, result caching, interaction modes, and a full REPL earned their place.

It remembers context across sessions with a 3-tier memory system — global preferences, project architecture decisions, and timestamped plans. All stored as plain markdown files you can read and edit directly.

Works with any model via OpenRouter, or point it at a local LLM. No lock-in, no abstractions, no dependencies beyond Node.js.

you> add error handling to server.ts [file] read server.ts (42 lines) [file] wrote server.ts with try/catch blocks [memory] saved: "server.ts uses express error handler" agent> Added error handling to server.ts — wrapped the route handlers with try/catch and added a central error handler middleware. Saved a note to memory.

Course-correct
without aborting

Press Tab while the agent is working to open a steer> prompt. Type a new direction, press Enter. The agent sees your message on the next turn and adjusts — current tool calls finish uninterrupted.

Tab opens the steer prompt and pauses output. Enter submits and resumes. Escape aborts the current run.

Steer messages are queued and injected before the next LLM call. You can steer multiple times — each message is delivered in order.

you> build an API with auth [bash] npm init... ← press Tab steer> use PostgreSQL not SQLite ← press Enter [steered] use PostgreSQL not SQLite [bash] done ⠧ thinking [2/200] ← LLM adjusts

Why persistent agents win

Every coding agent on the market treats a session as disposable. You open a terminal, load context, do work, close the terminal, and everything the agent learned evaporates. Next session starts from scratch. It's session zero, every time.

ag's memory, checkpoints, result refs, and turn summaries aren't four separate features bolted together. They're one coherent system for persisting reasoning over time. Memory preserves decisions across sessions. Checkpoints snapshot conversation and file state at every turn, so you can rewind without fear. Result refs cache large tool outputs to disk and replace them with summaries, keeping your context window clean without losing information. Turn summaries compress history into structured state—goals, outcomes, file paths, errors—so the agent remembers what it did, not just what it said.

Together they mean the agent accumulates competence on your project. Session two is better than session one. Session twenty knows your architecture, your test patterns, your past mistakes. This isn't chat history you scroll through. It's state that compounds.

ag isn't a smaller Claude Code or a bigger pi. It's a different bet about what coding agents are for.

Built for persistence

01
Mm
Memory
3-tier persistent memory. Global preferences, project decisions, timestamped plans. All plain markdown you can edit directly.
02
Sk
Skills
Install prompt skills from skills.sh. Or write your own SKILL.md files. The agent activates them on demand when a task matches.
03
Tl
Tools
14 built-in tools: bash, file, memory, plan, git, grep, web, skill, task, agent, content, result, history, self. Add your own: drop a .mjs file in ~/.ag/tools/ or call agent.addTool() from an extension.
04
Ma
Any Model
Any model with tool calling via OpenRouter. Or point at Ollama, LM Studio, or any OpenAI-compatible API.
05
Hk
Hackable
~9500 lines of readable TypeScript. No abstractions, no magic. Fork it, extend it, understand every line.

Agents all the way down

06
Pl
Plans
Interactive REPL sessions start in plan mode so you can review the approach first. Press Shift+Tab to switch to auto and carry the work through. Plans stay as plain markdown.
07
Tk
Tasks
Track multi-step work with create, list, update, read, remove, clear. Link tasks to sub-agents for automatic progress tracking.
08
Sa
Sub-Agents
Spawn independent agents for parallel work. Link to tasks, route to cheaper models. Sub-agents inherit memory, plans, skills, and extensions.
09
St
Steering
Press Tab to course-correct mid-execution. Type a new direction, press Enter. The agent adjusts on the next turn without aborting current work.
10
Ex
Extensions
TypeScript lifecycle hooks with 12 events. Intercept tool calls, inject context, block commands, customize compaction, observe finish reasons and API metadata. Register custom tools at runtime. Project or global scope.
11
Ct
Content
Send images and PDFs in your prompts. Paste from clipboard, capture screenshots. Content is sent once then referenced by pointer — the agent can recall it on demand.

Smart about context

12
Cp
Checkpoints
Auto-created at every turn start via a local shadow repo, capturing all file changes including bash. /checkpoint lists newest first; /rewind shows a change preview before rollback.
13
Rf
Result Refs
Large tool outputs (>2KB) are cached to disk and replaced with summaries in context. The agent retrieves the full content on demand via result(action=get).
14
Ts
Turn Summaries
Turns with 3+ tool calls are auto-summarized. Older turns are replaced with LLM-generated summaries in API requests. Large write arguments collapse after the first turn.
15
Hs
History
Conversation history is persisted to history.jsonl. Search or browse past turns with history(action=search) and history(action=recent). Session state is restored on restart.

Built-in guardrails

16
Zd
Zero Deps
Zero npm dependencies. ~130kB packaged. Node.js 20+ and TypeScript. Nothing to audit, nothing to break.
17
Cx
Context
Real-time context window tracking with visual breakdown. Shows token usage by system prompt, environment, memory, skill catalog, tool definitions, custom tools, and interactions. Auto-compacts at 90%. Set contextLength for local models.
18
Pc
Prompt Cache
Automatic ephemeral cache control for Anthropic models. Tracks cache hit rate and shows tokens saved in the context display.
19
Gr
Guardrails
Scans custom tools and skills for injection attacks, exfiltration attempts, hidden content, and encoded payloads. Loop guards stop repeated same-file edits without a read or verification step.
20
Pm
Permissions
Three-scope access control: session, project, global. Glob-based patterns like bash(npm:*). Deny rules always win. Read-only tools, including built-in web(fetch|search), are auto-approved.

One line to start

Try it
$npx @elementics/ag
Install permanently
$npm i -g @elementics/ag

Prompts for your OpenRouter API key on first use. REPL starts in plan mode; press Shift+Tab to switch to auto.

ag # interactive REPL (starts in plan mode) ag "what files are here?" # one-shot mode ag -m anthropic/claude-sonnet-4.6 "help me" # pick a model ag --stats # show memory status
Run with local models
# Install Ollama brew install ollama # Start the Ollama service ollama serve & # Pull Gemma 4 ollama pull gemma4 # Run ag against it (no API key needed) ag -b http://localhost:11434/v1 -m gemma4 "what tools do you have?"
# Or set it permanently in the REPL /config set baseURL http://localhost:11434/v1 /config set model gemma4 /config set contextLength 131072
cli/
repl.ts interactive REPL, /noun commands
cli.ts · parser.ts entry point, arg parsing
core/
agent.ts the loop, sub-agents, steering
permissions.ts 3-scope access control with globs
guardrails.ts prompt injection scanning
events.ts · extensions.ts lifecycle hooks, extension loading
skills.ts · registry.ts skill discovery, skills.sh install
context.ts · compaction.ts context tracking, auto-compaction
checkpoint.ts · shadow.ts shadow snapshots + checkpoint metadata
ledger.ts · traces.ts loop state, guard stops, JSONL traces
results.ts · summarization.ts result ref cache, turn summarization
content.ts image/PDF ingest, caching, send-once
+ 8 more config, prompt, types, loader, colors, ...
memory/
memory.ts memory, plans, tasks, history
tools/ — 14 files, one per tool
bash · file · git · grep shell, files, version control, search
memory · plan · task persistence, plans, task tracking
result · history result ref cache, history search
agent · skill · web · content · self sub-agents, skills, web, content, self-management

~130kB packaged.
That's the whole agent.

The core is a tool-calling loop in agent.ts. It sends messages to any OpenAI-compatible API, executes tool calls, and repeats. Sub-agents spawn parallel workers. Extensions hook into 12 lifecycle events. Steering lets you course-correct mid-execution. Checkpoints snapshot files and conversation at every turn. A per-turn ledger tracks edits, reads, verification, and guard stops. Memory is injected into every system prompt. Context auto-compacts at 90%.

Every tool is a single file with a type definition and an execute function. Custom tools and skills are scanned by guardrails before loading. Permissions use glob-based patterns across three scopes. Dangerous bash commands are blocked before they run.

~130kB
Package size
~9.5k
Lines of TS
0
Dependencies

Write a tool
in 30 lines

Drop a .mjs file in ~/.ag/tools/ for global tools or .ag/tools/ for project-local tools. Export a tool object with a name, description, parameters, and an execute function.

Add a permissionKey to wire your tool into the permission system. The qualifier maps a tool argument to permission patterns — so deploy(staging) and deploy(production) can have separate rules.

Guardrails automatically scan every custom tool for injection patterns, exfiltration attempts, and hidden content before it loads.

~/.ag/tools/deploy.mjs
export default { type: 'function', function: { name: 'deploy', description: 'Deploy to a target environment', parameters: { type: 'object', properties: { target: { type: 'string', enum: ['staging', 'production'], }, }, required: ['target'], }, }, // Permission pattern: deploy(staging), deploy(production) permissionKey: { qualifier: 'target' }, async execute({ target }) { const res = await fetch(`https://deploy.internal/${target}`); return `Deployed to ${target}: ${res.status}`; }, };

Hook into everything

Extensions are TypeScript files that hook into the agent's lifecycle. Place them in .ag/extensions/ (project) or ~/.ag/extensions/ (global). They're loaded at startup and can intercept, modify, or extend any behavior.

Each extension exports a default function that receives the agent instance. Use agent.on() to subscribe to events and agent.log() for spinner-safe output. Handlers run sequentially — each sees mutations from the previous one.

Extensions can block tool calls, inject context into every LLM request, customize compaction behavior, add tools at runtime, and programmatically steer the agent.

.ag/extensions/log-tools.ts
export const name = 'log-tools'; export const description = 'Logs tool calls and errors'; export default function(agent: any) { agent.on('tool_call', (event: any) => { agent.log(`[log] ${event.toolName}`); }); agent.on('tool_result', (event: any) => { if (event.isError) agent.log(`[log] error: ${event.content}`); }); }

Lifecycle Events

input # User message arrives — writable: content, skip turn_start # Top of each iteration — iteration, maxIterations, messageCount before_request # Before LLM API call — writable: messages, systemPrompt | readable: model, stream, baseURL, provider, maskedKey, compacted request_ready # Body resolved, before fetch — readable: url, body after_response # After LLM response parsed — readable: message, usage, finishReason, model, baseURL, provider tool_call # Before tool executes — writable: args, block, blockReason | readable: toolName, toolCallId tool_result # After tool executes — writable: content, isError | readable: toolName, toolCallId, args before_compact # Before context compaction — writable: cancel, customSummary | readable: messageCount after_compact # After context compaction — readable: messagesRemoved, newMessageCount, summaryPreview turn_end # After iteration completes — iteration, hadToolCalls, toolCallCount checkpoint_create # After checkpoint created — id, label, messageIndex, turnNumber checkpoint_restore # Before rewind executes — writable: cancel | readable: id, mode

Agent API

The agent object passed to your extension exposes these methods:

on(event, handler) # Subscribe to events (returns unsubscribe fn) log(message) # Spinner-safe stderr output addTool(tool) # Register a new tool at runtime activateSkill(name) # Activate a skill by name queueSteer(message) # Programmatically inject a steer message compactNow() # Force context compaction getModel() / setModel(m) # Read or change the active model getCwd() # Working directory isSilent() # True if running as a sub-agent getLoadedExtensions() # List loaded extension metadata
Extensions can also block tool calls (event.block = true), rewrite the system prompt via before_request, provide a custom compaction summary, or add tools dynamically with addTool(). Check agent.isSilent() to skip output when running inside a sub-agent.

Permissions that
make sense

Session
Lasts until you close ag. For one-off approvals during a single session.
in-memory only
Project
Persisted per project. Share via git so your team gets the same rules.
.ag/permissions.json
Global
Applies to every project. Set once for tools you always trust.
~/.ag/permissions.json
bash(npm:*) # allow all npm commands file(write:src/**) # allow writes under src/ git(commit) # allow git commit web(fetch:*.github.com*) # fetch from GitHub deploy(staging) # custom tool permission
Deny rules always win. Read-only tools (grep, file read, git status) are auto-approved without prompting. Dangerous bash commands like rm -rf /, fork bombs, and pipe-to-shell patterns are always blocked regardless of permissions.

When to use something else

Claude Code
If you want MCP, git worktrees, and polished IDE integration. ag has sub-agents, tasks, and extensions but is terminal-only.
aider
Git-centric workflow with commit-per-change and diff-based editing.
Cursor / Windsurf
IDE integration. ag is terminal-only by design.
ag
Hackable, persistent, model-agnostic agent with sub-agents, extensions, steering, and fine-grained permissions. Terminal-native. Zero dependencies.

Frequently Asked Questions

Does ag send my code anywhere?
Only what you explicitly share in messages goes to your chosen model provider (OpenRouter by default). Memory, plans, history, and all project data are stored locally in ~/.ag/. Nothing is sent to elementics.
What models does ag support?
Any model with tool calling via OpenRouter — Claude, GPT-4o, Gemini, Llama, Mistral, and hundreds more. Or point at a local LLM via Ollama, LM Studio, or any OpenAI-compatible API.
How do I use a local model?
ag -b http://localhost:11434/v1 -m gemma4 for Ollama — no API key needed. Set it permanently with /config set baseURL ... and /config set contextLength 131072 for context tracking.
How do I prevent ag from running certain commands?
Use the permissions system: /permissions deny bash(rm:*) blocks all rm commands. When prompted, press d to deny for the session or D to save a deny rule permanently. See the full permissions docs.
Can I use ag in CI or headless mode?
Yes. ag -y "run tests and fix failures" auto-approves all tool calls. Combine with -m to choose a model and -n to limit iterations.
How do I share context across my team?
Commit the .ag/ directory to version control. Project memory, plans, skills, custom tools, and permissions are all plain files that version-control normally.
What's the difference between memory and plans?
Memory stores persistent facts that apply across sessions ("we use PostgreSQL", "deploy to Vercel"). Plans are structured task context for the current piece of work, with steps and progress tracking.
How do I attach images or PDFs?
/content add photo.png attaches it to your next message. /content paste grabs from clipboard, /content screenshot captures a screen region. Supports PNG, JPEG, GIF, WebP, and PDF.
Can I undo what ag just did?
Yes — /rewind restores any checkpoint. Checkpoints are created automatically at every turn, so you can always go back. Choose to restore code, conversation, or both.
How do I install a skill?
/skill search frontend to browse the registry, /skill add <name> to install. Or drop a SKILL.md in .ag/skills/ for project-local skills. See the skills docs.