comodor 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- comodor-0.1.0/.gitignore +25 -0
- comodor-0.1.0/LICENSE +21 -0
- comodor-0.1.0/PKG-INFO +313 -0
- comodor-0.1.0/README.md +288 -0
- comodor-0.1.0/pyproject.toml +44 -0
- comodor-0.1.0/src/comodor/__init__.py +18 -0
- comodor-0.1.0/src/comodor/__main__.py +6 -0
- comodor-0.1.0/src/comodor/agent/__init__.py +9 -0
- comodor-0.1.0/src/comodor/agent/context.py +149 -0
- comodor-0.1.0/src/comodor/agent/loop.py +409 -0
- comodor-0.1.0/src/comodor/agent/prompts.py +209 -0
- comodor-0.1.0/src/comodor/agent/tokens.py +131 -0
- comodor-0.1.0/src/comodor/cli.py +295 -0
- comodor-0.1.0/src/comodor/config.py +394 -0
- comodor-0.1.0/src/comodor/events.py +211 -0
- comodor-0.1.0/src/comodor/learning/__init__.py +8 -0
- comodor-0.1.0/src/comodor/learning/bm25.py +147 -0
- comodor-0.1.0/src/comodor/learning/hotindex.py +228 -0
- comodor-0.1.0/src/comodor/learning/memory.py +450 -0
- comodor-0.1.0/src/comodor/learning/progress.py +184 -0
- comodor-0.1.0/src/comodor/learning/reflect.py +152 -0
- comodor-0.1.0/src/comodor/learning/rules.py +418 -0
- comodor-0.1.0/src/comodor/learning/signals.py +310 -0
- comodor-0.1.0/src/comodor/learning/store.py +992 -0
- comodor-0.1.0/src/comodor/learning/writer.py +185 -0
- comodor-0.1.0/src/comodor/net/__init__.py +11 -0
- comodor-0.1.0/src/comodor/net/http.py +2036 -0
- comodor-0.1.0/src/comodor/net/sse.py +113 -0
- comodor-0.1.0/src/comodor/paths.py +120 -0
- comodor-0.1.0/src/comodor/providers/__init__.py +24 -0
- comodor-0.1.0/src/comodor/providers/anthropic.py +267 -0
- comodor-0.1.0/src/comodor/providers/base.py +266 -0
- comodor-0.1.0/src/comodor/providers/fake.py +136 -0
- comodor-0.1.0/src/comodor/providers/gateway.py +275 -0
- comodor-0.1.0/src/comodor/providers/openai_compat.py +281 -0
- comodor-0.1.0/src/comodor/providers/registry.py +178 -0
- comodor-0.1.0/src/comodor/safety/__init__.py +11 -0
- comodor-0.1.0/src/comodor/safety/checkpoints.py +232 -0
- comodor-0.1.0/src/comodor/safety/permissions.py +199 -0
- comodor-0.1.0/src/comodor/safety/redact.py +92 -0
- comodor-0.1.0/src/comodor/session/__init__.py +5 -0
- comodor-0.1.0/src/comodor/session/store.py +203 -0
- comodor-0.1.0/src/comodor/tools/__init__.py +7 -0
- comodor-0.1.0/src/comodor/tools/base.py +173 -0
- comodor-0.1.0/src/comodor/tools/fs.py +314 -0
- comodor-0.1.0/src/comodor/tools/registry.py +85 -0
- comodor-0.1.0/src/comodor/tools/search.py +252 -0
- comodor-0.1.0/src/comodor/tools/shell.py +234 -0
- comodor-0.1.0/src/comodor/tools/todo.py +93 -0
- comodor-0.1.0/src/comodor/tools/web.py +174 -0
- comodor-0.1.0/src/comodor/ui/__init__.py +8 -0
- comodor-0.1.0/src/comodor/ui/app.py +1159 -0
- comodor-0.1.0/src/comodor/ui/console.py +125 -0
- comodor-0.1.0/src/comodor/ui/input/__init__.py +15 -0
- comodor-0.1.0/src/comodor/ui/input/keys.py +322 -0
- comodor-0.1.0/src/comodor/ui/input/reader.py +288 -0
- comodor-0.1.0/src/comodor/ui/layout.py +189 -0
- comodor-0.1.0/src/comodor/ui/markdown.py +76 -0
- comodor-0.1.0/src/comodor/ui/screen.py +185 -0
- comodor-0.1.0/src/comodor/ui/theme.py +251 -0
- comodor-0.1.0/src/comodor/ui/widgets/__init__.py +21 -0
- comodor-0.1.0/src/comodor/ui/widgets/buttons.py +108 -0
- comodor-0.1.0/src/comodor/ui/widgets/chat.py +236 -0
- comodor-0.1.0/src/comodor/ui/widgets/history.py +131 -0
- comodor-0.1.0/src/comodor/ui/widgets/overlay.py +246 -0
- comodor-0.1.0/src/comodor/ui/widgets/panel.py +91 -0
- comodor-0.1.0/src/comodor/ui/widgets/progress.py +143 -0
- comodor-0.1.0/src/comodor/ui/widgets/prompt.py +310 -0
- comodor-0.1.0/src/comodor/ui/widgets/statusbar.py +193 -0
- comodor-0.1.0/src/comodor/ui/widgets/toast.py +67 -0
- comodor-0.1.0/tests/conftest.py +76 -0
- comodor-0.1.0/tests/test_agent_loop.py +172 -0
- comodor-0.1.0/tests/test_app.py +534 -0
- comodor-0.1.0/tests/test_input.py +264 -0
- comodor-0.1.0/tests/test_layout.py +210 -0
- comodor-0.1.0/tests/test_learning.py +317 -0
- comodor-0.1.0/tests/test_performance.py +141 -0
- comodor-0.1.0/tests/test_progress.py +187 -0
- comodor-0.1.0/tests/test_providers.py +493 -0
- comodor-0.1.0/tests/test_reflex.py +366 -0
- comodor-0.1.0/tests/test_run_loop.py +155 -0
- comodor-0.1.0/tests/test_tools.py +336 -0
comodor-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
.venv/
|
|
5
|
+
.comodor/
|
|
6
|
+
*.db
|
|
7
|
+
*.db-shm
|
|
8
|
+
*.db-wal
|
|
9
|
+
.env
|
|
10
|
+
dist/
|
|
11
|
+
build/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
|
|
15
|
+
# The comodor.ai site is a separate deliverable and is deliberately not part
|
|
16
|
+
# of this repository. It lives in its own tree.
|
|
17
|
+
website/
|
|
18
|
+
node_modules/
|
|
19
|
+
.next/
|
|
20
|
+
out/
|
|
21
|
+
next-env.d.ts
|
|
22
|
+
*.tsbuildinfo
|
|
23
|
+
.env*.local
|
|
24
|
+
npm-debug.log*
|
|
25
|
+
dist/
|
comodor-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Comodor
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
comodor-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: comodor
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Comodor — a self-improving terminal coding agent with a Rich TUI
|
|
5
|
+
Project-URL: Homepage, https://comodor.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/ifekri/comodor
|
|
7
|
+
Author: Comodor
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: agent,coding-assistant,llm,rich,tui
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Software Development :: Code Generators
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: python-dotenv>=1.0
|
|
21
|
+
Requires-Dist: rich>=13.7
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Comodor
|
|
27
|
+
|
|
28
|
+
**It learns the way you correct it.** — [comodor.ai](https://comodor.ai)
|
|
29
|
+
|
|
30
|
+
A terminal coding agent that reads and edits your files, runs your tests,
|
|
31
|
+
searches the web, and works through multi-step tasks on its own — inside a Rich
|
|
32
|
+
interface that reflows cleanly from a 40-column SSH window to an ultrawide
|
|
33
|
+
monitor.
|
|
34
|
+
|
|
35
|
+
What makes it different is **Reflex**: Comodor watches what you *do* — the code
|
|
36
|
+
you rewrite, the edits you undo, the commands you refuse — and turns that into
|
|
37
|
+
rules, with no model call and no perceptible delay. Fix something once, and the
|
|
38
|
+
next answer already obeys.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
› create defaults.py with 6 string constants
|
|
42
|
+
◈ learned: Use single quotes for string literals. (/rules forget 1 to undo)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
That is a real transcript. The turn before it, Comodor wrote double quotes and the
|
|
46
|
+
file was edited by hand. Nobody told it anything.
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
┌─ History ──────────────┐ ┌─ Chat ───────────────────────────────────────────────┐
|
|
50
|
+
│ TASKS 2/4 ──────────── │ │ › add a health endpoint and a test for it │
|
|
51
|
+
│ ● read the app factory │ │ ◈ recalled 3 lessons │
|
|
52
|
+
│ ● add the /health rou… │ │ │
|
|
53
|
+
│ ◐ write the test │ │ I'll add the route, then a test. │
|
|
54
|
+
│ ○ run the suite │ │ │
|
|
55
|
+
│ │ │ ⚙ edit src/app.py 0.2s │
|
|
56
|
+
│ │ │ + @app.get('/health') │
|
|
57
|
+
│ │ │ ⚙ run: pytest -q 3.4s │
|
|
58
|
+
│ │ │ 4 passed in 0.42s │
|
|
59
|
+
└────────────────────────┘ └──────────────────────────────────────────────────────┘
|
|
60
|
+
┌────────────────────────┐ ┌──────────────────────────────────────────┐
|
|
61
|
+
│ Context:1M GW: Disable │ │ Prompt Here ... │ SEND
|
|
62
|
+
│ Mode : Act Loop : On │ │ ──────────────────────────────────────── │
|
|
63
|
+
│ ███░░░░░░░░░░░░░░░░░░░ │ │ Provider : Openrouter | Model : … │ ATTACH
|
|
64
|
+
│ 143K used $0.041 ◈7 │ │ │
|
|
65
|
+
│ ┌────────────────────┐ │ │ │ MODE
|
|
66
|
+
│ │ Settings │ │ └──────────────────────────────────────────┘
|
|
67
|
+
└────────────────────────┘
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Install
|
|
71
|
+
|
|
72
|
+
**macOS / Linux**
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
curl -fsSL https://comodor.ai/install.sh | sh
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Windows**
|
|
79
|
+
|
|
80
|
+
```powershell
|
|
81
|
+
irm https://comodor.ai/install.ps1 | iex
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The installer uses whichever of `uv`, `pipx` or `pip` you already have. If you
|
|
85
|
+
would rather run one yourself:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv tool install comodor # fastest; fetches a Python if you have none
|
|
89
|
+
pipx install comodor # isolated and on your PATH
|
|
90
|
+
pip install comodor # into the current environment
|
|
91
|
+
pipx install git+https://github.com/ifekri/comodor # latest commit
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Requires Python 3.11+. The only runtime dependencies are `rich` and
|
|
95
|
+
`python-dotenv` — the HTTP client is part of the package.
|
|
96
|
+
|
|
97
|
+
**From a clone**
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
python -m venv .venv
|
|
101
|
+
.venv/Scripts/activate # Windows; source .venv/bin/activate elsewhere
|
|
102
|
+
pip install -e ".[dev]"
|
|
103
|
+
pytest -q
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Configure
|
|
107
|
+
|
|
108
|
+
Copy `.env.example` to `.env` and fill in whichever provider you use:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
OPENROUTER_API_KEY=sk-or-v1-…
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Comodor speaks the OpenAI-compatible protocol (OpenRouter, Xiaomi MiMo, DeepSeek,
|
|
115
|
+
Groq, Together, Ollama, LM Studio) and the native Anthropic Messages API. It
|
|
116
|
+
enables a provider as soon as it finds a key.
|
|
117
|
+
|
|
118
|
+
No key yet? `comodor --demo` runs the whole interface against a scripted offline
|
|
119
|
+
provider.
|
|
120
|
+
|
|
121
|
+
## Use
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
comodor # the interface
|
|
125
|
+
comodor --demo # offline walkthrough, no key needed
|
|
126
|
+
comodor run "fix the failing test" --yes # one task, headless, for scripts
|
|
127
|
+
comodor run "audit this module" --json # machine-readable result
|
|
128
|
+
comodor doctor # what is configured and what is reachable
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Keys
|
|
132
|
+
|
|
133
|
+
| Key | Action |
|
|
134
|
+
|---|---|
|
|
135
|
+
| `Enter` | send · `Ctrl+J` newline |
|
|
136
|
+
| `Esc` | stop the agent |
|
|
137
|
+
| `F1` … `F5` | help · sidebar · mode · loop · gateway |
|
|
138
|
+
| `Ctrl+O` | attach a file |
|
|
139
|
+
| `PgUp` / `PgDn` | scroll the transcript |
|
|
140
|
+
| `Ctrl+C` | stop; twice to quit |
|
|
141
|
+
|
|
142
|
+
`!command` runs a shell command directly. `@path` attaches a file to your
|
|
143
|
+
message. Buttons and the sidebar are clickable where the terminal supports it.
|
|
144
|
+
|
|
145
|
+
### Commands
|
|
146
|
+
|
|
147
|
+
`/help` `/model` `/provider` `/mode` `/loop` `/gw` `/rules` `/progress` `/memory`
|
|
148
|
+
`/teach` `/skills` `/good` `/bad` `/undo` `/cost` `/export` `/theme` `/settings`
|
|
149
|
+
`/approve` `/save` `/attach` `/clear` `/resume` `/quit`
|
|
150
|
+
|
|
151
|
+
## The three switches
|
|
152
|
+
|
|
153
|
+
**Mode** decides what the agent may touch.
|
|
154
|
+
|
|
155
|
+
- **Act** — the full tool set; it can change your project.
|
|
156
|
+
- **Plan** — read-only. Write tools are not merely blocked, they are never shown
|
|
157
|
+
to the model, so you get a plan rather than a thwarted attempt to edit.
|
|
158
|
+
- **Chat** — no tools at all.
|
|
159
|
+
|
|
160
|
+
**Loop** decides whether it keeps going. On, the agent iterates until the task is
|
|
161
|
+
done or a guard trips (steps, wall clock, spend). Off, it answers once.
|
|
162
|
+
|
|
163
|
+
**GW** is the model gateway. Disabled — the default — every request goes to the
|
|
164
|
+
provider you picked, so what the status bar says is what answered. Enabled, it
|
|
165
|
+
ranks healthy providers by cost, speed or quality and fails over when a call
|
|
166
|
+
breaks. A stream that has already produced output is never retried elsewhere:
|
|
167
|
+
duplicating half an answer is worse than reporting the failure.
|
|
168
|
+
|
|
169
|
+
## Reflex — a two-speed brain
|
|
170
|
+
|
|
171
|
+
Most agents remember what you *tell* them. Comodor learns from what you *fix*.
|
|
172
|
+
|
|
173
|
+
**Reflex is the fast lane.** Deterministic, model-free, sub-millisecond, always
|
|
174
|
+
on. It reads five signals, all of them free because you produce them just by
|
|
175
|
+
working:
|
|
176
|
+
|
|
177
|
+
| signal | what it means |
|
|
178
|
+
|---|---|
|
|
179
|
+
| you rewrite a file the agent wrote | the diff *is* the preference — quotes, indentation, annotations, verbosity |
|
|
180
|
+
| you `/undo` a change | an outright rejection |
|
|
181
|
+
| you deny a permission | one command this user does not want run |
|
|
182
|
+
| you ask the same thing twice | the answer missed |
|
|
183
|
+
| a tool fails the same way twice | a pitfall in this environment, verified |
|
|
184
|
+
|
|
185
|
+
Each becomes a **rule** with its evidence attached — not "I think you prefer
|
|
186
|
+
single quotes" but `31 of 34 literals` — and how much evidence a rule needs
|
|
187
|
+
depends on where it came from. Watching your codebase is weak proof, so it takes
|
|
188
|
+
four agreeing observations. You editing the agent's output is a deliberate
|
|
189
|
+
statement, so it takes two. Telling it outright takes one.
|
|
190
|
+
|
|
191
|
+
Detection runs at the *start* of a turn, not the end. That is what makes the
|
|
192
|
+
correction land immediately rather than a task later.
|
|
193
|
+
|
|
194
|
+
**Reflection is the slow lane** — the original LLM pass that distils prose
|
|
195
|
+
lessons from an episode. It still runs, in the background, and it is now
|
|
196
|
+
optional. Switch it off, work offline, use a cheap model: Reflex keeps learning
|
|
197
|
+
either way, because it never needed a model at all.
|
|
198
|
+
|
|
199
|
+
Everything is inspectable and reversible:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
/rules browse rules with their evidence; pin, disable or drop one
|
|
203
|
+
/rules teach Never add comments unless asked.
|
|
204
|
+
/rules export writes .comodor/house-rules.md for the team to commit
|
|
205
|
+
/memory the distilled lessons, same controls
|
|
206
|
+
/teach /good /bad
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Proof, not claims: `/progress`
|
|
210
|
+
|
|
211
|
+
"Gets better over time" is what every tool says. Comodor shows the numbers.
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
◈ Steps per task down 40% since the first tasks in this project.
|
|
215
|
+
|
|
216
|
+
metric trend now vs first
|
|
217
|
+
Steps per task ▇██▇▇▆▇▅▅▅▅▆▄▅▄▅▄▄▂▄▂▁▂▂▂▁▁▁▁▁ 5.3 ↓40%
|
|
218
|
+
Corrections per task ████▆▇▆█▆▆▆▇▆▆▅▃▃▅▆▆▅▃▆▃▆▃▂▁▁▃ 0.9 ↓65%
|
|
219
|
+
Approvals asked █▇▇▇▇▇▇▇▇▇▅▅▅▅▅▅▅▅▅▅▃▃▃▃▃▃▃▃▃▁ 0.8 ↓73%
|
|
220
|
+
Tokens per task █▇████▇▇▆▆▆▆▆▆▅▅▄▄▅▃▃▄▄▃▂▂▂▂▂▁ 6.4K ↓29%
|
|
221
|
+
First-try success ██▁███████████████████████████ 100% ↑8pp
|
|
222
|
+
|
|
223
|
+
brain 7 rules · 23 lessons · 70 corrections learned from
|
|
224
|
+
history 40 tasks over 2 days
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
The panel is built to be honest, which is what makes it worth showing: with too
|
|
228
|
+
little history it says so, a metric that has not moved is reported as unchanged,
|
|
229
|
+
a rate moves in percentage points rather than as a percentage of a percentage,
|
|
230
|
+
and a fall from 0.4 to 0 is never allowed to headline as "down 100%".
|
|
231
|
+
|
|
232
|
+
## Speed
|
|
233
|
+
|
|
234
|
+
Memory sits between pressing Enter and the first token, so it is measured and
|
|
235
|
+
budgeted. Against a deliberately worst-case corpus on a normal laptop:
|
|
236
|
+
|
|
237
|
+
| operation | before | now |
|
|
238
|
+
|---|---|---|
|
|
239
|
+
| recall, 3,000 lessons | 2.0 ms | 0.38 ms |
|
|
240
|
+
| recall, 20,000 lessons | — | **0.38 ms** (flat) |
|
|
241
|
+
| deduplication, 3,000 lessons | 22 ms | 0.25 ms |
|
|
242
|
+
| pinned lookup, 20,000 lessons | 8.9 ms | 0.10 ms |
|
|
243
|
+
| recording reinforcement | 0.04 ms | 0.001 ms |
|
|
244
|
+
|
|
245
|
+
Three things get it there. A **RAM mirror** holds every lesson with its tokens
|
|
246
|
+
pre-computed and an inverted index over them, so a lookup touches only the
|
|
247
|
+
documents sharing a word with the query — and the candidate set is capped, which
|
|
248
|
+
is why the cost stops growing with the corpus. A **background writer** batches
|
|
249
|
+
commits so nothing user-facing ever waits on the disk. And **speculative recall**
|
|
250
|
+
runs the whole ranking while you are still typing, so on the turn itself it
|
|
251
|
+
costs nothing at all.
|
|
252
|
+
|
|
253
|
+
`tests/test_performance.py` enforces these as ceilings. A change that makes
|
|
254
|
+
memory slow fails the suite.
|
|
255
|
+
|
|
256
|
+
## Safety
|
|
257
|
+
|
|
258
|
+
- **Risk tiers.** Reads never prompt. Writes show a coloured diff and ask.
|
|
259
|
+
Commands and network calls always ask.
|
|
260
|
+
- **Checkpoints.** Files are snapshotted before any change; `/undo` restores them.
|
|
261
|
+
- **A deny list** no prompt can talk past, for the handful of commands that are
|
|
262
|
+
never acceptable.
|
|
263
|
+
- **Workspace confinement.** Writes outside the project are refused by default.
|
|
264
|
+
- **Redaction.** API keys and tokens are stripped from logs, transcripts and
|
|
265
|
+
exports.
|
|
266
|
+
- `--yes` exists for CI. Headless runs refuse to change anything without it.
|
|
267
|
+
|
|
268
|
+
## Any terminal, any size
|
|
269
|
+
|
|
270
|
+
The layout is recomputed every frame from the terminal size, so resizing just
|
|
271
|
+
works.
|
|
272
|
+
|
|
273
|
+
| Width | Layout |
|
|
274
|
+
|---|---|
|
|
275
|
+
| `< 60` | one column; sidebar on `F2` |
|
|
276
|
+
| `60–99` | narrow sidebar, compact status |
|
|
277
|
+
| `100–139` | the reference design |
|
|
278
|
+
| `≥ 140` | wide sidebar, roomier transcript |
|
|
279
|
+
|
|
280
|
+
Below 40×12 it says so plainly rather than drawing a corrupted screen. `--ascii`
|
|
281
|
+
drops box-drawing glyphs for terminals that cannot render them, and a monochrome
|
|
282
|
+
terminal gets a monochrome theme automatically.
|
|
283
|
+
|
|
284
|
+
## Layout of the code
|
|
285
|
+
|
|
286
|
+
```
|
|
287
|
+
src/comodor/
|
|
288
|
+
├─ net/ zero-dependency HTTP client + SSE reader
|
|
289
|
+
├─ providers/ OpenAI-compatible, Anthropic, offline fake, and the gateway
|
|
290
|
+
├─ agent/ the reason/act loop, context budgeting, prompts
|
|
291
|
+
├─ tools/ files, search, shell, python, web, task list
|
|
292
|
+
├─ safety/ permissions, checkpoints, redaction
|
|
293
|
+
├─ learning/ the brain: hot index, async writer, signals, rules, progress
|
|
294
|
+
├─ session/ persistence and export
|
|
295
|
+
└─ ui/ layout, theme, widgets, raw input, the app loop
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Development
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
pip install -e ".[dev]"
|
|
302
|
+
pytest -q
|
|
303
|
+
comodor preview 120x34 # render one frame at a fixed size
|
|
304
|
+
comodor preview 60x20 --svg out.svg
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
The test suite runs the whole agent against a scripted provider, so there is no
|
|
308
|
+
network and no spend, and renders the interface at a range of sizes to prove the
|
|
309
|
+
responsive layout holds.
|
|
310
|
+
|
|
311
|
+
## Licence
|
|
312
|
+
|
|
313
|
+
MIT.
|
comodor-0.1.0/README.md
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
# Comodor
|
|
2
|
+
|
|
3
|
+
**It learns the way you correct it.** — [comodor.ai](https://comodor.ai)
|
|
4
|
+
|
|
5
|
+
A terminal coding agent that reads and edits your files, runs your tests,
|
|
6
|
+
searches the web, and works through multi-step tasks on its own — inside a Rich
|
|
7
|
+
interface that reflows cleanly from a 40-column SSH window to an ultrawide
|
|
8
|
+
monitor.
|
|
9
|
+
|
|
10
|
+
What makes it different is **Reflex**: Comodor watches what you *do* — the code
|
|
11
|
+
you rewrite, the edits you undo, the commands you refuse — and turns that into
|
|
12
|
+
rules, with no model call and no perceptible delay. Fix something once, and the
|
|
13
|
+
next answer already obeys.
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
› create defaults.py with 6 string constants
|
|
17
|
+
◈ learned: Use single quotes for string literals. (/rules forget 1 to undo)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
That is a real transcript. The turn before it, Comodor wrote double quotes and the
|
|
21
|
+
file was edited by hand. Nobody told it anything.
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
┌─ History ──────────────┐ ┌─ Chat ───────────────────────────────────────────────┐
|
|
25
|
+
│ TASKS 2/4 ──────────── │ │ › add a health endpoint and a test for it │
|
|
26
|
+
│ ● read the app factory │ │ ◈ recalled 3 lessons │
|
|
27
|
+
│ ● add the /health rou… │ │ │
|
|
28
|
+
│ ◐ write the test │ │ I'll add the route, then a test. │
|
|
29
|
+
│ ○ run the suite │ │ │
|
|
30
|
+
│ │ │ ⚙ edit src/app.py 0.2s │
|
|
31
|
+
│ │ │ + @app.get('/health') │
|
|
32
|
+
│ │ │ ⚙ run: pytest -q 3.4s │
|
|
33
|
+
│ │ │ 4 passed in 0.42s │
|
|
34
|
+
└────────────────────────┘ └──────────────────────────────────────────────────────┘
|
|
35
|
+
┌────────────────────────┐ ┌──────────────────────────────────────────┐
|
|
36
|
+
│ Context:1M GW: Disable │ │ Prompt Here ... │ SEND
|
|
37
|
+
│ Mode : Act Loop : On │ │ ──────────────────────────────────────── │
|
|
38
|
+
│ ███░░░░░░░░░░░░░░░░░░░ │ │ Provider : Openrouter | Model : … │ ATTACH
|
|
39
|
+
│ 143K used $0.041 ◈7 │ │ │
|
|
40
|
+
│ ┌────────────────────┐ │ │ │ MODE
|
|
41
|
+
│ │ Settings │ │ └──────────────────────────────────────────┘
|
|
42
|
+
└────────────────────────┘
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
**macOS / Linux**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
curl -fsSL https://comodor.ai/install.sh | sh
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Windows**
|
|
54
|
+
|
|
55
|
+
```powershell
|
|
56
|
+
irm https://comodor.ai/install.ps1 | iex
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The installer uses whichever of `uv`, `pipx` or `pip` you already have. If you
|
|
60
|
+
would rather run one yourself:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv tool install comodor # fastest; fetches a Python if you have none
|
|
64
|
+
pipx install comodor # isolated and on your PATH
|
|
65
|
+
pip install comodor # into the current environment
|
|
66
|
+
pipx install git+https://github.com/ifekri/comodor # latest commit
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Requires Python 3.11+. The only runtime dependencies are `rich` and
|
|
70
|
+
`python-dotenv` — the HTTP client is part of the package.
|
|
71
|
+
|
|
72
|
+
**From a clone**
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
python -m venv .venv
|
|
76
|
+
.venv/Scripts/activate # Windows; source .venv/bin/activate elsewhere
|
|
77
|
+
pip install -e ".[dev]"
|
|
78
|
+
pytest -q
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Configure
|
|
82
|
+
|
|
83
|
+
Copy `.env.example` to `.env` and fill in whichever provider you use:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
OPENROUTER_API_KEY=sk-or-v1-…
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Comodor speaks the OpenAI-compatible protocol (OpenRouter, Xiaomi MiMo, DeepSeek,
|
|
90
|
+
Groq, Together, Ollama, LM Studio) and the native Anthropic Messages API. It
|
|
91
|
+
enables a provider as soon as it finds a key.
|
|
92
|
+
|
|
93
|
+
No key yet? `comodor --demo` runs the whole interface against a scripted offline
|
|
94
|
+
provider.
|
|
95
|
+
|
|
96
|
+
## Use
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
comodor # the interface
|
|
100
|
+
comodor --demo # offline walkthrough, no key needed
|
|
101
|
+
comodor run "fix the failing test" --yes # one task, headless, for scripts
|
|
102
|
+
comodor run "audit this module" --json # machine-readable result
|
|
103
|
+
comodor doctor # what is configured and what is reachable
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Keys
|
|
107
|
+
|
|
108
|
+
| Key | Action |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `Enter` | send · `Ctrl+J` newline |
|
|
111
|
+
| `Esc` | stop the agent |
|
|
112
|
+
| `F1` … `F5` | help · sidebar · mode · loop · gateway |
|
|
113
|
+
| `Ctrl+O` | attach a file |
|
|
114
|
+
| `PgUp` / `PgDn` | scroll the transcript |
|
|
115
|
+
| `Ctrl+C` | stop; twice to quit |
|
|
116
|
+
|
|
117
|
+
`!command` runs a shell command directly. `@path` attaches a file to your
|
|
118
|
+
message. Buttons and the sidebar are clickable where the terminal supports it.
|
|
119
|
+
|
|
120
|
+
### Commands
|
|
121
|
+
|
|
122
|
+
`/help` `/model` `/provider` `/mode` `/loop` `/gw` `/rules` `/progress` `/memory`
|
|
123
|
+
`/teach` `/skills` `/good` `/bad` `/undo` `/cost` `/export` `/theme` `/settings`
|
|
124
|
+
`/approve` `/save` `/attach` `/clear` `/resume` `/quit`
|
|
125
|
+
|
|
126
|
+
## The three switches
|
|
127
|
+
|
|
128
|
+
**Mode** decides what the agent may touch.
|
|
129
|
+
|
|
130
|
+
- **Act** — the full tool set; it can change your project.
|
|
131
|
+
- **Plan** — read-only. Write tools are not merely blocked, they are never shown
|
|
132
|
+
to the model, so you get a plan rather than a thwarted attempt to edit.
|
|
133
|
+
- **Chat** — no tools at all.
|
|
134
|
+
|
|
135
|
+
**Loop** decides whether it keeps going. On, the agent iterates until the task is
|
|
136
|
+
done or a guard trips (steps, wall clock, spend). Off, it answers once.
|
|
137
|
+
|
|
138
|
+
**GW** is the model gateway. Disabled — the default — every request goes to the
|
|
139
|
+
provider you picked, so what the status bar says is what answered. Enabled, it
|
|
140
|
+
ranks healthy providers by cost, speed or quality and fails over when a call
|
|
141
|
+
breaks. A stream that has already produced output is never retried elsewhere:
|
|
142
|
+
duplicating half an answer is worse than reporting the failure.
|
|
143
|
+
|
|
144
|
+
## Reflex — a two-speed brain
|
|
145
|
+
|
|
146
|
+
Most agents remember what you *tell* them. Comodor learns from what you *fix*.
|
|
147
|
+
|
|
148
|
+
**Reflex is the fast lane.** Deterministic, model-free, sub-millisecond, always
|
|
149
|
+
on. It reads five signals, all of them free because you produce them just by
|
|
150
|
+
working:
|
|
151
|
+
|
|
152
|
+
| signal | what it means |
|
|
153
|
+
|---|---|
|
|
154
|
+
| you rewrite a file the agent wrote | the diff *is* the preference — quotes, indentation, annotations, verbosity |
|
|
155
|
+
| you `/undo` a change | an outright rejection |
|
|
156
|
+
| you deny a permission | one command this user does not want run |
|
|
157
|
+
| you ask the same thing twice | the answer missed |
|
|
158
|
+
| a tool fails the same way twice | a pitfall in this environment, verified |
|
|
159
|
+
|
|
160
|
+
Each becomes a **rule** with its evidence attached — not "I think you prefer
|
|
161
|
+
single quotes" but `31 of 34 literals` — and how much evidence a rule needs
|
|
162
|
+
depends on where it came from. Watching your codebase is weak proof, so it takes
|
|
163
|
+
four agreeing observations. You editing the agent's output is a deliberate
|
|
164
|
+
statement, so it takes two. Telling it outright takes one.
|
|
165
|
+
|
|
166
|
+
Detection runs at the *start* of a turn, not the end. That is what makes the
|
|
167
|
+
correction land immediately rather than a task later.
|
|
168
|
+
|
|
169
|
+
**Reflection is the slow lane** — the original LLM pass that distils prose
|
|
170
|
+
lessons from an episode. It still runs, in the background, and it is now
|
|
171
|
+
optional. Switch it off, work offline, use a cheap model: Reflex keeps learning
|
|
172
|
+
either way, because it never needed a model at all.
|
|
173
|
+
|
|
174
|
+
Everything is inspectable and reversible:
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
/rules browse rules with their evidence; pin, disable or drop one
|
|
178
|
+
/rules teach Never add comments unless asked.
|
|
179
|
+
/rules export writes .comodor/house-rules.md for the team to commit
|
|
180
|
+
/memory the distilled lessons, same controls
|
|
181
|
+
/teach /good /bad
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Proof, not claims: `/progress`
|
|
185
|
+
|
|
186
|
+
"Gets better over time" is what every tool says. Comodor shows the numbers.
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
◈ Steps per task down 40% since the first tasks in this project.
|
|
190
|
+
|
|
191
|
+
metric trend now vs first
|
|
192
|
+
Steps per task ▇██▇▇▆▇▅▅▅▅▆▄▅▄▅▄▄▂▄▂▁▂▂▂▁▁▁▁▁ 5.3 ↓40%
|
|
193
|
+
Corrections per task ████▆▇▆█▆▆▆▇▆▆▅▃▃▅▆▆▅▃▆▃▆▃▂▁▁▃ 0.9 ↓65%
|
|
194
|
+
Approvals asked █▇▇▇▇▇▇▇▇▇▅▅▅▅▅▅▅▅▅▅▃▃▃▃▃▃▃▃▃▁ 0.8 ↓73%
|
|
195
|
+
Tokens per task █▇████▇▇▆▆▆▆▆▆▅▅▄▄▅▃▃▄▄▃▂▂▂▂▂▁ 6.4K ↓29%
|
|
196
|
+
First-try success ██▁███████████████████████████ 100% ↑8pp
|
|
197
|
+
|
|
198
|
+
brain 7 rules · 23 lessons · 70 corrections learned from
|
|
199
|
+
history 40 tasks over 2 days
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The panel is built to be honest, which is what makes it worth showing: with too
|
|
203
|
+
little history it says so, a metric that has not moved is reported as unchanged,
|
|
204
|
+
a rate moves in percentage points rather than as a percentage of a percentage,
|
|
205
|
+
and a fall from 0.4 to 0 is never allowed to headline as "down 100%".
|
|
206
|
+
|
|
207
|
+
## Speed
|
|
208
|
+
|
|
209
|
+
Memory sits between pressing Enter and the first token, so it is measured and
|
|
210
|
+
budgeted. Against a deliberately worst-case corpus on a normal laptop:
|
|
211
|
+
|
|
212
|
+
| operation | before | now |
|
|
213
|
+
|---|---|---|
|
|
214
|
+
| recall, 3,000 lessons | 2.0 ms | 0.38 ms |
|
|
215
|
+
| recall, 20,000 lessons | — | **0.38 ms** (flat) |
|
|
216
|
+
| deduplication, 3,000 lessons | 22 ms | 0.25 ms |
|
|
217
|
+
| pinned lookup, 20,000 lessons | 8.9 ms | 0.10 ms |
|
|
218
|
+
| recording reinforcement | 0.04 ms | 0.001 ms |
|
|
219
|
+
|
|
220
|
+
Three things get it there. A **RAM mirror** holds every lesson with its tokens
|
|
221
|
+
pre-computed and an inverted index over them, so a lookup touches only the
|
|
222
|
+
documents sharing a word with the query — and the candidate set is capped, which
|
|
223
|
+
is why the cost stops growing with the corpus. A **background writer** batches
|
|
224
|
+
commits so nothing user-facing ever waits on the disk. And **speculative recall**
|
|
225
|
+
runs the whole ranking while you are still typing, so on the turn itself it
|
|
226
|
+
costs nothing at all.
|
|
227
|
+
|
|
228
|
+
`tests/test_performance.py` enforces these as ceilings. A change that makes
|
|
229
|
+
memory slow fails the suite.
|
|
230
|
+
|
|
231
|
+
## Safety
|
|
232
|
+
|
|
233
|
+
- **Risk tiers.** Reads never prompt. Writes show a coloured diff and ask.
|
|
234
|
+
Commands and network calls always ask.
|
|
235
|
+
- **Checkpoints.** Files are snapshotted before any change; `/undo` restores them.
|
|
236
|
+
- **A deny list** no prompt can talk past, for the handful of commands that are
|
|
237
|
+
never acceptable.
|
|
238
|
+
- **Workspace confinement.** Writes outside the project are refused by default.
|
|
239
|
+
- **Redaction.** API keys and tokens are stripped from logs, transcripts and
|
|
240
|
+
exports.
|
|
241
|
+
- `--yes` exists for CI. Headless runs refuse to change anything without it.
|
|
242
|
+
|
|
243
|
+
## Any terminal, any size
|
|
244
|
+
|
|
245
|
+
The layout is recomputed every frame from the terminal size, so resizing just
|
|
246
|
+
works.
|
|
247
|
+
|
|
248
|
+
| Width | Layout |
|
|
249
|
+
|---|---|
|
|
250
|
+
| `< 60` | one column; sidebar on `F2` |
|
|
251
|
+
| `60–99` | narrow sidebar, compact status |
|
|
252
|
+
| `100–139` | the reference design |
|
|
253
|
+
| `≥ 140` | wide sidebar, roomier transcript |
|
|
254
|
+
|
|
255
|
+
Below 40×12 it says so plainly rather than drawing a corrupted screen. `--ascii`
|
|
256
|
+
drops box-drawing glyphs for terminals that cannot render them, and a monochrome
|
|
257
|
+
terminal gets a monochrome theme automatically.
|
|
258
|
+
|
|
259
|
+
## Layout of the code
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
src/comodor/
|
|
263
|
+
├─ net/ zero-dependency HTTP client + SSE reader
|
|
264
|
+
├─ providers/ OpenAI-compatible, Anthropic, offline fake, and the gateway
|
|
265
|
+
├─ agent/ the reason/act loop, context budgeting, prompts
|
|
266
|
+
├─ tools/ files, search, shell, python, web, task list
|
|
267
|
+
├─ safety/ permissions, checkpoints, redaction
|
|
268
|
+
├─ learning/ the brain: hot index, async writer, signals, rules, progress
|
|
269
|
+
├─ session/ persistence and export
|
|
270
|
+
└─ ui/ layout, theme, widgets, raw input, the app loop
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Development
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
pip install -e ".[dev]"
|
|
277
|
+
pytest -q
|
|
278
|
+
comodor preview 120x34 # render one frame at a fixed size
|
|
279
|
+
comodor preview 60x20 --svg out.svg
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
The test suite runs the whole agent against a scripted provider, so there is no
|
|
283
|
+
network and no spend, and renders the interface at a range of sizes to prove the
|
|
284
|
+
responsive layout holds.
|
|
285
|
+
|
|
286
|
+
## Licence
|
|
287
|
+
|
|
288
|
+
MIT.
|