This release is a pre-release and may not be stable for production use.
chatrepl
A minimal agent for OpenAI-compatible Chat Completions APIs with four built-in tools:
readwriteeditshell
Features
- Interactive Python-powered REPL
- Python 2.7+ and Python 3 compatible
- Works with OpenAI-compatible
/chat/completionsendpoints - Discovery of
AGENTS.mdandCLAUDE.mdunder the current working directory - Streaming assistant responses
- Reasoning deltas streamed inline as
[reasoning]sections when the provider reports them - Editable multiline input through your editor
- Non-interactive CLI mode for piped input or one-shot prompts
--debugflag to print tool call deltas as they stream in
Installation
pip install chatrepl
Usage
CLI options
-k, --api-key API key for the OpenAI-compatible endpoint
-u, --base-url Base URL, e.g. http://localhost:11434/v1
-m, --model Model ID
--no-stream Disable streaming
--no-context-files Disable AGENTS.md and CLAUDE.md discovery
--debug Print tool call deltas as they stream in
Interactive REPL
chatrepl \
--api-key "your-api-key" \
--base-url "https://api.openai.com/v1" \
--model "gpt-5.4"
You enter a Python interactive console with helper functions preloaded.
Available commands:
| Function | Description |
|---|---|
send(text='', image_path=None, stream=True) |
Send a message and let the agent complete tool calls, optionally with a local image path used as-is and streaming control |
send(...) with reasoning |
When the provider streams reasoning content, it is printed under a [reasoning] header before the final text |
append(text) |
Append a user message without sending |
multiline() |
Append multiline input from your editor |
txt(path) |
Append a UTF-8 text file as a user message using the provided path as-is |
img(path) |
Append a local image as a user message; files are embedded as data URLs using the provided path as-is |
reset() |
Reset to only the system prompt |
save(path) |
Save the current conversation transcript as a JSON messages file |
load(path) |
Load a saved JSON transcript and append it to the current conversation |
Exit with exit() or EOF.
One-shot prompt
chatrepl \
--api-key "your-api-key" \
--base-url "https://api.openai.com/v1" \
--model "gpt-4o" \
"Inspect this repository and summarize the build system"
Piped input
cat prompt.txt | chatrepl \
--api-key "your-api-key" \
--base-url "https://api.openai.com/v1" \
--model "gpt-4o"
Tool model
The agent is intentionally small and constrained.
read
Reads a text file with optional offset and limit arguments.
- Uses the provided path as-is
write
Writes full file contents.
- Creates parent directories automatically
- Rewrites the destination file completely
edit
Applies exact text replacements to an existing file.
Rules:
- each
oldTextmust match exactly once - edits must not overlap
- all edits are matched against the original file
Returns a unified diff after a successful edit.
shell
Runs a shell command in the current working directory.
- live output is streamed to the terminal
- full output is returned to the model
Example session
Turn 1: appended user message, then send with no new text
This is useful because it exercises the path where send() is called with no pending user message.
>>> append("Reply with exactly APPENDED-OK.")
>>> send(stream=False)
Assistant response:
APPENDED-OK
Turn 2: streamed text + streamed tool-call deltas + follow-up tool result
>>> send("Read hello.txt and quote its contents back to me.", stream=True)
Mock streamed assistant output:
I’ll inspect the file.
[assistant is preparing tool call(s)]
[tool_call 0]
id: call_read_1
type: function
name += re
name += ad
arguments += {"path":"he
arguments += llo.txt"}
Then tool execution:
[assistant is using 1 tool(s)]
[tool read]
Hello!
Then assistant follow-up response:
The file contains `Hello!`.
Turn 3: multiple tool calls in one assistant message
This exercises:
- multiple tool calls
writeeditread- diff generation
- tool index tracking in streaming
>>> send("Create tmp/demo.txt with alpha and beta on separate lines, change beta to gamma, then read it back.", stream=True)
Mock streamed assistant output:
I’ll create the file, patch it, and verify the result.
[assistant is preparing tool call(s)]
[tool_call 0]
id: call_write_1
type: function
name += wr
name += ite
arguments += {"path":"tmp/demo.txt","content":"alpha\nbeta\n"}
[tool_call 1]
id: call_edit_1
type: function
name += ed
name += it
arguments += {"path":"tmp/demo.txt","edits":[{"oldText":"beta","newText":"gamma"}]}
[tool_call 2]
id: call_read_2
type: function
name += read
arguments += {"path":"tmp/demo.txt"}
Then tool execution:
[assistant is using 3 tool(s)]
[tool write]
Successfully wrote 11 characters to <repo>/tmp/demo.txt
[tool edit]
Applied 1 edit(s) to <repo>/tmp/demo.txt
--- <repo>/tmp/demo.txt
+++ <repo>/tmp/demo.txt
@@
-alpha
-beta
+alpha
+gamma
[tool read]
alpha
gamma
Then assistant follow-up:
Done. `tmp/demo.txt` now contains:
- alpha
- gamma
Turn 4: shell tool, stdout + stderr, non-streaming
>>> send("Run a shell command that prints one line to stdout and one to stderr.", stream=False)
Assistant response with tool call:
I’ll run a small shell command.
Then tool execution:
[assistant is using 1 tool(s)]
[tool shell]
$ printf 'stdout-line\n'; printf 'stderr-line\n' >&2
Exit code: 0
stdout-line
stderr-line
Then assistant follow-up:
The shell command succeeded and produced both stdout and stderr output.
License
This project is licensed under the MIT License.
Metadata
Release files for chatrepl 0.3.0a12
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| chatrepl-0.3.0a12.tar.gz | 16.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chatrepl-0.3.0a12-py2.py3-none-any.whl | Python 2, Python 3 | none | any | Details |
Total release size: 28.1 kB
Release files / chatrepl-0.3.0a12.tar.gz
| Download URL | chatrepl-0.3.0a12.tar.gz |
|---|---|
| Size | 16.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a569b643f9135c535bf6298b6739b6fc8e5f2ca3c6704b911ff936c62682095f
|
|
BLAKE2b-256 checksum How to use checksums |
045d0dcc4a61e0c8993aec0af2b46d805094393beb5dfcdf213650f40b41e8d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / chatrepl-0.3.0a12-py2.py3-none-any.whl
| Download URL | chatrepl-0.3.0a12-py2.py3-none-any.whl |
|---|---|
| Size | 11.6 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
d63e2155bf863654300d2282265bfec7ba894677c6c6ce0b81d92d19dba0c015
|
|
BLAKE2b-256 checksum How to use checksums |
383e24a9806c099f7446e487b1ea49eacdb22cb9fd56d15cdd2a4b1dc24cce60
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Security for chatrepl 0.3.0a12
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.