python-vibe

ask, test, fix, add

GitHub

Commands

The usual way is the python-vibe command. You can also call the Python library, or an HTTP server on 127.0.0.1.

Command line

python-vibe                  # prints the command list
python-vibe brief            # no model
python-vibe ask  "what does compute_total return?"
python-vibe run  "write tests for apply_discount"
python-vibe run  "write tests for apply_discount" --dry-run --scope src
python-vibe serve --project .
python-vibe editors cursor --allow-writes

python -m harness … is the same command if python-vibe is not on PATH.

brief, layout, and route never call a model. ask never changes files. run writes unless you pass --dry-run. Add --json for machine-readable output, -v for tool results.

What run may do to your project

run changes files inside the folder you give it, keeps a .bak copy of anything it edits, and runs that project’s test suite to check its own work. If you would rather it did nothing, use ask, or pass --dry-run, which refuses every change and never runs anything.

Some fixes need no model at all. A misspelled name that Python cannot resolve, or a rename you asked for by name, are corrected directly; the tests are then run once, and if they pass the task ends there.

Library

from pathlib import Path
from harness import Agent, AgentOptions

agent = Agent(AgentOptions(project=Path("~/app"), scope="src"))
result = agent.run("add multiply(a, b) and a unit test")

result.ok        # True when the agent finished the task
result.summary   # its closing sentence
result.writes    # files it changed
result.steps     # every turn, in order
result.refusals  # what the harness stopped, and why

Settings

Field Default What it does
project required Directory the agent may read and write inside
task "" What you are asking for
model llama3.1:8b Ollama model name
engine ollama ollama, mlx, or openai (remote OpenAI-compatible HTTP)
scope "" Stay inside this subdirectory
skills () Skill names to load. Empty means choose from the task. Catalog: Skills
steps 20 Maximum model turns before the run stops
max_tokens 700 Maximum length of one model reply
allow_writes True When False, patch, edit and run are refused
record None File to append redacted turns to. None writes .python-vibe/traces.jsonl in the project
keep_no_record False Write no trace (--no-record)
on_event None Called with progress messages
on_question None Called when the agent needs you to choose

Read-only runs

options = AgentOptions(project=Path("~/app"), allow_writes=False)
Agent(options).run("what would you change in src/app.py?")

Nothing is written. patch, edit and run are refused before any tool sees them, and the prompt says the run is read-only.

When the agent needs to know something

A task such as "clean this up" names no file and no function. Rather than guessing, the harness asks before it calls the model:

def choose(question):
    print(question.render())
    return input("> ")

Agent(AgentOptions(project=..., on_question=choose)).run("clean this up")

Without on_question the run stops immediately and returns the question:

result.stopped   # "question"
result.summary   # the question and the options
result.writes    # ()

Install

The harness uses only the standard library, so there is nothing to build and the same three commands work on macOS, Linux and Windows.

git clone https://github.com/YauhenBichel/python-vibe.git
cd python-vibe
python3 scripts/run/install.py
source .venv/bin/activate

That creates .venv when needed and runs pip install -e .. Activate it in every new terminal, or the shell says command not found. Already in a virtualenv: pip install -e . is the same install. The sample project is cd demo/orders then python-vibe brief.

That gives you a python-vibe command. No PYTHONPATH, no version-pinned interpreter, no script paths:

  Before After
macOS / Linux PYTHONPATH=src python3.13 scripts/run/agent.py --project ~/app "..." python-vibe run "…" in that folder
Windows did not work: PYTHONPATH=src is not valid in cmd or PowerShell python-vibe run "…" in that folder

Training on Apple Silicon needs extras: pip install -e ".[train]". Publishing to the Hub needs pip install -e ".[hub]".

Remote weights

--engine openai sends generate calls to an OpenAI-compatible host (Hugging Face Inference, vLLM, or a box you rent). The write limit stays on this machine. Set PYTHON_VIBE_BASE_URL and a token (HF_TOKEN or PYTHON_VIBE_API_KEY). A remote Ollama is the same --engine ollama with OLLAMA_HOST pointed at that box.

What goes to that host is read before it leaves. A prompt carrying an AWS access key, an Anthropic key, a GitHub token or a private key is refused rather than sent, and the refusal names the kind without repeating the value. A prompt over 200,000 characters is refused as well, on the grounds that a whole tree is a mistake rather than a task; raise PYTHON_VIBE_MAX_SEND if it was the intent. The first send of a run prints how many characters went where, so nobody has to guess.

None of this runs for a local host. Sending to 127.0.0.1 is not sending.

See cloud weights.

Hub GGUFs that Ollama does not ship

OpenCoder 8B and SWE-agent-LM 7B are on Hugging Face, not in the Ollama library. From a clone of this repo:

python3 scripts/weights/import_hf_ollama.py --name opencoder
python3 scripts/weights/import_hf_ollama.py --name swe-agent-lm
python-vibe --model opencoder:8b run "add a function clamp and a unit test"

That downloads the Q4_K_M GGUF (~4.7 GB each) and runs ollama create. Default stays llama3.1:8b. See Hub models.

Paths are always written with forward slashes, on every platform, because the model is shown them and copies them back.

HTTP server

python-vibe serve --project ~/app --port 8090

Binds 127.0.0.1 only. File changes are off by default, because an HTTP request that reaches the agent can change files on the machine the server runs on.

Route Method Needs --allow-writes
/health GET no
/v1/brief POST no
/v1/layout POST no
/v1/ask POST no
/v1/models GET no
/v1/chat/completions POST writes only with --allow-writes
/v1/run POST yes
curl -s localhost:8090/health
curl -s localhost:8090/v1/layout -d '{}'
curl -s localhost:8090/v1/ask -d '{"task":"what does compute_total return?"}'
curl -s localhost:8090/v1/models

POST /v1/chat/completions takes the last user message as the task and returns an OpenAI-shaped reply. stream is refused. A write task on a read-only server is 403. Point VS Code and other OpenAI-compatible editors at http://127.0.0.1:8090/v1, or copy drop-in files with python-vibe editors cursor --allow-writes. Details: Cursor · local editor.

Without --allow-writes, /v1/run answers 403 and says how to enable it. The path restriction, the draft guard and the .bak backup apply in every mode; the flag is an additional control, not a replacement for them.