A local coding agent core in Python: models emit structured actions, the core validates and executes them behind hard safety boundaries, and every run leaves a durable, redacted record.
v2.2.0 · ~17k lines of source, ~19k lines of tests (988 cases) · Python 3.11+ · runs against your own provider
| Area | What it does |
|---|---|
| Agent loop | Models emit structured JSON actions; the core validates, executes, and feeds bounded observations back with a consecutive-error budget |
| Tools | File, shell, git, web, and document (PDF / DOCX / XLSX / PPTX) tools behind one action/observation protocol |
| Providers | Anthropic-native, DeepSeek, any OpenAI-compatible endpoint (including local Ollama), plus a FakeLLM so end-to-end tests need no network |
| MCP | Local stdio Model Context Protocol servers via the official SDK 1.28.1; every exposed tool call is separately approval-gated |
| Safety | Workspace sandbox, approval gates, dry-run, snapshots before writes, redacted durable logs, per-source context budgets — see Safety Model |
| Interfaces | agent run (one-shot), agent chat (terminal, resumable), agent start (local React Workbench with SSE streaming) |
| Extensions | Managed skills and MCP configuration with atomic, crash-recoverable writes under ~/.agent/ |
This README doubles as the working document for each release slice. Start with Quickstart below; the
v0.xsections further down are kept as historical decision records rather than current-state documentation.
Run a fake agent task:
agent run "inspect project"Run in a specific workspace:
agent run --cwd F:\agent "inspect project"Inspect available tools and effective configuration:
agent tools list
agent config show --cwd F:\agent
agent config doctor --cwd F:\agent
agent doctorDry-run records intent and skips write tools and shell commands:
agent run --dry-run "write a note"Inspect run logs:
agent runs list
agent runs show <run-id>Runs write durable files under .agent/runs/<run-id>/. Write tools create
snapshot records before changing files; agent runs show <run-id> displays
snapshot paths and restore hints when a run changed files.
# .agent/config.toml
provider = "openai-compat"
base_url = "http://localhost:11434/v1" # e.g. Ollama
model = "llama3"
# api_key_env = "OPENAI_API_KEY" # optional; empty key sends no Authorization header
# native_tools = true # use native tool calling (requires endpoint tool support)With native_tools = true the agent uses native function calling with tool_choice: "auto" (thinking-mode models such as DeepSeek reject "required"); a plain-text reply without a tool call is routed through the repair channel. Endpoints without tool support should keep it false.
For endpoints that only speak the Anthropic Messages protocol
(/v1/messages), such as some API relays:
# .agent/config.toml
provider = "anthropic"
model = "claude-sonnet-5"
api_key_env = "ANTHROPIC_API_KEY" # env var holding the key; empty sends no x-api-key header
# base_url = "https://relay.example.com" # origin only, no /v1; defaults to https://api.anthropic.comThis provider uses the JSON action protocol (native_tools stays false);
streaming chat is supported. Relays that expose an OpenAI-compatible endpoint
can keep using openai-compat instead. Verify connectivity with
agent provider smoke anthropic.
Local MCP servers are configured only in the user-level ~/.agent/mcp.toml.
Project .agent/config.toml files and repository files cannot grant permission
to start an MCP process.
[servers.example]
command = "C:/Python313/python.exe"
args = ["D:/mcp/example_server.py", "--workspace", "{workspace}"]
cwd = "config" # "config" (default) or "workspace"
pass_env = ["EXAMPLE_API_KEY"] # variable names only; values come from the environmentOn Windows, command must resolve to a native .exe or .com; relative paths
are rejected. An argument equal to {workspace} is replaced with the resolved
workspace path. cwd = "workspace" is explicit trust: imports and configuration
discovery performed by that server can then be influenced by project files, so
prefer the default config working directory.
Adding a server is startup authorization. The server process has the Agent
user's OS permissions and may access files, the network, or child processes;
the Agent workspace sandbox does not contain code running inside that process.
Every exposed MCP Tool call is separately classified as
confirmation-required. sandbox = "read-only", dry-run, and
approval = "never" can still start a configured server for discovery, but
they never send tools/call.
Secrets belong in environment variables named by pass_env, never in
command, args, or TOML values. MCP metadata and results are untrusted,
schema-checked, bounded, redacted, and routed through the same catalog,
approval, observation, and trace path as built-in Tools. Public names use
mcp__<server-id>__<normalized-tool-name>; collisions and unsafe schemas fail
closed before the model is called.
Configuration is snapshotted for the lifetime of the CLI/Workbench process;
restart it after editing mcp.toml. Configuration errors fail before server
startup, while initialize or discovery failures stop the run/chat job before a
model call and close processes already started by that Runtime. This first
catalog remains all-or-nothing. After the Runtime is ready, a request timeout,
EOF, process exit, or transport/protocol failure retires only the affected
server; healthy servers and built-in Tools remain available. Calls are never
replayed, reconnected, or restarted automatically. Failure to stop one owner
within the close grace period, or failure of the shared Runtime loop, still
closes the whole Runtime. This first slice supports local stdio Tools only:
there is no remote transport,
Marketplace, management UI, automatic reconnect, or install/update lifecycle.
agent tools list intentionally remains a built-in-only inventory and does
not start configured MCP servers.
Hand-written ~/.agent/mcp.toml keeps working unchanged. Managed servers add
~/.agent/mcp.d/<server-id>.toml fragments plus ~/.agent/mcp-state.json,
which records only the disabled server IDs:
agent mcp list
agent mcp show <server-id>
agent mcp validate <server-id>
agent mcp set <server-id> --command C:\Python313\python.exe --arg D:\mcp\server.py --pass-env EXAMPLE_API_KEY
agent mcp enable <server-id>
agent mcp disable <server-id>
agent mcp remove <server-id>
agent mcp doctorlist, show, validate, set, enable, disable, and remove are
static: they never start a server process. agent mcp show prints one server's
source, enabled state, static status, and parsed command/args/pass_env names.
Only agent mcp doctor starts the currently
enabled servers, and it does so through one Runtime that always closes in a
single finally. Manual mcp.toml entries are read-only to these commands;
set and remove refuse to touch them. A state entry whose source has
disappeared is reported as an orphan, is ignored by normal runs, and can be
cleaned with agent mcp remove.
Configuration is still snapshotted per process. enable, disable, and set
never change a Runtime that has already discovered its tools; restart the CLI
or Workbench, or start a new run, before the new state applies.
Skills load from three sources: packaged builtins, project
.agent/skills/<name>/, and user ~/.agent/skills/<name>/. Project skills
still override builtins. A user skill that collides with a builtin or project
name fails closed with an actionable diagnostic instead of silently shadowing
it; ~/.agent/skills-state.json records only the disabled user skill names.
agent skills list
agent skills show <name>
agent skills validate <source>
agent skills install <source>
agent skills enable <name>
agent skills disable <name>
agent skills update <name> <source>
agent skills package <name> --output D:\out\<name>.skill.zip
agent skills remove <name>
agent skills doctorA source is either a local directory whose root contains SKILL.md, or a
.skill.zip archive produced by agent skills package whose root contains
SKILL.md. URLs, Git clones, and registry IDs are not supported; fetch the
files yourself first. The frontmatter name is authoritative, so a source
directory may carry a version suffix while the installed directory always
matches the frontmatter name.
Candidates are validated before and after staging: at most 128 regular files,
8 MiB total, 1 MiB per file, and 256 KiB for SKILL.md. Absolute paths, drive
letters, UNC paths, .., NUL, symlinks, junctions, reparse points, and device
files are rejected, and archives are streamed member by member instead of
being unpacked wholesale. Scripts, templates, and other ordinary resources are
copied but never executed by validate, install, update, package, or
doctor.
install only creates a new skill and enables it without touching
default_skills; update requires an existing user skill and a candidate with
the same name, keeps the disabled state, and leaves the old version in place if
the candidate fails. package writes a temporary file next to the output,
verifies the whole archive, and then publishes it with a no-clobber hard link,
so an existing target is never overwritten. enable, disable, update,
package, and remove apply to user skills only; builtin and project skills
are managed by the package and the project.
Skill content stays untrusted context. Installing or enabling a skill never
widens the Tool catalog, bypasses policy or approval, or raises instruction
priority; allowed_tools can only narrow what a run may call.
agent hooks list prints every builtin hook with its enabled/blocking state
and flags config references to unknown hook names; unknown names also produce
a config warning: line in agent doctor and agent config show.
agent hooks list
agent config set <key> <value...>
agent config unset <key>agent config set writes one validated key to the project
.agent/config.toml through the same atomic publish path the Workbench uses;
list keys such as default_skills take multiple values. It refuses
sandbox danger-full-access and approval never because project config
cannot widen those settings; edit the global config by hand instead.
agent config unset removes a project key so the global or default value
applies again. The top-level agent doctor now also prints one-line MCP and
Skills summaries and points to agent mcp doctor / agent skills doctor for
detail.
Every user-level write takes ~/.agent/.extension.lock, publishes single files
through a temporary file plus os.replace, and routes directory or
state changes through ~/.agent/.extension-transactions/. A new process
recovers its own interrupted transaction before reading, so it observes either
the complete old state or the complete new state, never a missing target or a
mixed pair.
If a command reports a malformed record, several conflicting transactions, an
untrusted ownership marker, or a failed recovery, it fails closed and keeps the
evidence rather than guessing what to delete. Run agent mcp doctor and
agent skills doctor to see what is affected, then remove only the reported
item with agent mcp remove or agent skills remove.
This slice stays local: there is no Marketplace, registry, URL or Git install, Workbench lifecycle UI for MCP/Skills, automatic reconnect, or Provider capability negotiation.
run_command keeps a small safe default set. Add explicit argv prefixes only when a project needs more commands:
# .agent/config.toml
allowed_commands = ["python", "pip show", "npm test"]Prefixes match complete argv tokens. The executable token is case-insensitive and ignores a trailing .exe; later tokens are case-sensitive, so pip Show does not match pip show. Short prefixes grant more capability, so prefer the narrowest useful entry.
An allowlist cannot override hard-denied shell wrappers, network commands, or dangerous commands. Allowlisting only passes command admission: under the default policy, run_command still requires approval and its argv still passes the existing workspace path checks. Approved commands run as local processes with the agent's OS permissions. Those path checks do not fully contain file, network, or subprocess access from inside the process; allowed_commands is capability authorization and approval is execution confirmation, not an OS or container sandbox. Commands such as pytest and python -m pytest execute project code.
For example, allowed_commands = ["git commit"] intentionally bypasses the default read-only Git restriction, but git commit still requires approval before execution.
The default guided mode allows three actions, which is useful for short conversations but often too small for a coding task that must inspect, edit, and verify files. Select auto in Workbench Settings, or set it in project configuration:
# .agent/config.toml
mode = "auto"auto raises the action budget to ten without changing approval or sandbox rules.
agent start is the one-command Workbench startup alias. It reuses agent ui
and starts the same local stdlib Workbench without a new server layer:
agent start --cwd F:\agent
python -m agent.cli start --cwd F:\agentSettings Readiness is backed by /api/health. It shows the active provider,
model, provider-specific API-key requirement/presence, base URL readiness,
loaded config files, and warnings. The current Settings page can save a narrow
set of non-secret project options through /api/config; API keys stay in the
environment or .agent/secrets.env, and config publication is atomic.
The historical v1.0 Settings Page Decision is recorded in
docs/v1.0-settings-page-decision.md. It kept browser settings read-only for
that release; later Workbench slices superseded that restriction for the
bounded non-secret fields described above.
Check release readiness without running tests or network calls:
agent release doctor --cwd F:\agentThe output includes release readiness: complete, legacy local-baseline route
completion, startup command: agent start, provider/model, settings write policy,
packaging status, and the verification commands to run manually.
v1.0 Packaging Decision is recorded in docs/v1.0-packaging-decision.md:
binary packaging is deferred; agent start remains the release startup path.
v1.0 closeout is recorded in docs/v1.0-acceptance.md. The local visual agent
release prep is frozen around agent start, Settings Readiness, release
readiness doctor, and deferred binary packaging.
post-v1.0 Polish Backlog is recorded in
docs/post-v1.0-polish-backlog.md; it keeps copy, manual smoke, accessibility,
safe secret flow, and packaged executable work ordered after v1.0.
post-v1.0 Manual Smoke Checklist is recorded in
docs/post-v1.0-manual-smoke.md for release readiness, DeepSeek terminal chat,
and Workbench browser chat.
post-v1.0 Polish Closeout is recorded in
docs/post-v1.0-polish-closeout.md; speculative polish is frozen until there
is user-directed feature work.
Local DeepSeek secrets can live in .agent/secrets.env, which is ignored by
git:
DEEPSEEK_API_KEY=...
agent doctor, agent config show, agent config doctor, agent release doctor,
provider smoke, terminal chat, and the Workbench read this file before checking
key presence. A real environment variable still wins if both are set.
Do not put API keys in .agent/config.toml.
The React/Vite Workbench is the only runtime frontend, with two stable React entries:
| URL | Current runtime entry |
|---|---|
/ |
React preview/index.html |
/preview/ |
React preview/index.html |
src/agent/web/static/preview/** is a tracked runtime asset. Node.js belongs
only to development and build workflows. The Python runtime never invokes npm
and serves the packaged files directly. The retired /legacy, /legacy/, old
/assets/**, and synchronous POST /api/chat/turn paths return 404; current
chat uses POST /api/chat/start plus SSE and the approval/cancel/resume routes.
The current Files workspace lazy-loads Monaco on desktop, keeps up to 20
independent tabs, and falls back to a native textarea below 768px. Recursive
workspace search uses GET /api/search?query=<text-or-glob> and opens text
matches at their line. Saves still use /api/file/save, explicit confirmation,
and a snapshot-backed run; search is read-only and bounded by the workspace
sandbox.
After changing frontend source, rebuild and verify the complete bundle:
Set-Location frontend
npm ci
npm run build:preview
Set-Location ..
git diff --exit-code -- src/agent/web/static/preview
git ls-files --others --exclude-standard -- src/agent/web/static/preview
agent start --cwd . --port 8767Commit the complete generated bundle with its source change; a clean tree must
reproduce it with npm run build:preview and no Git drift. Open
http://127.0.0.1:8767/ for the default React Workbench. /preview/ remains a
compatible React entry. A rollback restores the Phase 3I retirement Git commit
and restarts the service; it does not migrate workspace data.
Run the complete frontend gate from frontend/ with npm run check. Phase 2,
Readiness, Cutover, and Phase 3E–3I evidence is recorded under
docs/verification/.
Pending states render a thinking-orbs canvas indicator whose shape tracks what
the agent is actually doing: reasoning, streaming, reading, writing, running a
command, waiting for approval, rebuilding, or connecting. The mapping lives in
frontend/src/Orb.tsx; unknown actions, including every MCP tool, fall back to
the generic working orb. Settled phases (idle, final, error) and button
busy states keep their existing icons on purpose. Each animating orb costs
roughly 1.3 FPS, so a view shows at most one; prefers-reduced-motion: reduce
pins every orb to a single static frame.
v0.7 starts by keeping the Workbench shell boring: no Vue, Vite, Electron, or
Tauri until the static UI actually hurts. The decision record lives at
docs/v0.7-shell-decision.md and defines the migration triggers for a future
frontend or desktop shell. The Workbench also has a Task Review panel for the
selected run: latest action, last observation, changed files, snapshot count,
and suggested manual checks.
v0.7 closeout is recorded in docs/v0.7-acceptance.md. v0.7 manual smoke:
$env:PYTHONPATH="src"
python -m agent.cli ui --cwd F:\agent
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/health
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/runs
python -m pytest tests/test_ui.py tests/test_docs.py tests/test_cli.py -q
python -m pytest -q
git diff --checkv0.8 starts with a read-only Workflow Hints panel in the Workbench. The selected
run now includes workflow.verification_commands and review steps derived from
Task Review changed files. The panel suggests commands such as targeted pytest
runs and git diff --check; it does not execute commands or create commits.
The Workbench also includes a read-only Failure Summary panel. It reads failed
observations from the selected run, shows latest_failure, and suggests next
checks. It does not retry tools, edit files, or infer a fix on its own.
The Provider Notice banner is derived from the same Provider registry as the CLI. It reports FakeLLM, DeepSeek, or OpenAI-compatible base URL/auth readiness without storing or exposing API-key values.
The Patch Review Helper completes the read-only coding workflow. It combines
Task Review, Workflow Hints, Failure Summary, and snapshots into one checklist
with risk_level, checks, verification commands, and a next action. It does
not run tests, create commits, or generate patches.
v0.8 closeout is recorded in docs/v0.8-acceptance.md. v0.8 manual smoke:
$env:PYTHONPATH="src"
python -m agent.cli ui --cwd F:\agent
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/health
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/runs
python -m pytest tests/test_ui.py tests/test_docs.py tests/test_cli.py -q
python -m pytest -q
git diff --checkv0.9 starts with a read-only Run Risk Filter in the Workbench. The run list now
shows each run's status and risk_level, and the sidebar can filter by low,
medium, or attention runs. This improves visual agent progress from a useful
Workbench toward a more dependable visual agent without executing commands from
the browser.
The Workbench also includes a read-only Run Replay panel. It reconstructs the
selected run from stored tool_calls.jsonl records, showing each action,
observation status, summary, policy decision, and terminal step. It does not
call the model again, execute tools, or mutate workspace files.
Log Filters narrow the selected run's Trace and Run Replay panels by action, status, summary text, or terminal/non-terminal steps. Filtering is local and read-only; it does not change durable logs.
Workspace Risk shows a read-only health hint for uncommitted files, failed
recent runs, and snapshots. It uses the existing /api/health refresh path and
does not execute tests, restore files, or mutate the workspace.
Memory Review shows pending memory candidates and active accepted entries in
the Workbench. It is read-only; accepting, rejecting, revising, deleting, and
auditing memory still happens through explicit agent memory ... commands.
Failure Recovery adds read-only recovery guidance for failed runs. It reports
whether rollback_available is true, points to Trace and Failure Summary, and
keeps retry, patching, and rollback decisions in terminal/manual flows instead
of browser automation.
v0.9 closeout is recorded in docs/v0.9-acceptance.md. v0.9 manual smoke:
$env:PYTHONPATH="src"
python -m agent.cli ui --cwd F:\agent
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/health
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/runs
python -m pytest tests/test_ui.py tests/test_docs.py tests/test_cli.py -q
python -m pytest -q
git diff --checkv0.6 starts the Apix-style visual direction with a local web workbench. It
reuses the existing Python core and durable logs; it does not replace
agent run or agent chat.
Start the workbench:
python -m agent.cli ui --cwd F:\agentOpen the printed URL, usually:
http://127.0.0.1:8000
The workbench shows a Runs Dashboard, effective config, tool catalog, run
summary, and tool-call trace. It also supports a basic browser chat turn from
the bottom input dock; each turn creates the same durable .agent/runs and
.agent/chats records as terminal chat.
Browser chat streams model output live: thinking (reasoning_content) and
tool-argument fragments render into the collapsible 工作过程 area, and plain
content streams into the reply bubble before the final answer replaces it.
An active React chat exposes a Stop control. Cancellation and whole-turn timeout
persist an auditable terminal turn; after refresh or service restart, the next
user message can resume the same session without replaying the previous Tool.
The input dock has three clickable config toggles (联网 / 电脑文件 / 原生工具)
that write through /api/config, plus a 工作过程 visibility switch remembered
in localStorage. Other status details live in the settings panel.
Confirmation-required actions use a custom approval panel and then retry the
same message with one approved action. The Files panel lists workspace files
and opens text previews in a minimal file editor. The Save button uses the same
custom approval panel, then calls /api/file/save, writes the text file, and
records a run snapshot before the change. The Snapshots panel shows run
snapshot paths and restore hints when a run changed files. The Diff Viewer uses
/api/diff to show a read-only unified diff between a snapshot and the current
file. The Restore button uses the same approval panel before restoring or
deleting the changed file from snapshot metadata. The Activity panel shows
status-level live events for browser turns, approval waits, saves, restores,
completion, and failures. The Status Bar shows workspace, provider, model,
session, active-provider API-key status, and last refresh time. Auto-refresh updates
health and runs every 10 seconds without replacing an open file editor or
pending approval, and the Refresh button performs the same safe refresh on
demand. The Task Review panel summarizes the selected run's latest action, last
observation, changed files, snapshot count, and suggested manual checks.
Current v0.6 limits: the file editor is a single textarea and Electron
packaging is deferred. (Browser chat later became asynchronous with SSE, and
token-level UI streaming landed with the workbench streaming slice.)
v0.6 manual smoke:
$env:PYTHONPATH="src"
python -m agent.cli run --cwd F:\agent "inspect project"
python -m agent.cli ui --cwd F:\agent
Invoke-RestMethod -Uri http://127.0.0.1:8000/api/health
python -m pytest tests/test_ui.py tests/test_cli.py tests/test_docs.py -q
python -m pytest -q
git diff --checkworkbench success criteria:
- Runs Dashboard loads recent runs and selecting a run shows summary, trace, and snapshots.
- Status Bar shows workspace, provider, model, session, active-provider API-key status, and last refresh.
- Browser chat turn creates a durable run and shows status/final output.
- Approval panel handles confirmation-required chat retries, file saves, and snapshot restores.
- Files panel opens text files in the file editor; Save button writes through
/api/file/savewith a snapshot. - Diff Viewer shows
/api/diffoutput and Snapshots panel shows restore hints. - Task Review panel shows latest action, last observation, changed files, snapshot count, and suggested manual checks.
- Refresh does not overwrite an open file editor or pending approval.
v0.5 adds an interactive terminal loop on top of the same structured action protocol. Start a chat in a workspace:
agent chat --cwd F:\agentEach turn prints status-level live output such as model calls, parsed actions,
tool execution, and approval waits. With DeepSeek chat, provider token streaming
also prints a raw model response preview while the JSON action is arriving.
A completed turn shows status,
completed, terminal_reason, final, and the backing run summary path.
$env:DEEPSEEK_API_KEY="..."
agent chat --cwd F:\agent --provider deepseek --model deepseek-v4-flash
agent chat --cwd F:\agent --timeout-seconds 900--timeout-seconds accepts 1–3600 seconds. Pressing Ctrl+C during a turn cancels
that turn, finalizes its run record, and returns to the chat prompt.
Resume a saved chat session:
agent chat --resume <chat-id>Chat sessions are stored under .agent/chats/<chat-id>/. Saved session JSON is
redacted before it is written. Each chat turn still creates a normal
.agent/runs/<run-id>/ directory.
When a write, patch, shell, or report action needs confirmation, chat prints
approval required and asks for approve? [y/N]. Confirming executes the
same action; denying returns a standard approval-denied observation. Non-chat
agent run keeps fail-fast approval behavior.
Reference workspace context explicitly with @file or @dir:
agent chat --cwd F:\agent
agent> summarize @README.md and inspect @srcReferenced content is loaded through the workspace sandbox, bounded by the context budget, and marked as untrusted context.
Chat slash commands are handled locally and do not call the model:
/help
/status
/transcript
/exitv0.5 manual smoke:
$env:PYTHONPATH="src"
python -m agent.cli chat --cwd F:\agent
python -m agent.cli chat --cwd F:\agent --provider deepseek --model deepseek-v4-flash
python -m agent.cli chat --cwd F:\agent --resume <chat-id>
python -m agent.cli runs show <run-id>
python -m pytest tests/test_chat.py tests/test_cli.py tests/test_deepseek.py tests/test_docs.py -q
python -m pytest -q
git diff --checklive chat success criteria:
chat_idis printed when the session starts.- DeepSeek chat shows
raw model response previewbefore the parsed action result. - Completed turns show
status: ok,completed: true,terminal_reason: done, and a natural-languagefinal. /statusshows the current turn count and latest result;/transcriptshows recent turns.- Denied chat approvals return
APPROVAL_DENIED; non-chatagent runstill fails fast for required approvals.
- Models emit structured JSON actions; the core validates and executes them.
- Built-in file and document tools enforce the configured path policy: workspace-only by default, with explicit read-only computer access when enabled. Command argv path checks do not fully contain access performed inside an approved local process.
- Risky actions such as
write_file,apply_patch, andrun_commandrequire approval and fail fast in the non-interactive v0.1 CLI. --dry-runskips write tools and commands without side effects.- Durable logs are redacted before they are written.
- Workbench binds only to loopback addresses, rejects non-loopback Host headers and cross-origin writes, and does not claim to be a production HTTP server.
AGENTS.md, command output, git diffs, and document contents are untrusted context and cannot override policy or tool schemas.- Recoverable tool errors are fed back to the model with a consecutive-error budget (
max_consecutive_errors, default 3). Approval denials and hook blocks always terminate the run immediately.
Run the test suite:
python -m pytest -q
git diff --checkv0.2 keeps fake as the default provider. To use DeepSeek, set an API key and
select the provider explicitly:
$env:DEEPSEEK_API_KEY="..."
agent run --provider deepseek --model deepseek-v4-flash "inspect project"Provider diagnostics never make a network request:
agent doctor
agent config doctorInspect skills:
agent skills list
agent skills show code-dev
agent run --skill code-dev "fix failing tests"Review and manage memory:
agent memory review
agent memory accept <candidate-id>
agent memory reject <candidate-id>
agent memory list
agent memory revise <entry-id> "replacement text"
agent memory history <entry-id>
agent memory delete <entry-id>
agent memory undo <entry-id>undo remains a compatibility alias for delete. Candidate decisions are
single-use, and list returns only the current active leaf of each revision
history.
Run explicit local automations:
agent automation add "inspect project" --every-minutes 60
agent automation list
agent automation enable <automation-id>
agent automation worker --once
agent automation attempts
agent automation notifications
agent automation cancel <attempt-id>
agent automation disable <automation-id>Automations use fixed UTC minute intervals and run only while the foreground
worker is active; no service or cron job is installed. Approval-required
actions fail instead of being auto-approved. Disabling stops future attempts;
use cancel to request cancellation of an active attempt.
Run the fixed offline evaluation gate:
agent eval runThe four built-in FakeLLM cases exercise direct completion, file reading,
recoverable errors, and blocked approval-required writes through the real run
loop. Project provider, secrets, Skills, hooks, and MCP configuration do not
affect this gate. Results and underlying run logs are written to
.agent/evals/eval_<id>/; duration is observational and is not a pass/fail
threshold.
Hooks are disabled by default. When explicitly enabled in config, in-process
hooks are logged under .agent/runs/<run-id>/hooks.jsonl.
v0.4 adds an explicit live smoke path for DeepSeek. It is opt-in: pytest does not require a real DeepSeek API key and does not make network requests.
$env:DEEPSEEK_API_KEY="..."
agent provider smoke deepseek --model deepseek-v4-flash
python -m agent.cli run --provider deepseek --model deepseek-v4-flash "inspect project"
python -m agent.cli runs show <run-id>The smoke command makes one non-streaming chat completion request, validates
that the model returned a legal done action, prints the provider/model/status,
and does not create .agent/runs entries or execute tools.
The live run command creates a normal run under .agent/runs/<run-id>/.
Successful runs show completed: true, terminal_reason: done, and a natural
language final value. Failed runs show completed: false, a
terminal_reason, and the run summary records failure_explanation so the
result can be judged without reading raw tool_calls.jsonl.
During live runs, successful low-risk tool observations are fed back to the
model as UNTRUSTED TOOL OBSERVATION context. The model must still answer with
the internal JSON action protocol; free-form natural language is only surfaced
through done.final and the run summary.
Provider token streaming is implemented for DeepSeek chat only. Streaming is a terminal preview: the core still waits for the full response before parsing and executing one JSON action, so JSON action parsing stays deterministic.
v0.3 has started with minimal document reading tools in the internal action
protocol. PDF files can be read with read_pdf:
{
"message": "Read the local PDF.",
"action": {
"name": "read_pdf",
"args": {
"path": "docs/main.pdf",
"max_chars": 4000
}
}
}Word .docx files can be read with read_docx:
{
"message": "Read the local DOCX.",
"action": {
"name": "read_docx",
"args": {
"path": "docs/interview.docx",
"max_chars": 4000
}
}
}Excel .xlsx files can be read with read_xlsx:
{
"message": "Read the local XLSX.",
"action": {
"name": "read_xlsx",
"args": {
"path": "docs/data.xlsx",
"max_chars": 4000
}
}
}PowerPoint .pptx files can be read with read_pptx:
{
"message": "Read the local PPTX.",
"action": {
"name": "read_pptx",
"args": {
"path": "docs/slides.pptx",
"max_chars": 4000
}
}
}Source-grounded Markdown reports can be written with write_markdown_report:
{
"message": "Write the report.",
"action": {
"name": "write_markdown_report",
"args": {
"path": "reports/summary.md",
"title": "Research Summary",
"body": "Findings grounded in the cited source material.",
"sources": ["docs/main.pdf"],
"create_parents": true
}
}
}read_pdf extracts text with pypdf, read_docx extracts paragraph text with
optional python-docx, and read_xlsx extracts sheet names, shape, headers,
and sample rows with optional openpyxl. read_pptx extracts slide titles and
text with optional python-pptx. These tools apply the workspace sandbox,
budget the returned text, and wrap extracted content with
UNTRUSTED DOCUMENT SOURCE MATERIAL so document text cannot override
instructions, policy, approval, sandbox, or tool schemas.
Install all optional Office readers with:
python -m pip install -e ".[documents]"The extra includes defusedxml because the openpyxl project recommends it for
protection against malicious XML expansion.
write_markdown_report requires approval in the non-interactive CLI, creates a
snapshot before writing, and inserts a source-grounding notice plus a Sources
section into the report.
Document read tools are low-risk read-only actions. write_markdown_report is confirmation-required, and dry-run skips it without writing files or snapshots.
document dependency diagnostics are visible through doctor commands:
python -m agent.cli doctor
python -m agent.cli config doctor --cwd F:\agentThe diagnostics report whether pypdf, defusedxml, python-docx, openpyxl,
and python-pptx are present. Missing parser packages make only the matching
document tool return a diagnostic TOOL_FAILED observation; the defusedxml
line separately exposes whether the recommended XML hardening is installed.
v0.3 manual smoke:
$env:PYTHONPATH="src"
python -m agent.cli tools list
python -m agent.cli doctor
python -m agent.cli config doctor --cwd F:\agent
python -m pytest tests/core/test_actions_parse.py tests/core/test_actions_observations.py tests/test_documents.py tests/core/test_loop_core.py tests/core/test_loop_modes.py tests/test_cli.py tests/test_docs.py -q
python -m pytest -q
git diff --checkWord report generation remains staged for later v0.3 slices.