engine
# engine
A self-owned, model-agnostic AI agent client whose core is a **native, host-agnostic plugin
system**. Adding a tool — from a tiny helper to the full `scribe` transcriber — is one small act,
and the same tool works for both you (a REPL command) and the agent (a model tool). Plain
line-REPL by design: no fullscreen TUI, so Polish input, trackpad scroll and text selection just
work. Runtime is stdlib-only and portable (macOS now, Linux/3090 later).
## Layout
- `engine/` — core: `config`, `backends` (the model interface), `plugins` (contract + discovery),
`agent` (the loop), `repl` (the client), `cli` (bare-shell host adapter).
- `plugins/` — drop-in plugins: `sysinfo` (tiny), `scribe` (big). Add one = add a file here.
- `tests/` — pytest suite (deterministic, no network).
- `smoke/` — live checks against a real model (Ollama).
- `tools/check_polish_input.py` — a Polish-keyboard input check.
## Run
```
# REPL (talks to qwen3:8b via Ollama by default):
PYTHONPATH=. .venv/bin/python -m engine.repl
# force the deterministic mock model instead:
ENGINE_BACKEND=mock PYTHONPATH=. .venv/bin/python -m engine.repl
# run a plugin straight from the shell (no model):
PYTHONPATH=. .venv/bin/python -m engine.cli sysinfo
PYTHONPATH=. .venv/bin/python -m engine.cli scribe --help
```
## Add a plugin (zero core edits)
Create `plugins/hello.py`:
```python
from engine.plugins import SimplePlugin
PLUGIN = SimplePlugin("hello", "say hi",
{"type": "object", "properties": {"input": {"type": "string"}}},
lambda a: "hi " + str(a.get("input", "")))
```
It is now a REPL command (`/hello`), a CLI command, and a tool the agent can call.
## Swap the model (one value)
`ENGINE_BACKEND=ollama|mock|anthropic` (+ `ENGINE_OLLAMA_MODEL` / `ENGINE_ANTHROPIC_MODEL`). A new
provider is one branch in `engine/backends.py:get_backend`. (anthropic is code-complete + unit-tested
for wire format; going live needs `ANTHROPIC_API_KEY`.)
## Use the plugins inside Claude Code (MCP)
The same plugins are exposed to Claude Code via a hand-rolled MCP stdio server (stdlib, zero deps):
```
# from the repo root:
claude mcp add engine -- "$PWD/.venv/bin/python" -m engine.hosts.mcp_server
```
Then Claude Code can call `sysinfo` / `calc` / `scribe` as tools — the identical plugins your REPL uses.
## Tests
```
.venv/bin/python -m pytest . # 36 deterministic tests
.venv/bin/python smoke/ollama_agent_smoke.py # live: a real model calls a plugin
.venv/bin/python smoke/filter_spike.py # Phase-2 taste: bge-m3 separates real vs junk (toy)
```
TDQS
Scored across 3 tools
Each tool has a clearly distinct purpose: calc for arithmetic, scribe for video transcription, sysinfo for system information. There is no overlap or ambiguity between them.
All tool names are lowercase single words (calc, scribe, sysinfo), which is consistent in style. However, they don't follow a strict verb_noun pattern, and one is an abbreviation (calc) while another is a concatenation (sysinfo).
Having three tools is borderline appropriate given the server name 'engine' implies a broad utility scope. The count feels thin but not extreme, and each tool seems self-contained.
The tools cover a calculator, a video transcriber, and system info, which are unrelated domains. There are obvious gaps if this is meant as a general-purpose engine (e.g., no file operations, no networking). The set feels incomplete for any coherent purpose.