monet.py
A simple DSPy based coding agent with a Textual TUI.
Install
pip install monet-code
Or for development:
git clone https://github.com/wallyqs/monet.py.git
cd monet.py
uv sync
Run
# Set API keys in .env (loaded automatically)
echo 'export ANTHROPIC_API_KEY=sk-...' >> .env
uv run monet
Features
ReAct-based chat
Chat uses ReAct for multi-step reasoning with tool calling:
class ChatSignature(dspy.Signature): # type: ignore[misc,valid-type]
"""Respond to the user. Use tools when helpful. Maintain context from history.
...
Use Rich markup in log.write(): [bold], [dim], [#F4A300]amber[/], etc.
"""
history: dspy.History = dspy.InputField(
desc="Prior turns of the conversation."
)
message: str = dspy.InputField(desc="The user's current message.")
response: str = dspy.OutputField(desc="Assistant reply.")
self._react = dspy.ReAct(ChatSignature, tools=self._tools)
return self._react
The agent thinks, calls tools, observes results, and iterates until it
has an answer. The trajectory (thinking, tool calls, results) is
displayed in the content pane. By pressing ctrl-o you can toggle
on/off thinking.
Multi-provider model switching
Switch models at runtime with /model or /model <name>. The current
model is shown in the bottom-right corner of the status bar.
| Provider | Models |
|---|---|
| Anthropic | claude-haiku-4-5, claude-sonnet-4, claude-opus-4 |
| OpenAI | gpt-4o, gpt-4o-mini, o3, o4-mini |
| NVIDIA NIM | gpt-oss-20b, gpt-oss-120b, qwen3-coder-480b, kimi-k2.5 |
Built-in coding tools
The agent has access to these tools:
| Tool | Description |
|---|---|
read |
Read files with line numbers, offset, and limit |
write |
Write/create files (creates directories as needed) |
edit |
Exact string replacement with unified diff output |
bash |
Shell command execution with timeout |
grep |
Regex search across files and directories |
list_dir |
List directory contents |
register_command |
Hot-load a slash command plugin from a Python file |
Self-extending
The agent can add new slash commands to itself at runtime via the
register_command. Ask it to "add a /greet monet command" and it
will:
- Create a plugin file at
.monet/commands/greet.py - Call
register_command()to activate it immediately - The command persists across restarts
Plugin files follow a simple convention:
NAME = "/greet"
DESCRIPTION = "Greet someone"
def handler(app, args: str) -> None:
log = app.query_one("#content")
log.write(f"Hi {args.strip() or 'world'}!")
Commands can call app.predict(signature, **kwargs) to query the LLM using DSPy Predict:
def handler(app, args: str) -> None:
log = app.query_one("#content")
result = app.predict("topic -> summary", topic=args.strip())
log.write(result.get("summary", result.get("error", "")))
Commands also have full access to the
Textual framework via the app
object. For example, you can ask the agent: "add a /screenshot monet
command which uses app.save_screenshot()" and it will generate:
NAME = "/screenshot"
DESCRIPTION = "Take a screenshot of the current application"
def handler(app, args: str) -> None:
log = app.query_one("#content")
try:
app.save_screenshot()
log.write("Screenshot saved successfully.")
except Exception as e:
log.write(f"Error saving screenshot: {e}")
Slash command completion
Type / to see available commands. Tab autocompletes from the
filtered list. ctrl+n / ctrl+p navigate the picker.
Input history
ctrl+p / ctrl+n navigate through previously submitted chat
messages (when the command picker is not visible). Slash commands are
not added to history. In-progress text is stashed and restored.
Keyboard shortcuts
| Key | Action |
|---|---|
? |
Show shortcuts help |
/ |
Show available commands |
Tab |
Autocomplete command name |
ctrl+p |
History previous / picker up |
ctrl+n |
History next / picker down |
ctrl+o |
Toggle thinking block visibility |
esc |
Cancel in-flight request |
ctrl+z |
Suspend process |
ctrl+b |
Cursor back one character |
ctrl+f |
Cursor forward one character |
ctrl+k |
Kill to end of line |
ctrl+y |
Yank (paste) killed text |
Response rendering
- Markdown with syntax-highlighted code blocks
- ReAct trajectory display (thinking, tool calls, tool results)
- Unified diffs with syntax highlighting after edits
- Animated spinner during LLM calls
- Text selection and auto-copy to clipboard
- Command output is kept in chat context for follow-up conversation
UI behavior
- Banner auto-hides when content overflows
- Typing anywhere auto-focuses the input
ctrl+oretroactively shows/hides all thinking blocks- Current model shown in status bar
Testing
uv run pytest
Release files for monet-code 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| monet_code-0.1.1.tar.gz | 186.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| monet_code-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 214.1 kB
Release files / monet_code-0.1.1.tar.gz
| Download URL | monet_code-0.1.1.tar.gz |
|---|---|
| Size | 186.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4f2710db8d2a150a20acc0b8690ea1d79ee94c71c2a5c09c34e1077163b93497
|
|
BLAKE2b-256 checksum How to use checksums |
65608ca443f9bf7638968eeb97399a5334293aa9bd2b5709fa47b5aec5eb4565
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.6
|
Release files / monet_code-0.1.1-py3-none-any.whl
| Download URL | monet_code-0.1.1-py3-none-any.whl |
|---|---|
| Size | 28.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1dcf75eb5e5c7730e99a7c2a31a2fcab92636cb0582a93ec5c9336e2454363e9
|
|
BLAKE2b-256 checksum How to use checksums |
c805c36edf7ad6100a5ec962ffc5bf530b2a3ca3121bcbc27594ad4db4551eba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.7.6
|