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.
Files changed (82) hide show
  1. comodor-0.1.0/.gitignore +25 -0
  2. comodor-0.1.0/LICENSE +21 -0
  3. comodor-0.1.0/PKG-INFO +313 -0
  4. comodor-0.1.0/README.md +288 -0
  5. comodor-0.1.0/pyproject.toml +44 -0
  6. comodor-0.1.0/src/comodor/__init__.py +18 -0
  7. comodor-0.1.0/src/comodor/__main__.py +6 -0
  8. comodor-0.1.0/src/comodor/agent/__init__.py +9 -0
  9. comodor-0.1.0/src/comodor/agent/context.py +149 -0
  10. comodor-0.1.0/src/comodor/agent/loop.py +409 -0
  11. comodor-0.1.0/src/comodor/agent/prompts.py +209 -0
  12. comodor-0.1.0/src/comodor/agent/tokens.py +131 -0
  13. comodor-0.1.0/src/comodor/cli.py +295 -0
  14. comodor-0.1.0/src/comodor/config.py +394 -0
  15. comodor-0.1.0/src/comodor/events.py +211 -0
  16. comodor-0.1.0/src/comodor/learning/__init__.py +8 -0
  17. comodor-0.1.0/src/comodor/learning/bm25.py +147 -0
  18. comodor-0.1.0/src/comodor/learning/hotindex.py +228 -0
  19. comodor-0.1.0/src/comodor/learning/memory.py +450 -0
  20. comodor-0.1.0/src/comodor/learning/progress.py +184 -0
  21. comodor-0.1.0/src/comodor/learning/reflect.py +152 -0
  22. comodor-0.1.0/src/comodor/learning/rules.py +418 -0
  23. comodor-0.1.0/src/comodor/learning/signals.py +310 -0
  24. comodor-0.1.0/src/comodor/learning/store.py +992 -0
  25. comodor-0.1.0/src/comodor/learning/writer.py +185 -0
  26. comodor-0.1.0/src/comodor/net/__init__.py +11 -0
  27. comodor-0.1.0/src/comodor/net/http.py +2036 -0
  28. comodor-0.1.0/src/comodor/net/sse.py +113 -0
  29. comodor-0.1.0/src/comodor/paths.py +120 -0
  30. comodor-0.1.0/src/comodor/providers/__init__.py +24 -0
  31. comodor-0.1.0/src/comodor/providers/anthropic.py +267 -0
  32. comodor-0.1.0/src/comodor/providers/base.py +266 -0
  33. comodor-0.1.0/src/comodor/providers/fake.py +136 -0
  34. comodor-0.1.0/src/comodor/providers/gateway.py +275 -0
  35. comodor-0.1.0/src/comodor/providers/openai_compat.py +281 -0
  36. comodor-0.1.0/src/comodor/providers/registry.py +178 -0
  37. comodor-0.1.0/src/comodor/safety/__init__.py +11 -0
  38. comodor-0.1.0/src/comodor/safety/checkpoints.py +232 -0
  39. comodor-0.1.0/src/comodor/safety/permissions.py +199 -0
  40. comodor-0.1.0/src/comodor/safety/redact.py +92 -0
  41. comodor-0.1.0/src/comodor/session/__init__.py +5 -0
  42. comodor-0.1.0/src/comodor/session/store.py +203 -0
  43. comodor-0.1.0/src/comodor/tools/__init__.py +7 -0
  44. comodor-0.1.0/src/comodor/tools/base.py +173 -0
  45. comodor-0.1.0/src/comodor/tools/fs.py +314 -0
  46. comodor-0.1.0/src/comodor/tools/registry.py +85 -0
  47. comodor-0.1.0/src/comodor/tools/search.py +252 -0
  48. comodor-0.1.0/src/comodor/tools/shell.py +234 -0
  49. comodor-0.1.0/src/comodor/tools/todo.py +93 -0
  50. comodor-0.1.0/src/comodor/tools/web.py +174 -0
  51. comodor-0.1.0/src/comodor/ui/__init__.py +8 -0
  52. comodor-0.1.0/src/comodor/ui/app.py +1159 -0
  53. comodor-0.1.0/src/comodor/ui/console.py +125 -0
  54. comodor-0.1.0/src/comodor/ui/input/__init__.py +15 -0
  55. comodor-0.1.0/src/comodor/ui/input/keys.py +322 -0
  56. comodor-0.1.0/src/comodor/ui/input/reader.py +288 -0
  57. comodor-0.1.0/src/comodor/ui/layout.py +189 -0
  58. comodor-0.1.0/src/comodor/ui/markdown.py +76 -0
  59. comodor-0.1.0/src/comodor/ui/screen.py +185 -0
  60. comodor-0.1.0/src/comodor/ui/theme.py +251 -0
  61. comodor-0.1.0/src/comodor/ui/widgets/__init__.py +21 -0
  62. comodor-0.1.0/src/comodor/ui/widgets/buttons.py +108 -0
  63. comodor-0.1.0/src/comodor/ui/widgets/chat.py +236 -0
  64. comodor-0.1.0/src/comodor/ui/widgets/history.py +131 -0
  65. comodor-0.1.0/src/comodor/ui/widgets/overlay.py +246 -0
  66. comodor-0.1.0/src/comodor/ui/widgets/panel.py +91 -0
  67. comodor-0.1.0/src/comodor/ui/widgets/progress.py +143 -0
  68. comodor-0.1.0/src/comodor/ui/widgets/prompt.py +310 -0
  69. comodor-0.1.0/src/comodor/ui/widgets/statusbar.py +193 -0
  70. comodor-0.1.0/src/comodor/ui/widgets/toast.py +67 -0
  71. comodor-0.1.0/tests/conftest.py +76 -0
  72. comodor-0.1.0/tests/test_agent_loop.py +172 -0
  73. comodor-0.1.0/tests/test_app.py +534 -0
  74. comodor-0.1.0/tests/test_input.py +264 -0
  75. comodor-0.1.0/tests/test_layout.py +210 -0
  76. comodor-0.1.0/tests/test_learning.py +317 -0
  77. comodor-0.1.0/tests/test_performance.py +141 -0
  78. comodor-0.1.0/tests/test_progress.py +187 -0
  79. comodor-0.1.0/tests/test_providers.py +493 -0
  80. comodor-0.1.0/tests/test_reflex.py +366 -0
  81. comodor-0.1.0/tests/test_run_loop.py +155 -0
  82. comodor-0.1.0/tests/test_tools.py +336 -0
@@ -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.
@@ -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.