Simple DSPy based coding harness with a Textual TUI
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file monet_code-0.1.1.tar.gz.
File metadata
- Download URL: monet_code-0.1.1.tar.gz
- Upload date:
- Size: 186.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f2710db8d2a150a20acc0b8690ea1d79ee94c71c2a5c09c34e1077163b93497
|
|
| MD5 |
f47e84a1b186e6415d7a4c57bf811c93
|
|
| BLAKE2b-256 |
65608ca443f9bf7638968eeb97399a5334293aa9bd2b5709fa47b5aec5eb4565
|
File details
Details for the file monet_code-0.1.1-py3-none-any.whl.
File metadata
- Download URL: monet_code-0.1.1-py3-none-any.whl
- Upload date:
- Size: 28.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.7.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1dcf75eb5e5c7730e99a7c2a31a2fcab92636cb0582a93ec5c9336e2454363e9
|
|
| MD5 |
ae84e972635fda418af7de0188af4c2e
|
|
| BLAKE2b-256 |
c805c36edf7ad6100a5ec962ffc5bf530b2a3ca3121bcbc27594ad4db4551eba
|