DoStuff
A pip-installable AI agent harness with a Textual TUI, persistent sessions, and MCP tool support.
Install • Quick start • Configuration • TUI controls • MCP servers • Skills • Troubleshooting
DoStuff is a terminal AI agent that runs anywhere pip runs. It gives you a full interactive session with persistent memory, multi-provider LLM support via litellm, and pluggable MCP tool servers. State lives in ~/.dostuff/, so any project you launch dostuff from shares the same memory and sessions.
Features
- Textual TUI with per-role colored messages, status bar, and a loading spinner
- Multi-provider LLMs via litellm — OpenAI, Anthropic, Gemini, Groq, Mistral, Ollama, OpenRouter
- Persistent sessions in SQLite; resume with
dostuff --session <id> - Long-term memory (semantic + episodic) backed by ChromaDB
- MCP server support — stdio (npx, uvx) and HTTP transports
- Skills loader — drop a
SKILL.mdin the right folder, restart, done - Per-tool timeout (120s) to prevent hung servers
- Token tracking — per-turn and cumulative totals
- Graceful exit —
Ctrl+Qor/exitsaves, cleans up, and stops background workers
Install
Install from PyPI:
pip install dostuff
This installs the dostuff command on your PATH. Done.
Other install methods
For an isolated install with pipx:
pipx install dostuff
For development (editable mode, from a clone):
git clone https://github.com/<you>/dostuff.git
cd dostuff
pip install -e . # core
pip install -e ".[full]" # + onnxruntime + grpcio
Verify:
dostuff --help
Quick start
# 1. Set up config and secrets
mkdir -p ~/.dostuff
cp config.example.yaml ~/.dostuff/config.yaml
cp .env.example ~/.dostuff/.env
nano ~/.dostuff/.env # add OPENAI_API_KEY=sk-...
# 2. Edit ~/.dostuff/config.yaml and set model.name
# (see config.example.yaml)
# 3. Launch the TUI
dostuff
In the TUI:
> hi there
[agent replies]
> /exit
[session saved, goodbye]
CLI reference
| Command | Description |
|---|---|
dostuff |
Launch the interactive TUI |
dostuff --session <id> |
Resume a prior session |
dostuff --user <id> |
Override the user ID |
dostuff init |
Create .dostuff/ in the current directory |
dostuff config |
Show resolved config paths and values |
dostuff doctor |
Health check (config, data dir, user ID) |
dostuff session-list |
List all past sessions with their working dirs |
TUI controls
| Key / command | Action |
|---|---|
Enter |
Submit message |
Ctrl+J |
Insert a newline (multi-line input) |
/exit |
Save memories and quit |
Ctrl+Q |
Graceful quit with save |
/help |
Show available in-TUI commands |
Visual elements:
- User messages — blue background
- Agent messages — neutral
- Tool calls and results — teal background, truncated at 600 chars
- Confirmations — yellow background (respond with
yorn) - Errors — red background
- Status bar —
cwd • session-id • new/resumed • ↑total ↓total - Loading —
⏳ agent is thinking...while waiting for the model
Configuration
Config is layered, with later sources overriding earlier ones:
~/.dostuff/config.yaml— global defaults<cwd>/.dostuff/config.yaml— per-project overrides~/.dostuff/.env/<cwd>/.dostuff/.env— secrets- Environment variables — highest priority
config.yaml
# ~/.dostuff/config.yaml
data:
global_dir: ~/.dostuff/data
mcp:
config_path: ~/.dostuff/mcp_config.json
tracing:
enabled: false # default OFF (no 4317 noise)
exporter: "otlp" # otlp | console | none
model:
name: "openai/gpt-4o-mini" # litellm format: provider/model
api_key_env: "OPENAI_API_KEY" # name of the env var holding the key
See config.example.yaml for a full template.
.env
Never put secrets in config.yaml. Use ~/.dostuff/.env:
# ~/.dostuff/.env (chmod 600 on Unix)
OPENAI_API_KEY=sk-...
GEMINI_API_KEY=AIza...
GROQ_API_KEY=gsk_...
TAVILY_API_KEY=tvly-...
Override at runtime
MODEL=gemini/gemini-3.1-flash-lite dostuff
OTEL_ENABLED=true OTEL_EXPORTER=console dostuff
Models
The name field uses litellm format: provider/model-name.
| Provider | Model name | API key env |
|---|---|---|
| OpenAI | openai/gpt-4o-mini |
OPENAI_API_KEY |
| Anthropic | anthropic/claude-3-5-sonnet-20240620 |
ANTHROPIC_API_KEY |
| Gemini | gemini/gemini-3.1-flash-lite |
GEMINI_API_KEY |
| Groq | groq/llama-3.1-70b-versatile |
GROQ_API_KEY |
| Ollama | ollama/llama3.1 |
(none) |
If name has no /, the provider field is auto-prepended.
MCP servers
MCP servers extend the agent with new tools. Configure them in ~/.dostuff/mcp_config.json.
Discovery order: mcp.config_path → ~/.dostuff/mcp_config.json → <cwd>/.dostuff/mcp_config.json → <cwd>/mcp_config.json.
Conflict resolution: No merge — the first found config wins. If ~/.dostuff/mcp_config.json exists, the project-level .dostuff/mcp_config.json is silently ignored. To use a custom path, set mcp.config_path in config.yaml — that takes highest priority.
Example config
{
"mcpServers": {
"tavily": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@tavily/mcp-server"],
"env": { "TAVILY_API_KEY": "tvly-..." }
},
"github": {
"transport": "stdio",
"command": "uvx",
"args": ["mcp-server-github"],
"env": { "GITHUB_TOKEN": "ghp_..." }
},
"remote": {
"transport": "http",
"url": "https://mcp.example.com/sse",
"headers": { "Authorization": "Bearer xxx" }
}
}
}
| Field | Required for | Notes |
|---|---|---|
transport |
optional | stdio (default) or http |
command |
stdio | Executable (npx, uvx, ...) |
args |
stdio | Argument list |
env |
stdio | Env vars for the child process |
url |
http | Remote MCP server URL |
headers |
http | HTTP headers |
MCP connections start in a background worker, so the TUI never blanks during boot. Each server is announced with a ✓ or ✗ in the message area.
To force a re-registration, delete:
rm ~/.dostuff/data/mcp_client_registrations.json
Skills
Skills are markdown documents that teach the agent new workflows. Each is a directory with a SKILL.md (frontmatter + body).
Discovered from (in order):
<cwd>/.dostuff/skills/<cwd>/.agents/skills/~/.dostuff/skills/~/.agents/skills/<cwd>/skills/
Conflict resolution: No deduplication. If two skills share the same name (from different directories), both are loaded and passed to the model — the agent may see the same skill twice with different location paths. To avoid confusion, keep names unique across the search paths.
Example structure:
~/.agents/skills/
└── my-skill/
├── SKILL.md # required
└── helpers/ # optional
SKILL.md:
---
name: my-skill
description: One-line description of what this skill does
---
# My Skill
Detailed instructions for the agent go here.
Run dostuff init to bootstrap a local .dostuff/skills/ folder. Restart the agent after adding new skills.
Sessions and memory
- DB:
~/.dostuff/data/sessions.db(SQLite) - Resume:
dostuff --session <id> - List:
dostuff session-list - Memory stores:
~/.dostuff/data/chroma/- Semantic (key/value facts)
- Episodic (events with summaries and timestamps)
- Saved on:
/exitorCtrl+Q
Long-term memory survives pip install . --upgrade because it lives in the user's home directory, not in the package.
Tracing (opt-in)
Tracing is OFF by default to avoid spurious localhost:4317 errors.
# ~/.dostuff/config.yaml
tracing:
enabled: true
exporter: "console" # or "otlp"
endpoint: "localhost:4317"
Or via env:
OTEL_ENABLED=true OTEL_EXPORTER=console dostuff
Troubleshooting
Project structure
dostuff/
├── cli_tui.py # Textual App + adapter
├── cli.py # typer CLI entrypoint
├── config.py # layered config (env > project > global > default)
├── agent/
│ ├── loop.py # agent loop, tool dispatch, token tracking
│ ├── call_agent.py # LLM call wrapper
│ └── run_tool.py # tool execution
├── lib/
│ ├── tracing.py # opt-in OpenTelemetry tracing
│ ├── model.py # model resolution
│ ├── memory/ # SQLite + ChromaDB stores
│ └── mcp/ # MCP client and registries
├── helpers/
│ ├── skills/ # skill discovery
│ ├── agent/ # identity, constants, exit handlers
│ ├── mcp/ # config loading
│ └── ui/ # emit shim
└── tools/ # tool definitions
├── bash/
├── files/
└── mcp/
Project metadata
- Author: varun
- Repository: https://github.com/kVarunkk/DoStuff
- Issues: https://github.com/kVarunkk/DoStuff/issues
Metadata
Release files for dostuff 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dostuff-0.1.1.tar.gz | 61.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dostuff-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 130.6 kB
Release files / dostuff-0.1.1.tar.gz
| Download URL | dostuff-0.1.1.tar.gz |
|---|---|
| Size | 61.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
29434ff12055daf313c63f74f97ea86cd9de638893460d45908b25a641b299d0
|
|
BLAKE2b-256 checksum How to use checksums |
61b9546d3a40bd6ca8386b3391ae5031c87b1de44ec0a5d7ef96360907fdce8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|
Release files / dostuff-0.1.1-py3-none-any.whl
| Download URL | dostuff-0.1.1-py3-none-any.whl |
|---|---|
| Size | 69.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8858f081615622684c2623c8fee0e614a66027d6deb109c93e8edb6b1a26fef7
|
|
BLAKE2b-256 checksum How to use checksums |
cc8e36bafb0ced1858b20047350927453d79aa7d79a895e906e7aa4f4ae95198
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.0
|