An AI agent that can do useful work, remember what matters, and show its work.
Veetbot is a self-hostable AI agent for work that takes more than a single prompt. Give it a goal and it can use tools, keep track of context, remember useful information, pause when it needs your approval, and continue after a process restart.
It is designed for people who want a capable assistant without giving up control. Every run leaves a durable record, important actions pass through explicit policy, and you can inspect what happened instead of trusting a black box.
- Carry work through to completion. Runs, tool calls, checkpoints, and results survive crashes and can be resumed safely.
- Use the model you prefer. OpenAI, Anthropic, and OpenAI-compatible local models share one provider-neutral interface.
- Work with tools and the web. Built-in tools, MCP servers, skills, public web search, page extraction, and browser automation use the same governed execution path.
- Remember with context. Long-term memory records where information came from, supports corrections and deletion, and makes retrieval decisions inspectable.
- Keep you in control. Deterministic policy rules, scoped credentials, isolated execution, and approval prompts guard consequential actions.
- Work with your mail and the people in it. The optional Gmail integration searches, triages, and drafts, sends only what you approve, and can help you unsubscribe from bulk senders; People memory keeps track of who you know and write to, with the evidence behind each fact.
- Handle work while you are away. Durable schedules, offline results, and notifications let useful work continue beyond an open chat window.
- Meet you where you work. Use the command line, the versioned HTTP API and event stream, the downloadable terminal client, or the native Apple client.
- Make behavior testable. Reproducible evaluations and named release gates turn agent quality, safety, and recovery into things a team can verify.
Veetbot is under active development. The durable agent core and the workflows through Milestone 12 are complete, along with the memory evaluation and memory browser workstreams; newer capabilities continue to move through explicit release gates. See the current project state for the exact status of each milestone.
Public product and policy pages are available at
www.veetbot.com, with technical documentation at
docs.veetbot.com. The website source and its local
verification commands live under website/.
The quickest way to understand Veetbot is to run its deterministic local demo. It exercises PostgreSQL persistence, the worker queue, a real built-in tool, and the event log without requiring a model API key.
- Python 3.12 or newer
- Node.js 22.13 or newer
- uv
- Docker with the Compose plugin
make- Pandoc, required by
make docsand by the documentation gate thatmake checkruns
The commands below assume a macOS or Linux shell and start from the repository root.
Doppler holds the development secrets and .env is a generated cache of
them. Fetch them, then install the locked development dependencies:
make env-pull
make installmake env-pull needs the Doppler CLI
and access to the veetbot project. doppler.yaml pins the
project and config, so no doppler setup is required; rerun the target after
changing a secret and once in each new worktree. Without Doppler access, run
cp .env.example .env instead.
Either way the default environment uses development authentication and a scripted fake model, so the first run is local, deterministic, and free.
Start the pinned PostgreSQL 16 container and apply the migrations:
make db-up
make migrateThe development database listens on 127.0.0.1:5432. Veetbot never applies
migrations during application startup, so run make migrate whenever you pull
new migrations.
Keep this command running in its own terminal:
uv run agent worker --role workerThe worker leases queued runs, executes model and tool steps, and writes their events back to PostgreSQL.
In a second terminal, run the built-in calculator demo:
uv run agent run "What is 17 multiplied by 23?"You should see progress on stderr and 391 on stdout. That result travels
through the same durable run and tool lifecycle used by real model providers.
Add the credential for the provider you want to use to Doppler, which prompts
for the value so it stays out of your shell history, then regenerate .env:
doppler secrets set VEETBOT_OPENAI_KEY
make env-pullWithout Doppler, set VEETBOT_OPENAI_KEY or ANTHROPIC_API_KEY in .env
directly.
Restart the worker after changing .env, then create a run with a declared
model policy:
uv run agent run --model-policy balanced "Summarize this repository"
uv run agent run --model-policy flagship "Review the architecture"balanced uses OpenAI and flagship uses Anthropic. For a credential-free
local model, start Ollama with the configured qwen3:8b model and use:
uv run agent run --model-policy local "Explain the event-driven run loop"Model policies, provider profiles, pricing snapshots, and capability limits
live in reviewed YAML under src/agent_core/models/.
With the database and worker already running, start the local API in another terminal:
uv run agent apiIt listens on http://127.0.0.1:8000. Build and open the dependency-free
terminal client with:
make client-build
python build/veetbot-client.pyzThe client guide covers remote URLs, authentication, session resume, approvals, and reconnect behavior. The native iOS and macOS client has its own setup guide.
| Command | What it does |
|---|---|
make check |
Run formatting, lint, types, fast tests, deployment, documentation, and website checks with two concurrent jobs |
make format |
Apply Ruff formatting and safe lint fixes |
make test |
Run every non-live Python test |
make test-static |
Run unit and structural tests with two workers |
make test-contract |
Run shared contracts against in-memory and fake adapters |
make test-integration |
Run tests that need PostgreSQL or another local service, against a scratch database (below) |
make docs |
Build the MkDocs site and standalone HTML documentation |
make docs-serve |
Serve the documentation locally with live reload |
make test-website |
Reuse matching local dependencies, build, test, and lint the public static website |
make check does not require a database or provider credential. Static and
contract tests block network access; only explicitly enabled live tests may
contact model providers and incur cost. The provider-assisted memory evaluator
currently makes 25 bounded provider calls (at most USD 1.25 under its per-call
ceiling). make check does not run the integration suite; hosted CI does, and
the recipe below runs it locally.
Use one make check after the final edits: documentation and website checks
are included, so no separate repeat is needed on unchanged inputs. Static tests
finish before contract tests; independent lanes overlap. For serial debugging,
use make check CHECK_JOBS=1 STATIC_TEST_WORKERS=0. Website installs are reused
only when the manifests, Node/npm runtime, npm configuration, and dependency
tree checks match. CI always installs cleanly; locally force a reinstall with
WEBSITE_INSTALL_FORCE=1 make website-install.
Integration tests erase every application table in the database they use, so
they run only against a scratch database the run marks disposable with
VEETBOT_TEST_DATABASE_DISPOSABLE=1. Without that opt-in they skip and say
why. Never set it for the development database from step 2: its URL is the same
as CI's, so the opt-in is the only thing that tells them apart. With the
database from step 2 running:
docker compose exec postgres createdb -U agent agent_scratchDATABASE_URL=postgresql+asyncpg://agent:agent@localhost:5432/agent_scratch make migrateDATABASE_URL=postgresql+asyncpg://agent:agent@localhost:5432/agent_scratch VEETBOT_TEST_DATABASE_DISPOSABLE=1 make test-integrationdocker compose exec postgres dropdb -U agent agent_scratchSecrets, addresses, and deployment identity belong in Doppler, from which
make env-pull generates .env; reviewed tuning values belong in the YAML
file owned by the relevant package. Optional web, browser, typed-judgment,
scheduling, notification, email, and trajectory-export features are disabled by default. Their available environment switches are documented in
.env.example.
The initial public-web comparison keeps the incumbent provider for half of each capability and routes the other half to Keenable:
WEB_SEARCH_PROVIDERS=tavily:50,keenable:50
WEB_FETCH_PROVIDERS=firecrawl:50,keenable:50
TAVILY_API_KEY=...
FIRECRAWL_API_KEY=...
KEENABLE_API_KEY=...Weighted entries must be unique positive integer percentages summing to 100.
The backward-compatible singular selectors may instead name firecrawl,
tavily, keenable, or disabled. Provider keys are resolved by the
credential broker at call time and are never exposed to the model.
For image and video generation, add TENSORSCALE_API_KEY to Doppler and run
make env-pull, then restart the API and workers. New chats offer
image.generate (SenseNova U1.5, PNG) and video.generate (LTX-2.5 Fast,
5- or 10-second MP4 with audio). Both take a text prompt, require approval,
and attach the generated file to the reply. Token-authenticated owners need
media.generate and artifact.write in AUTH_SCOPES; the TensorScale key
must permit both models, including the ltx2-5-fast scope. Existing chats keep
their tool roster. To prompt with pictures, enable the existing attachment
uploads (AGENT_ATTACHMENT_UPLOADS_ENABLED=1) and grant artifact.read.
Attach PNG/JPEG/WebP images and ask for an edit, combination, or animation.
image.generate accepts up to eight ordered references (20 MiB each, 64 MiB
total); video.generate takes a first frame and optionally a last frame
(10 MiB each). Both use reference_image_ids from the chat's attachments or
previously generated images; omit them for text-only generation. For example:
"Put the subject from image 1 in the scene from image 2" or "Animate this
photo for five seconds." Provider charges are separate from model-token accounting;
a failed or timed-out request is never retried automatically. See
ADR-0140.
Before changing the codebase, read AGENTS.md. It explains the authorized milestone, required reading lane, test-driven workflow, and completion-report requirements. The main technical references are:
- Engineering plan — normative requirements
- Current milestone — authorized work
- Architecture decisions — decisions and tradeoffs
- Security model — trust boundaries and controls
- Deployment runbook — production installation, validation, rollback, and recovery
Markdown and YAML are canonical. Do not edit generated files under site/ or
dist/.