You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Python coding-agent inspired by [gptel-agent-harness](https://github.com/beacoder/gptel-agent-harness): a terminal coding agent that reads your repo, plans, edits files, runs commands, and verifies its own work — with only **three runtime dependencies** (`rich`, `httpx`, `prompt_toolkit`) and any OpenAI-compatible API. No heavy frameworks, no vendor lock-in.
13
+
A terminal codingagent inspired by [gptel-agent-harness](https://github.com/beacoder/gptel-agent-harness): reads your repo, plans, edits files, runs commands, and verifies its own work — with only **three runtime dependencies** (`rich`, `httpx`, `prompt_toolkit`) and any OpenAI-compatible API.
14
14
15
15
## Demo
16
16
@@ -22,61 +22,27 @@ Python coding-agent inspired by [gptel-agent-harness](https://github.com/beacode
python-agent-harness run # launch the agent in your project dir
28
28
```
29
29
30
-
Optional extras: `pip install -e ".[mcp]"` enables MCP server integration (see below); `pip install -e ".[dev]"` installs the development tooling.
31
-
32
-
Edit `~/.config/python-agent-harness/config.json`, set your `base_url`, `api_key` and `model`, and you're ready to go:
33
-
34
-
```sh
35
-
python-agent-harness run ~/my-project
36
-
```
30
+
Edit `~/.config/python-agent-harness/config.json`, set `base_url`/`api_key`/`model`, and run. Optional: `pip install -e ".[mcp]"` for MCP server integration; `pip install -e ".[dev]"` for dev tooling.
37
31
38
32
## Features
39
33
40
-
### Reliable by design
41
-
42
-
-**FSM-driven execution with completion supervision** — the run is driven by a finite state machine (`WAIT`/`TOOL`/`TRET`/`SUPERVISE`/`DONE`/`ERRS`/`ABRT`). When the model tries to stop before the task is done, it is nudged (max 2); the nudge counter resets on tool calls, and tool results are sanitized so a failed call never strands the machine.
43
-
-**Automatic retry with backoff** — transient failures (HTTP 429 / 5xx, connection errors) retry with exponential backoff + jitter, honoring `Retry-After`; retries never duplicate streamed output, Ctrl-C aborts the wait promptly, and permanent 4xx errors fail fast.
44
-
45
-
### Long conversations, no babysitting
46
-
47
-
-**Context management** — CJK-aware token estimation, per-model context windows (deepseek-v4/glm-5.2 1M, gpt-5 400k, kimi-k2.7 256k, claude 200k, ...), self-calibrating estimates from API-reported input tokens, and automatic compaction at 70% usage that summarizes the conversation and resumes with the last user request.
Tool execution mirrors gptel's `gptel--handle-tool-use`: synchronous tools (Read, Edit, Glob, ...) run one at a time in model-emitted order, while asynchronous tools (Bash, Agent) run concurrently in the background — results delivered in original call order.
54
-
55
-
### Plan before you build
56
-
57
-
-**Plan / Build modes** — plan mode is read-only except the per-session plan file; `PlanExit` switches back to build with an "execute the plan" prompt; sub-agents in plan mode get the read-only reminder.
58
-
59
-
### Sessions that survive
60
-
61
-
- Auto-saved after every response to `~/.local/share/python-agent-harness/sessions/`
62
-
- LLM-generated titles (one-shot, when the run finishes; file renamed to `<title>_<TS>.md`)
63
-
-`/restore` (with `--latest`) and `/sessions` TUI commands
64
-
65
-
### A TUI built for focus
66
-
67
-
- Rich live interface: pinned status bar (mode, context usage, spinner), streaming output, tool-result previews, pinned Todos panel (sub-agent lists labeled `sub:`), and numbered-choice prompts for Question / PlanExit.
68
-
-**Inline diff rendering** — Edit/Write calls capture a unified diff and render it red/green in the TUI, so file changes are visible without leaving the app.
69
-
-`prompt_toolkit` editor: Enter for newline, **Esc+Enter** (or Alt+Enter) to submit, **Tab completion** for slash commands and paths (`~/` and relative, Shift+Tab to cycle backwards), Up/Down history recall (persisted to `~/.local/share/python-agent-harness/input_history`), **Ctrl-D** quits, **Ctrl-C** cancels the current input or run without leaving the app — history is preserved so you can immediately ask a follow-up, and a cancelled worker can never clobber the next run's state (per-run cancellation identity).
70
-
71
-
### Extensible
72
-
73
-
-**MCP servers (optional)** — with `pip install -e ".[mcp]"`, any MCP server's tools become ordinary agent tools, namespaced `mcp__<server>__<tool>` (so `search` from two servers never collides). Supported transports: `stdio` (spawn a command), `streamable-http` and `sse` (remote URLs). Tool discovery happens once at session start; results are normalized into the harness's tool-result format, MCP errors surface as normal tool errors, and `parallel: true` opts a read-only server into concurrent execution (serial by default). Configured in the `mcp` section of the config file (or programmatically via `MCPConfig` + `session.connect_mcp()`); `enabled: false` keeps an entry without connecting it. The `mcp` extra is never required — the base harness works without it.
74
-
-**Default agent prompts** — distinct system prompts for the main agent and sub-agents (`prompts/agent.md`, `prompts/subagent.md`), YAML frontmatter stripped, `{{SKILLS}}` filled from the discovered skill directory; the main prompt is prefixed with project context files and task-completion rules.
75
-
-**Slash commands** — `/init`, `/review`, `/explain`, plus custom commands from `prompts/commands/*.md` become TUI slash commands automatically.
34
+
-**FSM-driven execution** (`WAIT`/`TOOL`/`TRET`/`SUPERVISE`/`DONE`/`ERRS`/`ABRT`) with completion supervision: the model is nudged (max 2) if it stops early; failed tool calls are sanitized and never strand the machine. Transient failures (429/5xx) retry with exponential backoff + jitter.
35
+
-**Context management** — CJK-aware token estimation, per-model context windows, automatic compaction at 70% usage (summarizes and resumes with the last user request).
36
+
-**Real coding tools** — Agent (sub-agents), TodoWrite, Glob, Grep, Read, Insert, Edit (incl. unified diffs), Write, Mkdir, Bash, Skill, Question, PlanExit. Synchronous tools run one at a time; asynchronous ones (Bash, Agent) run concurrently in emitted order.
37
+
-**Plan / Build modes** — plan mode is read-only except the per-session plan file.
38
+
-**Sessions that survive** — auto-saved to `~/.local/share/python-agent-harness/sessions/` after every response, LLM-generated titles, `/restore --latest`, `/sessions`.
39
+
-**A TUI built for focus** — rich live interface with pinned status bar, Todos panel, inline red/green diff rendering for Edit/Write, `prompt_toolkit` editor (Esc+Enter to submit, Tab completion, history, Ctrl-D quits, Ctrl-C cancels without leaving the app).
40
+
-**MCP servers (optional)** — with the `[mcp]` extra, MCP tools become ordinary agent tools (`mcp__<server>__<tool>`); supports `stdio`, `streamable-http`, `sse` transports.
41
+
-**Slash commands** — `/init`, `/review`, `/explain`, plus custom commands from `prompts/commands/*.md`.
76
42
77
43
## Configuration
78
44
79
-
LLM settings live in a JSON config file — no environment variables required:
45
+
All LLM settings live in one JSON config file (no env vars required):
80
46
81
47
```json
82
48
{
@@ -88,61 +54,33 @@ LLM settings live in a JSON config file — no environment variables required:
88
54
"stream": true
89
55
},
90
56
"models": {
91
-
"_comment": "Named LLM profiles for /model switching. Each entry is a partial set of LLM settings; unset keys inherit the main llm.",
-`reasoning_effort` is passed to the API as-is (omitted when unset) — whatever your provider accepts ("low"/"medium"/"high").
137
-
- Other optional keys: `backend`, `temperature`, `max_tokens`, `timeout`, `stream` (`true` by default; `run --no-stream` overrides on the command line).
138
-
-`subagent_llm` configures the LLM for Agent-tool requests: every key is optional and unset keys inherit the main `llm`, so a cheaper/smaller model (or a different provider) can serve delegated work.
139
-
-**Named model profiles** (`models` section) enable runtime switching via `/model`: each profile is a partial LLM settings dict; unset keys inherit the main `llm`. Use `/model` in the TUI to switch between providers/models without restarting.
140
-
-`paths.context_path` / `paths.skill_path` override context/skill discovery — defaults are `<project>/contexts` or `~/.emacs.d/contexts` (skills: `<project>/skills` or `~/.emacs.d/skills`).
141
-
-`mcp.servers` configures MCP servers (requires the `[mcp]` extra). Each server is `{transport, command, args, env, url, headers, parallel, timeout, enabled}` — `stdio` needs `command`/`args` (optionally `env` naming environment variables to pass through, e.g. `["GITHUB_TOKEN"]`); `streamable-http`/`sse` need `url` (optionally `headers`). Its tools appear as `mcp__<server>__<tool>`.
142
-
- Precedence: code defaults < config file < `OPENAI_*` env vars (env still wins if set, but nothing is required). Sub-agent settings honor `OPENAI_SUBAGENT_*` (`_BASE_URL`, `_API_KEY`, `_MODEL`, `_BACKEND`).
143
-
- Use a custom config with `--config PATH` (or `PYTHON_AGENT_HARNESS_CONFIG`).
144
-
145
-
LLM request/response bodies are logged as JSON to `/tmp/python-agent-harness-<date>-<id>.json` (override the directory with `LLM_LOG_DIR`); the path is printed at TUI startup.
76
+
- Optional `llm` keys: `backend`, `temperature`, `max_tokens`, `timeout`, `reasoning_effort` (passed to the API as-is when set), `stream` (`run --no-stream` overrides).
77
+
-**`models`** — named LLM profiles for runtime switching via `/model` (in the TUI: no arg lists, name or number switches). Each profile is a partial settings dict; unset keys inherit the main `llm`.
78
+
-**`subagent_llm`** — LLM for Agent-tool requests; every key optional, unset keys inherit main `llm`. Set `profile` to a name from `models` to reuse a profile; precedence: profile settings > explicit `subagent_llm` keys > main `llm` > env.
- Custom config: `--config PATH` or `PYTHON_AGENT_HARNESS_CONFIG`.
83
+
- LLM request/response bodies are logged as JSON to `/tmp/python-agent-harness-<date>-<id>.json` (override dir with `LLM_LOG_DIR`); path printed at startup.
|`/restore [path\|title\|--latest]`| restore a session (title substring match) |
101
+
|`/restore [path\|title\|--latest\|latest]`| restore a session (title substring match) |
164
102
|`/clear`| start a fresh conversation |
165
-
|`/model [name]`| switch LLM model profile (no arg: list available; with arg: switch to that profile) |
103
+
|`/model [name]`| switch LLM model profile (no arg: list available; with arg: switch) |
166
104
|`/exit`| quit |
167
105
168
-
Custom commands from `prompts/commands/*.md` are registered as slash commands too (TUI-only — no CLI subcommand is registered for them). Tool availability differs per command: `/init` and `/review` may use all tools except `PlanExit` (hidden for the run, including for spawned sub-agents); custom commands may use everything; `compact`/`summary` run with no tools (a one-shot `chat_sync` call, like session-title generation).
106
+
Custom commands from `prompts/commands/*.md` are registered as slash commands too (TUI-only).
0 commit comments