Skip to main content
Pre-release

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:

  • read
  • write
  • edit
  • shell

Features

  • Interactive Python-powered REPL
  • Python 2.7+ and Python 3 compatible
  • Works with OpenAI-compatible /chat/completions endpoints
  • Discovery of AGENTS.md and CLAUDE.md under 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
  • --debug flag 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 oldText must 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
  • write
  • edit
  • read
  • 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.

Release files for chatrepl 0.3.0a11

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chatrepl 0.3.0a11
File Size Uploaded
chatrepl-0.3.0a11.tar.gz 14.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for chatrepl 0.3.0a11
File Interpreter ABI Platform
chatrepl-0.3.0a11-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 25.8 kB

Release files / chatrepl-0.3.0a11.tar.gz

Download URL chatrepl-0.3.0a11.tar.gz
Size 14.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e94fbf938c5a69e6acc289d7710255463815008458f9cd0f100bf63e7a7df295
BLAKE2b-256 checksum
How to use checksums
01379ec15451f262b42dd97e2b500d4a69ffb6968195e1d54ee03c84c4d4706a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / chatrepl-0.3.0a11-py2.py3-none-any.whl

Download URL chatrepl-0.3.0a11-py2.py3-none-any.whl
Size 11.5 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
ba627b44dcece3c43f134893daa0650291fe5e219136cc4c43aefed210042b3e
BLAKE2b-256 checksum
How to use checksums
507c9347b0fac59dc3b6050aca135b148a1247ba1603ecad73b4569bd729b884
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page