Skip to main content

CodeAgent

A document and coding agent. It reads and edits files, Excel workbooks and PDFs (scans included) in a project folder, searches a library of documents, browses the web, writes mail drafts and code, asks before every change, and remembers what it learned about each project. The model is Claude (Anthropic's API, or your own Azure subscription through Microsoft Foundry) or DeepSeek. Use it from the terminal, or as a library to build your own tool on top of it (a desktop app that fills Excel workbooks from invoices, a voice assistant over a library of PDFs...).

pip install seedagent

Or from a clone of this repository: uv sync installs the package and the coding-agent command in .venv (uv run coding-agent), and uv sync --all-extras adds the browser and the Excel backend. An application built on it just runs uv sync too: its own pyproject.toml and uv.lock say which version of the engine to fetch.

The package seedagent installs the coding_agent Python package and the coding-agent command (also available as seedagent). Python 3.10 or later; Windows, macOS and Linux.

Configure

Environment variables, or a .env file in the folder you run from (or ~/.coding-agent/.env):

Variable Meaning
ANTHROPIC_FOUNDRY_ENDPOINT https://<resource>.services.ai.azure.com/anthropic
ANTHROPIC_FOUNDRY_DEPLOYMENT your Claude deployment name
ANTHROPIC_FOUNDRY_API_KEY an API key; leave unset to sign in with your Microsoft work account

Without an API key, the agent signs in with the account of your Windows session, a developer's az login, or else the Microsoft sign-in page (once; the account is remembered).

Without Azure, use Anthropic's own API: leave ANTHROPIC_FOUNDRY_ENDPOINT unset and set

Variable Meaning
ANTHROPIC_API_KEY an API key from console.anthropic.com
ANTHROPIC_MODEL a model ID (default claude-sonnet-5)

Models: claude-sonnet-5 (the default, $2/$10 per million input/output tokens), claude-sonnet-5-5 (same price), claude-haiku-4-5 ($1/$5, the cheapest; no effort setting, weaker with tools; good for the two background models AGENT_MEMORY_MODEL and AGENT_COMPACT_MODEL), claude-opus-5-5 ($4/$20), claude-opus-5 ($5/$25) and claude-fable-5-1 ($10/$50, its thinking cannot be turned off).

Thinking and effort (cost and speed), for the agent's own requests:

Variable Meaning
CODEAGENT_THINKING thinking before the answer: off (the default), adaptive, between_tools or disabled
CODEAGENT_EFFORT how much the model thinks and writes: medium (the default), low, high, xhigh, max, or default (nothing is sent: the model's own default applies)

off means the lowest setting the model accepts: disabled, between_tools on claude-sonnet-5-5 (it answers 400 to disabled), adaptive on claude-opus-5-5 (it answers 400 to both), and no thinking field at all on claude-fable-* (its thinking cannot be turned off). On Foundry the model is a deployment name, so off may guess wrong: name between_tools or disabled yourself. between_tools does not work with effort xhigh or max, and claude-haiku-* has no effort setting (none is sent). A value that is not allowed is explained, never replaced. An application can also call configure(effort=...). coding-agent --check shows the thinking and effort it sends. example.env lists every variable the agent reads: copy it to .env.

A Foundry endpoint always wins: with ANTHROPIC_FOUNDRY_ENDPOINT set, the agent uses Foundry even if ANTHROPIC_API_KEY is also set.

DeepSeek instead of Claude

DeepSeek offers an Anthropic-compatible API (https://api.deepseek.com/anthropic), so the same client and the same tools work with a DeepSeek model. Set DEEPSEEK_API_KEY (and nothing else: no ANTHROPIC_API_KEY, no Foundry endpoint), or CODEAGENT_PROVIDER=deepseek to choose it over them. CODEAGENT_PROVIDER=claude does the opposite: Claude (Anthropic's API or Foundry) is used even when a DeepSeek key is set. The model is deepseek-flash by default; ANTHROPIC_MODEL=deepseek-v4-pro selects the larger one. Setting ANTHROPIC_API_KEY to a DeepSeek key with ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic also works and is recognised. coding-agent --check tests the connection.

What DeepSeek does not take, and what the agent does about it: no web_search tool (it is left out, Web search: off); no cache_control (DeepSeek caches by itself); no PDF document blocks, so read_pdf sends pages as rendered images instead (pypdfium2) and scans are read by OCR or by looking at the page; thinking is sent as disabled for CODEAGENT_THINKING=off. deepseek-flash looks at images; deepseek-v4-pro does not (it answers "unsupported image"): the tools that return an image are then not offered and read_pdf has no visual mode (AGENT_VISION=on|off overrides the list for a model that is not in it). Set AGENT_CONTEXT_WINDOW to the model's real window (the default is 200,000 tokens). An application can hand the key over without any environment variable: configure(api_key=..., model=...).

Use it in the terminal

coding-agent -d path/to/project "Add input validation to the CLI"
coding-agent -d path/to/project            # interactive
coding-agent -d path/to/project -r         # resume the last conversation
coding-agent -d path/to/project --read D:/docs --read //server/share   # also read (never write) other folders
coding-agent --check                      # Claude not answering? test each step of a call
coding-agent --help

In the interactive mode, the up arrow at the You: prompt recalls earlier questions, also from earlier runs (kept in ~/.coding-agent/history; needs readline: Linux, macOS, WSL; the Windows console recalls the questions of the running session by itself).

Use it as a library

from coding_agent import session
from coding_agent.ui import TerminalUI  # or your own UI (subclass coding_agent.ui.UI)

session.open_project("path/to/folder", ui=TerminalUI(),
                     tools=["read_excel", "edit_excel", "read_pdf", "ask_human"],  # optional subset
                     system_prompt=None)                                           # or your own instructions
ok, message = session.check_connection()   # can Claude be reached?
session.send("Fill costs.xlsx from invoice.pdf")
session.close()

session.open_project(..., excel_first=True) (for an application that fills workbooks) refuses read_pdf until read_excel has run, when the instruction mentions a spreadsheet; it is off by default.

An application that fills one workbook can also set, after open_project: state.excel_writable = {path} (no other workbook can be changed or created), state.excel_protect_formulas = True (a formula can be neither replaced nor cleared), and state.excel_edit_sheets[path] = {"Sheet1"} (only those sheets). They are checked by the tool, not asked of the model.

session.stop() stops the running instruction from another thread (e.g. a Stop button); session.add_read_folder(path) lets the agent read (never write) another folder. Every approval, question and progress message goes through the UI object, so a web or desktop front end can show them.

Your own tools

An application adds a tool of its own without changing the package:

import coding_agent

def say_hello(who: str, loud: bool = False) -> str:          # called as handler(**arguments)
    return f"Hello {who}{'!' if loud else ''}"

coding_agent.register_tool(
    {"name": "say_hello", "description": "Greet someone.",
     "input_schema": {"type": "object", "properties": {"who": {"type": "string"}, "loud": {"type": "boolean"}}, "required": ["who"]}},
    say_hello)
session.open_project(folder, ui=ui, tools=["read_file", "say_hello"])    # a tool is offered only when the session lists it

The handler gets one keyword argument per property of the input_schema and returns a string or a list of content blocks ({"type": "text", ...}, {"type": "image", ...}). To report a failure Claude should see, it raises coding_agent.common.ToolError; any other exception also reaches Claude as an error result and does not stop the agent. It runs in the agent's thread and can use coding_agent.state (state.ui, state.workspace). CodeAgent's path checks and confirmations guard only its own tools: what the handler does is the application's responsibility (to read a file the way the built-in tools do, coding_agent.common.resolve_readable(path) applies the same rules). A built-in tool cannot be replaced, registering the same handler twice does nothing, and a second handler under a taken name is an error.

Tools

45 tools; an application offers the subset it wants (session.open_project(tools=[...])).

Group Tools
Files read_file, write_file, edit_file, list_directory, change_directory, grep, copy_path, delete_file, delete_folder
Documents read_pdf, search_pdf, search_library, view_image, read_word, read_powerpoint
Excel read_excel, edit_excel, view_excel, format_excel, add_chart, add_table, add_pivot_table, restore_backup, run_python_excel
Web web_search, web_open, web_click, web_type, web_back, web_page, web_look, screenshot_page, web_sign_in, web_set_token, web_close, download_file
Mail and SMS mail_login, mail_draft, send_mail, send_sms
Code run_python (sandboxed), git (read-only), clone_repo
Other load_skill, ask_human

read_file reads UTF-8 and, failing that, Windows-1252 (the usual export of Excel and French accounting software; the result says so). grep cuts a matching line at 300 characters and bounds its whole result, so a minified file cannot flood the conversation.

Documents, scans and the library

  • read_pdf reads text by default (page ranges). Its visual mode (pages rendered as images, at most 20 per call) is allowed once a text read happened in the conversation, to check what a scan or a table really shows; names, dates and amounts taken from a scan should be checked that way. A model that cannot see images gets no visual mode.
  • Scanned pages are read by OCR (tesseract and its language packs must be installed); the text is kept in AGENT_OCR_DIR so a page is read once. coding-agent --ocr PDF... does it ahead of time.
  • search_library searches a library of PDFs, Word and PowerPoint files and text files (the read-only folders and the project) through a full-text index (SQLite FTS5; alternatives with a | b | c, ranked by the words found). Files that are new or changed are indexed on the way, up to a size; bigger ones, and a first indexing with OCR, are done once with coding-agent --index FOLDER... (AGENT_INDEX_DIR moves the index).
  • read_word (.docx: paragraphs and tables) and read_powerpoint (.pptx: slides and speaker notes) read the text only, with no extra dependency; a long document is read in parts with start, a slide alone with slide. Both are in the search index (a slide is a page; a Word file is cut in blocks, located by character). A picture inside is not read.
  • read_pdf, read_file, search_library and grep also read the folders given with --read / session.add_read_folder (never write).

Browsing the web

web_search finds pages; web_open reads one in a hidden browser that stays open, and lists its text and its links, buttons and fields with numbers. The agent goes through a site with web_click 3 and web_type 5 "weather paris" submit, reads long pages with web_page, goes back with web_back, sees the page with web_look and ends with web_close. It needs Playwright and a browser, like screenshot_page (uv sync --extra browser, then playwright install chromium; coding-agent --check-browser tests it).

What keeps it safe (in the tools, not only in the prompt):

  • The first visit to a public site asks you, with the full URL ([a]ll sites for this session stops the questions until the session ends; AGENT_WEB_APPROVE=off never asks, for unattended runs); after that the agent can click and type on that site. Links to other sites are refused until the agent opens them with web_open, which asks you. localhost, private addresses and workspace HTML files need no question.
  • It never types into password, sign-in or payment fields. When a site needs you signed in, web_sign_in opens a visible window where you type the password yourself; the agent never sees it and keeps only the session (cookies) of that site, for 30 days (AGENT_WEB_SESSION_DAYS), in ~/.coding-agent/web-sessions (owner-only files). coding-agent --forget-logins deletes them (--forget-logins SITE for one). A saved session is as good as a password until it expires: keep it for sites you are comfortable with.
  • A form that sends data (POST), by a button or by pressing Enter, shows what it sends and asks first.
  • Downloads are blocked, metadata addresses are refused, and nothing is kept on disk (apart from sign-ins you made with web_sign_in): cookies and history end with the session (web_close, or the program ending).
  • The page text reaches Claude marked as untrusted content, and the tools say that pages cannot give it instructions.

Limits: content inside frames and shadow DOM is not listed, nothing is drawn on a canvas for the text view (use web_look), and a site that blocks automated browsers will block this one too.

Excel: two backends

Who changes, formats and renders workbooks is set by AGENT_EXCEL_BACKEND:

openpyxl xlwings (uv sync --extra excel)
Runs on anywhere Windows or macOS with Excel installed
Saving rewrites the file: charts, pictures, pivot tables can be damaged (you are warned first) Excel saves: nothing is lost
Formulas after an edit old results until the file is opened in Excel recalculated at once
view_excel a drawing of the cells (needs the browser extra); charts listed, not drawn what Excel prints, charts included
A workbook open in Excel refused (locked) written in that window, if it has no unsaved changes
add_chart, add_table written by openpyxl added by Excel
add_pivot_table refused (openpyxl cannot build them) built by Excel

auto (the default) uses xlwings when it is installed and Excel can be started, else openpyxl. Reading (read_excel) is the same in both: it never changes the file, lists the charts, pictures, tables and pivot tables of a sheet, and shows a long cell whole when that one cell is read. scripts/compare_excel_backends.py runs the same edits, formatting and views with both backends and reports what each kept (run it on a PC with Excel: uv run --extra excel --extra browser python scripts/compare_excel_backends.py [your.xlsx ...]).

Excel scripts (run_python_excel)

For what no Excel tool does, the agent has run_python_excel: a Python script run with Excel (xlwings backend only) on a workbook, which it gets as book. Excel can do far more than the run_python sandbox can see (run macros, start programs, open and save any file), so:

  • the script is checked before it runs, and refused if it uses macros (Run, Evaluate, VBProject, ExecuteExcel4Macro...), programs or links (Shell, FollowHyperlink, DDE formulas such as =cmd|...), other files or workbooks (save, SaveAs, Open, books, app, Application, Parent), external data (QueryTables, WEBSERVICE), imports beyond math, datetime, re, collections... , or ways around the check (eval, exec, getattr with a computed name, _private attributes);
  • you approve the script (unless autonomous mode is on), and a backup of the workbook is kept first (restore_backup undoes it);
  • it runs in its own invisible Excel with macros forced off and events off, inside the run_python sandbox; macros it adds are refused and the workbook is put back;
  • you see what it changed: cells, sheets, charts, tables, pivot tables.

The check reads the script; it cannot prove what Excel will do. An application that passes its own list of tools (session.open_project(tools=[...])) does not get it unless it lists it, and it is refused in applications that restrict edits (chosen sheets, protected formulas, no formatting).

Safety

  • It writes only inside the project folder. Reading elsewhere: in the terminal the agent asks you the first time it wants to read a folder outside the project (Allow the agent to read (never change) files in ...?), and remembers the answer for the session; folders given with --read need no question. Keys and settings (~/.ssh, ~/.aws, ~/.azure, ~/.coding-agent, .env files, *.pem, *.key...) are never read. An application built on the package keeps reading limited to what it was given.
  • Every file or workbook change is shown (a diff, or a cell-by-cell table) and waits for your approval; a copy of the previous version of each workbook is kept in ~/.coding-agent/backups/ for 3 days, and restore_backup puts one back ("undo your changes to costs.xlsx"). Applications can list and restore them with coding_agent.backups (versions(), restore()).
  • Deleting always asks, even in autonomous mode; downloads and clones always ask; the agent cannot modify its own files; run_python cannot start processes or delete files.
  • No secret reaches code the model wrote. run_python and Excel scripts run with an environment from which every variable that says it is a secret (*KEY*, *TOKEN*, *SECRET*, *PASSWORD*, *AUTH*), the variables of cloud and model services (ANTHROPIC_*, DEEPSEEK_*, AZURE_*, AWS_*, GITHUB_*...) and any copy of an API key are removed, and the output of the script has those values hidden. A document that steers the model cannot make it print your keys.
  • The agent never reads ~/.coding-agent (credentials and its own settings), so a knowledge folder must live elsewhere.

What stays on your machine

Everything is in ~/.coding-agent ($HOME, or your user folder on Windows), cleaned automatically (coding_agent/cleanup.py): once per process, at the start of coding-agent and the first time an application opens a project (session.open_project). AGENT_CLEANUP=off switches that off; an application that runs for weeks (a server) can call coding_agent.cleanup.run() itself, daily (a call counts as the run):

What Where Kept
Copies of workbooks before each change backups/ 3 days (AGENT_BACKUP_DAYS)
What the agent learned about each project memory/<project>-<code>/ notes capped in size; deleted after 90 days unused (AGENT_MEMORY_DAYS)
The saved conversation (--resume) memory/<project>-<code>/conversation.json 30 days (AGENT_CONVERSATION_DAYS)

AGENT_MEMORY=off stops the agent from writing memory at all.

For developers, to see and delete what the agent remembers:

coding-agent --memories              # every project's memory: name, last used, size, notes
coding-agent --memories myapp        # one project's notes, in full
coding-agent --forget myapp          # delete one project's memory (asks first)
coding-agent --forget . -d path      # the memory of that project folder
coding-agent --forget all            # delete every project's memory (asks first)

Development

uv sync --all-extras                      # the exact versions the tests ran with (uv.lock), with the browser and Excel extras
uv run playwright install chromium        # the browser tools and their tests need it
uv run pytest
uv build                                  # dist/seedagent-<version>.tar.gz and .whl

The CI (.github/workflows/package.yml) runs the same on Linux and Windows, Python 3.10 and 3.14, with every extra and Chromium installed, then installs the built wheel in a fresh environment and runs the tests there. A test must not depend on a .env, on the order of files or on the repository layout (the wheel's tests run from a copy of tests/).

Releasing (maintainers)

The workflow (.github/workflows/package.yml) publishes to PyPI by trusted publishing (no token stored). The project is seedagent; its publisher on pypi.org is owner DemePS, repository CodeAgent, workflow package.yml, environment pypi (also an environment pypi in the repository's settings). PyPI refuses a name that equals an existing one once -, _ and . are removed (codeagent was refused: code-agent exists), so check a new name against the full list before registering it.

To publish a version, tag the commit whose pyproject.toml has that version, with CI green, and push the tag:

git fetch origin
git tag -a v0.7.0 origin/main -m "v0.7.0"
git push origin v0.7.0

The tag runs the tests and the build, publishes to PyPI and creates a GitHub Release. A tag whose version differs from pyproject.toml is refused. A published version can never be replaced: fix forward with a new version. Applications then depend on seedagent==<version>.

License

MIT (see LICENSE).

Metadata

Release files for seedagent 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for seedagent 0.7.0
File Size Uploaded
seedagent-0.7.0.tar.gz 231.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for seedagent 0.7.0
File Interpreter ABI Platform
seedagent-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 435.2 kB

Release files / seedagent-0.7.0.tar.gz

Download URL seedagent-0.7.0.tar.gz
Size 231.2 kB
Tags Source
SHA-256 checksum
How to use checksums
2f53b8daeff845080ac91b8c5182161231aa91e024a4ed2ee6ee744dfd638009
BLAKE2b-256 checksum
How to use checksums
e2903dae2a01704bb9eb06721cb45dbc74b71946ca6b149f17528e62cf811722
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release files / seedagent-0.7.0-py3-none-any.whl

Download URL seedagent-0.7.0-py3-none-any.whl
Size 204.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
032c864bec03d8b3bdaf857863bbb36b723e2c6e52aa9bccd4b1e26eaf969aef
BLAKE2b-256 checksum
How to use checksums
5361843610b417638425fe2124ca61ffb588c2673760adda14d69582f8bdee7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 10, 2026.

Transparency log

Release history Release notifications | RSS feed

0.8.0

2 release files

This release

0.7.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page