minibot
# minibot
[](https://github.com/karun99/minibot/actions/workflows/ci.yml)
[](https://www.python.org/downloads/)
[](LICENSE)
A locally-hosted **bot for your terminal**, powered by [Ollama](https://ollama.com)
tool calling. Type natural language — the model picks tools, your bot eats,
plays, recharges, and can **read/write code files** in a restricted sandbox.
Zero third-party dependencies: pure Python stdlib. Runs on **Termux, Linux,
macOS and Windows**.
```
.---. Pixel the bot · mood: happy · age 3d
/ o o \ Hunger [██░░░░░░░░] 20/100
\ w / Happiness [███████░░░] 72/100
'---' Energy [██████░░░░] 65/100
Health [██████████] 100/100
❯ write a file hello.py that prints hello
» tools: write_file
Pixel: wrote hello.py (21 bytes), want me to run the idea past you?
```
## Requirements
- Python **3.10+**
- Ollama running locally (or on another machine on your LAN)
## Install Ollama
| Platform | How |
| --- | --- |
| Linux | `curl -fsSL https://ollama.com/install.sh \| sh` |
| macOS | `brew install ollama`, or download from ollama.com |
| Windows | `winget install Ollama.Ollama`, then start "Ollama" from the Start menu |
| Termux | `pkg install python` first. Ollama is **not** in the official Termux repo — options: the Termux User Repository (`pkg install tur-repo && pkg install ollama`, availability varies by architecture) or a community `aarch64-linux-android` build (see Ollama's GitHub issues). If your phone can't run Ollama, install it on your PC and point `ollama_url` at `http://<pc-ip>:11434` on the same Wi-Fi |
Pull a tool-calling-capable model (7B recommended on desktops):
```bash
ollama pull qwen2.5:7b # or llama3.1:8b
# phones / weak CPUs:
ollama pull qwen2.5:3b
ollama pull qwen2.5:1.5b
```
Verify: `curl http://127.0.0.1:11434/api/tags` should list your models.
## Install minibot
```bash
git clone https://github.com/karun99/minibot.git && cd minibot
pip install . # installs the `minibot` command
# — or run without installing: python -m minibot
```
No `pip install` step needed beyond that — there are no runtime dependencies.
## Quick start
```bash
minibot doctor # check python/config/sandbox/ollama/model
minibot run # interactive terminal bot
```
Then chat, or use direct commands (they work even with Ollama stopped):
```
/feed /play /rest /treat /status /stats
/ls /read notes.md /write notes.md /history /undo notes.md
/needle on /doctor /clear /help /quit
```
Caring for the bot earns **treats** (feed and rest earn 1, play earns 2, capped
at 20); `/treat` spends one for a small happiness/health/energy boost.
`/stats` charts the recent stat history, `/history` lists recent sandbox
writes and `/undo [file]` reverts one.
Type `minibot run --offline` to start anyway when Ollama is down
(direct `/commands` only).
## One-shot commands (scriptable)
```bash
minibot status # human readable
minibot status --json # machine readable
minibot feed # feed once
minibot treat # spend a treat
minibot stats --points 20 # recent stat chart (also --json)
minibot ls src/
minibot read src/app.py
echo "print('hi')" | minibot write hello.py
minibot history # recent sandbox writes
minibot undo src/app.py # restore the previous version
minibot chat "read hello.py and tell me what it does"
```
## Use it from any MCP client
`minibot mcp` serves the bot's tools over stdio using the
[Model Context Protocol](https://modelcontextprotocol.io), so Claude Desktop,
Cursor, OpenCode or any other MCP client can feed your bot, read and write
sandbox files, and undo writes:
```json
{
"mcpServers": {
"minibot": {
"command": "minibot",
"args": ["mcp"]
}
}
}
```
Exposed tools: `feed_bot`, `play_with_bot`, `rest_bot`, `give_treat`,
`get_bot_status`, `read_file`, `write_file`, `list_dir`, `file_history`,
`undo_write`. The same sandbox rules apply — a client outside your machine
still cannot escape the sandbox directory.
## Configuration
Search order: `--config PATH` → `./config.json` →
`$XDG_CONFIG_HOME/minibot/config.json` → `~/.config/minibot/config.json` →
defaults. Precedence: **CLI flags > environment > config file > defaults**.
Copy `config.example.json` to `config.json` and edit. Every key is optional:
| Key | Default | Meaning |
| --- | --- | --- |
| `ollama_url` | `http://127.0.0.1:11434` | Ollama endpoint (also `OLLAMA_HOST`) |
| `model` | `qwen2.5:7b` | model for the main loop (also `MINIBOT_MODEL`) |
| `bot_name` | `Pixel` | your bot's name |
| `sandbox_path` | `~/.minibot/sandbox` | only directory file tools can touch (also `MINIBOT_SANDBOX`) |
| `state_path` | `~/.minibot/state.json` | persisted bot state |
| `log_path` | `~/.minibot/minibot.log` | rotating log (tool calls + file writes) |
| `max_iterations` | `5` | tool-loop cap per user message |
| `max_file_bytes` | `1048576` | read/write size limit (1 MB) |
| `journal_path` | `~/.minibot/journal.jsonl` | write journal backing `/history` and `/undo` |
| `journal_entries` | `100` | how many writes the journal keeps |
| `needle.enabled` | `false` | intent pre-filter on/off |
| `needle.mode` | `heuristic` | `heuristic` (zero-model) or `ollama` (tiny classifier model) |
| `decay.*` | see example | stat drift per hour of real time |
`MINIBOT_HOME` (default `~/.minibot`) overrides where state/sandbox/logs live.
## The Needle pre-filter (optional)
When enabled, input is classified first into `bot_action / file_action / chat /
unknown`:
- **heuristic mode** — regex/keyword classifier, no model, instant, offline.
- **ollama mode** — a tiny classifier model (`needle.model`); any failure
silently falls back to the heuristic, and any total failure falls back to the
main loop (graceful degradation).
- Only *high-confidence, unambiguous* bot-care phrases ("feed my bot", "status")
execute directly without the LLM; everything else — including vague or mixed
requests — goes through the normal tool-calling loop.
## Sandbox safety
- All paths are resolved (symlinks followed) and must stay inside the sandbox.
- `..` traversal, absolute paths outside the root, escaping symlinks and null
bytes are rejected with a safe error.
- Read/write capped at `max_file_bytes` (default 1 MB).
- Every write is logged with timestamp, path and size.
## Tests
```bash
pip install pytest
pytest
```
180+ tests: sandbox traversal attacks, state decay/persistence, treat
inventory, stat-history samples, the write journal (history/undo), tool
schemas, the ReAct loop (malformed-JSON retry, max iterations, history
trimming), Needle routing, the Ollama client against a local fake server,
the MCP server over stdio, and CLI acceptance tests.
## Troubleshooting
| Symptom | Fix |
| --- | --- |
| `Ollama unreachable` at startup | `ollama serve`, or check `ollama_url` / `OLLAMA_HOST` |
| `model '…' is not pulled` | `ollama pull <model>` |
| Bot replies but never uses tools | use a tool-capable model (`ollama show <model> \| grep Tools`) |
| Loop hits max iterations | ask for one thing at a time, or raise `max_iterations` |
| Colors/emoji look wrong | `MINIBOT_ASCII=1 minibot run`, or `NO_COLOR=1` |
| Windows console garbled | Windows Terminal recommended (VT sequences auto-enabled) |
## Layout
```
minibot/
config.py config file + env + CLI precedence
state.py bot stats, time decay, atomic JSON persistence
sandbox.py path containment, size limits, write audit
tools.py tool schemas + handlers (add a tool in ~10 lines)
ollama_client.py stdlib HTTP client for /api/chat and /api/tags
needle.py optional intent pre-filter (heuristic | ollama)
orchestrator.py ReAct loop, malformed-retry, history trimming
mcp_server.py stdio MCP server: expose the tools to other agents
tui.py terminal UI: sprite, bars, slash commands
cli.py run/status/feed/treat/stats/history/undo/chat/mcp/doctor
checks.py health checks shared by doctor and /doctor
docs/SRS.md the requirements this implements
tests/ pytest suite (run on a fast disk, not an SD card)
```
## License
MIT — see [LICENSE](LICENSE).
TDQS
Scored across 10 tools
The set splits into two clear clusters: bot-care tools and sandbox-file tools. Within each cluster the operations are distinct, though feed_bot and give_treat have overlapping effects and could occasionally be confused.
Most names are verb_noun, but conventions vary: feed_bot/play_with_bot/rest_bot use a bot suffix, file tools use read_file/write_file/list_dir, and file_history/undo_write break the pattern. Still readable, but not a single predictable scheme.
Ten tools is well-scoped for a small virtual-pet server with sandboxed file support. Each tool has a distinct role and the count does not feel bloated or thin.
Bot care covers feeding, playing, resting, status, and treats, but lacks inventory inspection or healing/medicine operations. File handling covers read, write, list, history, and undo, but misses explicit delete, move, copy, or search operations.