Skip to content
avitusPublic

About

A general purpose agent

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

1,408 Commits

Folders and files

Repository files navigation

Veetbot

Veetbot

An AI agent that can do useful work, remember what matters, and show its work.

Meet Veetbot

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.

What it can do

  • 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/.

Developer guide

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.

Prerequisites

  • Python 3.12 or newer
  • Node.js 22.13 or newer
  • uv
  • Docker with the Compose plugin
  • make
  • Pandoc, required by make docs and by the documentation gate that make check runs

The commands below assume a macOS or Linux shell and start from the repository root.

1. Install the project

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 install

make 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.

2. Start PostgreSQL

Start the pinned PostgreSQL 16 container and apply the migrations:

make db-up
make migrate

The 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.

3. Start a worker

Keep this command running in its own terminal:

uv run agent worker --role worker

The worker leases queued runs, executes model and tool steps, and writes their events back to PostgreSQL.

4. Submit your first run

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.

5. Connect a real model (optional)

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-pull

Without 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/.

Run the API and terminal client

With the database and worker already running, start the local API in another terminal:

uv run agent api

It listens on http://127.0.0.1:8000. Build and open the dependency-free terminal client with:

make client-build
python build/veetbot-client.pyz

The client guide covers remote URLs, authentication, session resume, approvals, and reconnect behavior. The native iOS and macOS client has its own setup guide.

Everyday development commands

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_scratch
DATABASE_URL=postgresql+asyncpg://agent:agent@localhost:5432/agent_scratch make migrate
DATABASE_URL=postgresql+asyncpg://agent:agent@localhost:5432/agent_scratch VEETBOT_TEST_DATABASE_DISPOSABLE=1 make test-integration
docker compose exec postgres dropdb -U agent agent_scratch

Configuration and project conventions

Secrets, 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:

Markdown and YAML are canonical. Do not edit generated files under site/ or dist/.

About

A general purpose agent

Resources

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages