openreflex 0.3.2__tar.gz → 0.5.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.
- {openreflex-0.3.2/src/openreflex.egg-info → openreflex-0.5.0}/PKG-INFO +38 -25
- {openreflex-0.3.2 → openreflex-0.5.0}/README.md +38 -25
- {openreflex-0.3.2 → openreflex-0.5.0}/pyproject.toml +2 -2
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/__init__.py +1 -1
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/__main__.py +1 -1
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/benchmark.py +1 -3
- openreflex-0.5.0/src/openreflex/claude_ui.py +52 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/cli.py +142 -3
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/decision.py +26 -12
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/engine.py +71 -26
- openreflex-0.5.0/src/openreflex/entrypoint.py +457 -0
- openreflex-0.5.0/src/openreflex/execution_state.py +140 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/hooks.py +38 -5
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/install.py +15 -1
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/learning.py +36 -8
- openreflex-0.5.0/src/openreflex/mcp_contracts.py +158 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/mcp_server.py +126 -103
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/metrics.py +14 -15
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/models.py +37 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/policies/default.toml +101 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/privacy.py +5 -3
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/project.py +2 -2
- openreflex-0.5.0/src/openreflex/project_map.py +362 -0
- openreflex-0.5.0/src/openreflex/project_memory.py +469 -0
- openreflex-0.5.0/src/openreflex/reflex_index.py +304 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/routing.py +23 -4
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/store.py +53 -9
- openreflex-0.5.0/src/openreflex/tui.py +254 -0
- openreflex-0.5.0/src/openreflex/updater.py +193 -0
- openreflex-0.5.0/src/openreflex/usage.py +332 -0
- {openreflex-0.3.2 → openreflex-0.5.0/src/openreflex.egg-info}/PKG-INFO +38 -25
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex.egg-info/SOURCES.txt +24 -1
- openreflex-0.5.0/src/openreflex.egg-info/entry_points.txt +2 -0
- openreflex-0.5.0/tests/test_completion_recap_semantics.py +86 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_engine.py +5 -3
- openreflex-0.5.0/tests/test_execution_state.py +116 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_mcp_metrics_benchmark.py +8 -3
- openreflex-0.5.0/tests/test_outcome_closure.py +106 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_policy_recap.py +3 -4
- openreflex-0.5.0/tests/test_primer_background.py +40 -0
- openreflex-0.5.0/tests/test_project_map.py +134 -0
- openreflex-0.5.0/tests/test_project_memory.py +66 -0
- openreflex-0.5.0/tests/test_project_scope.py +50 -0
- openreflex-0.5.0/tests/test_quality_hardening.py +93 -0
- openreflex-0.5.0/tests/test_reflex_index.py +151 -0
- openreflex-0.5.0/tests/test_release_consistency.py +24 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_routing_control.py +5 -1
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_stress.py +2 -1
- openreflex-0.5.0/tests/test_tui_memory.py +199 -0
- openreflex-0.5.0/tests/test_update_cli.py +156 -0
- openreflex-0.5.0/tests/test_work_modes_tokens.py +218 -0
- openreflex-0.3.2/src/openreflex.egg-info/entry_points.txt +0 -2
- {openreflex-0.3.2 → openreflex-0.5.0}/LICENSE +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/setup.cfg +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/control.py +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/detect.py +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/integrations/opencode.ts +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex/policy.py +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex.egg-info/dependency_links.txt +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex.egg-info/requires.txt +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/src/openreflex.egg-info/top_level.txt +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_hooks.py +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_install_cli.py +0 -0
- {openreflex-0.3.2 → openreflex-0.5.0}/tests/test_reliability_lifecycle.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openreflex
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Muscle memory for AI coding agents: learns from every task, advises the next one, and flags failure loops live
|
|
5
5
|
Author: vishnu-77
|
|
6
6
|
License-Expression: MIT
|
|
@@ -54,16 +54,17 @@ Dynamic: license-file
|
|
|
54
54
|
|
|
55
55
|
## What is OpenReflex
|
|
56
56
|
|
|
57
|
-
OpenReflex gives AI coding agents muscle memory
|
|
58
|
-
lifecycle hooks and MCP, quietly records how each task actually
|
|
59
|
-
|
|
57
|
+
OpenReflex gives AI coding agents muscle memory across coding, investigation, and reasoning work. It plugs into
|
|
58
|
+
Claude Code, Codex, Cursor, and OpenCode through lifecycle hooks and MCP, quietly records how each task actually
|
|
59
|
+
went, and hands the next similar task the useful parts of that experience.
|
|
60
60
|
|
|
61
|
-
You install it once and keep working normally.
|
|
62
|
-
There is no account
|
|
61
|
+
You install it once and keep working normally. Core memory stays on your machine in a local SQLite database.
|
|
62
|
+
There is no OpenReflex account or hosted service. Optional Claude token accounting uses Claude Code's local
|
|
63
|
+
OpenTelemetry export to a loopback-only OpenReflex receiver and stores counts only.
|
|
63
64
|
|
|
64
65
|
<p align="center">
|
|
65
66
|
<a href="docs/walkthrough.md">
|
|
66
|
-
<img alt="Recording of a real Claude Code session with OpenReflex: OpenReflex reports one similar past task and adds 162 context tokens, Claude finds and fixes the coupon bug, runs the tests, records the verified outcome through OpenReflex's MCP tool, and OpenReflex shows the completion recap with the path taken
|
|
67
|
+
<img alt="Recording of a real Claude Code session with OpenReflex: OpenReflex reports one similar past task and adds 162 context tokens, Claude finds and fixes the coupon bug, runs the tests, records the verified outcome through OpenReflex's MCP tool, and OpenReflex shows the completion recap with the path taken and observed cost" src="https://raw.githubusercontent.com/vishnu-77/openreflex/main/docs/screenshots/claude-code-session.gif" width="860">
|
|
67
68
|
</a>
|
|
68
69
|
<br>
|
|
69
70
|
<sub>A real Claude Code session, recorded from the terminal and sped up. OpenReflex had seen one similar task in this repository, so it adds 162 tokens of context before the first tool call; after the fix, Claude records the outcome through OpenReflex's MCP tool. The step-by-step walkthrough is in <a href="docs/walkthrough.md">docs/walkthrough.md</a>.</sub>
|
|
@@ -77,15 +78,16 @@ There is no account, no service, and no telemetry.
|
|
|
77
78
|
- **It catches loops while they happen.** Repeated failing commands, identical retries, stalled progress, and
|
|
78
79
|
runaway context growth raise one alert that says whether to continue, pivot to another approach, or stop and
|
|
79
80
|
check in with you, never a stream of nags.
|
|
80
|
-
- **It learns after every task.**
|
|
81
|
-
|
|
81
|
+
- **It learns after every task.** Build work closes against tests/lint/build evidence; investigations can close
|
|
82
|
+
against cross-checked sources; reasoning-only work can complete without external tools. A simple **Path check**
|
|
83
|
+
only names a better option when comparable past tasks actually support one.
|
|
82
84
|
- **It is private by design.** Only coarse, project-relative metadata is stored. File contents, commands, tool
|
|
83
85
|
output, and transcripts never are, and capture is off until you approve a project.
|
|
84
86
|
|
|
85
87
|
<p align="center">
|
|
86
88
|
<picture>
|
|
87
89
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vishnu-77/openreflex/main/assets/how-it-works-dark.svg">
|
|
88
|
-
<img alt="Before a task: retrieve similar experience, score candidate paths, inject context and a budget. During a task: watch every tool call, flag loops and stalls, advise continue, pivot or stop. After a task:
|
|
90
|
+
<img alt="Before a task: retrieve similar experience, score candidate paths, inject context and a budget. During a task: watch every tool call, flag loops and stalls, advise continue, pivot or stop. After a task: close the outcome using evidence appropriate to the work, run a simple Path check, extract lessons. Lessons feed the Experience Graph for the next task." src="https://raw.githubusercontent.com/vishnu-77/openreflex/main/assets/how-it-works-light.svg" width="860">
|
|
89
91
|
</picture>
|
|
90
92
|
</p>
|
|
91
93
|
|
|
@@ -118,8 +120,14 @@ Then work as usual. After a few tasks:
|
|
|
118
120
|
openreflex context "fix the login redirect bug" # preview the context a task would receive
|
|
119
121
|
openreflex status # what has been captured and learned
|
|
120
122
|
openreflex doctor # installation checks and recent hook errors
|
|
123
|
+
openreflex update --check # check the latest stable release
|
|
121
124
|
```
|
|
122
125
|
|
|
126
|
+
Package updates preserve local memory and project configuration. Managed `pipx` and `uv tool` installs can use
|
|
127
|
+
`openreflex update`, `openreflex update --reinstall`, or `openreflex self reinstall`. To remove only the package,
|
|
128
|
+
use `openreflex self uninstall --yes`; project memory is preserved. A fresh bootstrap still starts with
|
|
129
|
+
`pipx install openreflex` or `uv tool install openreflex` because the `openreflex` command does not exist before installation.
|
|
130
|
+
|
|
123
131
|
## Use it with your agent
|
|
124
132
|
|
|
125
133
|
OpenReflex installs per project with `openreflex install <agent>`, or as a plugin.
|
|
@@ -147,12 +155,11 @@ Execution -failed_with-> ToolCall -resolved_by-> ToolCall
|
|
|
147
155
|
Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
|
|
148
156
|
```
|
|
149
157
|
|
|
150
|
-
- **Before a task:** similar experiences are retrieved and
|
|
151
|
-
`
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
injected; nothing is injected without relevant experience.
|
|
158
|
+
- **Before a task:** similar experiences are retrieved and OpenReflex first identifies the work mode. **BUILD**
|
|
159
|
+
uses `inspect-first`, `test-first`, and `incremental`; **INVESTIGATE** uses `source-first`,
|
|
160
|
+
`cross-check`, and `broad-then-deep`; **THINK** uses `reason-first`, `compare-options`, and
|
|
161
|
+
`evidence-first`. Paths are ranked using past evidence, estimated cost, risk, uncertainty and reversibility.
|
|
162
|
+
A compact context is injected only when relevant experience exists.
|
|
156
163
|
- **During a task:** when a detector finds a failure loop, repeated calls, stalled progress, context growth,
|
|
157
164
|
or work past the budget, OpenReflex estimates the marginal value of more work. The current path's success
|
|
158
165
|
estimate is updated with each call that makes no progress or fails, and compared with the cost of the work
|
|
@@ -160,9 +167,9 @@ Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
|
|
|
160
167
|
to another strategy, or **stop** and ask the user. Each problem, pivot, or stop is raised once, with a cooldown
|
|
161
168
|
between messages.
|
|
162
169
|
- **After a task:** outcome and chosen path come from the agent's `record_outcome` / `choose_path` MCP calls when
|
|
163
|
-
available, and are otherwise inferred from
|
|
164
|
-
|
|
165
|
-
are
|
|
170
|
+
available, and are otherwise inferred from work-mode-appropriate evidence. The **Path check** says either
|
|
171
|
+
`better option: <path>` when comparable completed tasks support it or `better option: none proven`.
|
|
172
|
+
Recommendations are never presented as paths that were actually executed.
|
|
166
173
|
|
|
167
174
|
Every recommendation is stored as a decision snapshot with a **Reflex Score** (0-100): how strong the
|
|
168
175
|
recommendation is, which is separate from the estimated chance that the task succeeds. `openreflex why` explains
|
|
@@ -183,7 +190,7 @@ Agents can also query OpenReflex directly through its MCP server.
|
|
|
183
190
|
| `get_execution_context` | Plan a task: similar past tasks, the suggested strategy with alternatives, a budget, likely files, lessons. Optional `max_tool_calls`, `max_minutes`, `max_context_tokens`. |
|
|
184
191
|
| `check_progress` | Whether more work on the current path is worth it: continue, pivot or stop. |
|
|
185
192
|
| `choose_path` | Declare the strategy being followed when it differs from the suggestion. |
|
|
186
|
-
| `record_outcome` | Record a
|
|
193
|
+
| `record_outcome` | Record a confirmed outcome (tests/builds, cross-checked research, user confirmation, or failure) and learn from it. |
|
|
187
194
|
| `explain_decision` | Why the latest recommendation was made: Reflex Score, signals, confidence, next-best route. |
|
|
188
195
|
| `get_execution_trace` | The decision timeline of the most recent task. |
|
|
189
196
|
| `get_reflex_score` | The latest Reflex Score and its components as JSON. |
|
|
@@ -201,12 +208,16 @@ Agents can also query OpenReflex directly through its MCP server.
|
|
|
201
208
|
|---|---|
|
|
202
209
|
| `install <agent> [--dry-run]` | Write project hooks and MCP config, and enable the project |
|
|
203
210
|
| `uninstall <agent> [--dry-run]` | Remove OpenReflex's project hooks and MCP config; captured memory is kept |
|
|
211
|
+
| `update [--check] [--reinstall]` | Check or update a managed pipx/uv-tool installation; optionally force a reinstall |
|
|
212
|
+
| `self reinstall` | Repair/reinstall the managed OpenReflex package while preserving memory/config |
|
|
213
|
+
| `self uninstall --yes` | Remove only the managed OpenReflex package; memory/config remain on disk |
|
|
204
214
|
| `approve` / `revoke` | Enable or disable capture for the current project |
|
|
205
215
|
| `context "<task>"` | Preview the Execution Context a task would receive |
|
|
206
|
-
| `status [--json]` | What has been captured, reused, and
|
|
216
|
+
| `status [--json]` | What has been captured, reused, learned, and how model-token usage compares |
|
|
207
217
|
| `why` / `trace` | Explain the latest recommendation, or show the decision timeline |
|
|
208
218
|
| `doctor` | Installation, project resolution, and recent hook activity checks |
|
|
209
219
|
| `forget --yes` | Delete the project's data |
|
|
220
|
+
| `tokens enable` / `tokens status` / `tokens disable` | Opt in to local Claude Code token accounting, inspect it, or remove OpenReflex-owned telemetry settings |
|
|
210
221
|
| `benchmark` | Run the simulated benchmark |
|
|
211
222
|
| `hook <agent> <event>` / `mcp` | Used by agent configs |
|
|
212
223
|
|
|
@@ -218,8 +229,9 @@ Agents can also query OpenReflex directly through its MCP server.
|
|
|
218
229
|
| A fingerprint of the arguments | Command text |
|
|
219
230
|
| Project-relative file paths | Tool output |
|
|
220
231
|
| Pass or fail, duration, output size | Transcripts and model output |
|
|
232
|
+
| Optional model-token counts, model/source label, estimated cost | Prompt/response/tool contents from Claude telemetry |
|
|
221
233
|
| A masked one-line error signature | Paths outside the project |
|
|
222
|
-
| The prompt as a task description (up to 1,000 characters, secrets redacted) | Anything sent to
|
|
234
|
+
| The prompt as a task description (up to 1,000 characters, secrets redacted) | Anything sent to an OpenReflex-hosted service: there is none |
|
|
223
235
|
|
|
224
236
|
Data lives in `~/.openreflex/projects/<hash>/experience.sqlite3`. Set `OPENREFLEX_HOME` to move it,
|
|
225
237
|
`OPENREFLEX_DISABLE=1` to turn capture off everywhere, `openreflex forget --yes` to delete a project's data, or ask
|
|
@@ -228,9 +240,10 @@ your agent to `forget_experience` a single task.
|
|
|
228
240
|
## Research
|
|
229
241
|
|
|
230
242
|
OpenReflex is also a research project in budget-aware execution: instead of treating success as a yes or no, it
|
|
231
|
-
studies how agents choose execution paths, spend tool calls and context, respond to uncertainty, and
|
|
232
|
-
|
|
233
|
-
|
|
243
|
+
studies how agents choose execution paths, spend tool calls, model tokens and context, respond to uncertainty, and
|
|
244
|
+
whether past work makes similar future work cheaper without reducing outcome quality. The loop is experience
|
|
245
|
+
retrieval, evidence-aware path selection, budget-aware execution, work-mode-specific completion and plain-language
|
|
246
|
+
path comparison. The [Researcher view](https://openreflex.cc/?view=research) on the site explains the idea,
|
|
234
247
|
lets you step through one reflex forming in the graph, and places it next to related work.
|
|
235
248
|
|
|
236
249
|
## Community & Contributing
|
|
@@ -22,16 +22,17 @@
|
|
|
22
22
|
|
|
23
23
|
## What is OpenReflex
|
|
24
24
|
|
|
25
|
-
OpenReflex gives AI coding agents muscle memory
|
|
26
|
-
lifecycle hooks and MCP, quietly records how each task actually
|
|
27
|
-
|
|
25
|
+
OpenReflex gives AI coding agents muscle memory across coding, investigation, and reasoning work. It plugs into
|
|
26
|
+
Claude Code, Codex, Cursor, and OpenCode through lifecycle hooks and MCP, quietly records how each task actually
|
|
27
|
+
went, and hands the next similar task the useful parts of that experience.
|
|
28
28
|
|
|
29
|
-
You install it once and keep working normally.
|
|
30
|
-
There is no account
|
|
29
|
+
You install it once and keep working normally. Core memory stays on your machine in a local SQLite database.
|
|
30
|
+
There is no OpenReflex account or hosted service. Optional Claude token accounting uses Claude Code's local
|
|
31
|
+
OpenTelemetry export to a loopback-only OpenReflex receiver and stores counts only.
|
|
31
32
|
|
|
32
33
|
<p align="center">
|
|
33
34
|
<a href="docs/walkthrough.md">
|
|
34
|
-
<img alt="Recording of a real Claude Code session with OpenReflex: OpenReflex reports one similar past task and adds 162 context tokens, Claude finds and fixes the coupon bug, runs the tests, records the verified outcome through OpenReflex's MCP tool, and OpenReflex shows the completion recap with the path taken
|
|
35
|
+
<img alt="Recording of a real Claude Code session with OpenReflex: OpenReflex reports one similar past task and adds 162 context tokens, Claude finds and fixes the coupon bug, runs the tests, records the verified outcome through OpenReflex's MCP tool, and OpenReflex shows the completion recap with the path taken and observed cost" src="https://raw.githubusercontent.com/vishnu-77/openreflex/main/docs/screenshots/claude-code-session.gif" width="860">
|
|
35
36
|
</a>
|
|
36
37
|
<br>
|
|
37
38
|
<sub>A real Claude Code session, recorded from the terminal and sped up. OpenReflex had seen one similar task in this repository, so it adds 162 tokens of context before the first tool call; after the fix, Claude records the outcome through OpenReflex's MCP tool. The step-by-step walkthrough is in <a href="docs/walkthrough.md">docs/walkthrough.md</a>.</sub>
|
|
@@ -45,15 +46,16 @@ There is no account, no service, and no telemetry.
|
|
|
45
46
|
- **It catches loops while they happen.** Repeated failing commands, identical retries, stalled progress, and
|
|
46
47
|
runaway context growth raise one alert that says whether to continue, pivot to another approach, or stop and
|
|
47
48
|
check in with you, never a stream of nags.
|
|
48
|
-
- **It learns after every task.**
|
|
49
|
-
|
|
49
|
+
- **It learns after every task.** Build work closes against tests/lint/build evidence; investigations can close
|
|
50
|
+
against cross-checked sources; reasoning-only work can complete without external tools. A simple **Path check**
|
|
51
|
+
only names a better option when comparable past tasks actually support one.
|
|
50
52
|
- **It is private by design.** Only coarse, project-relative metadata is stored. File contents, commands, tool
|
|
51
53
|
output, and transcripts never are, and capture is off until you approve a project.
|
|
52
54
|
|
|
53
55
|
<p align="center">
|
|
54
56
|
<picture>
|
|
55
57
|
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vishnu-77/openreflex/main/assets/how-it-works-dark.svg">
|
|
56
|
-
<img alt="Before a task: retrieve similar experience, score candidate paths, inject context and a budget. During a task: watch every tool call, flag loops and stalls, advise continue, pivot or stop. After a task:
|
|
58
|
+
<img alt="Before a task: retrieve similar experience, score candidate paths, inject context and a budget. During a task: watch every tool call, flag loops and stalls, advise continue, pivot or stop. After a task: close the outcome using evidence appropriate to the work, run a simple Path check, extract lessons. Lessons feed the Experience Graph for the next task." src="https://raw.githubusercontent.com/vishnu-77/openreflex/main/assets/how-it-works-light.svg" width="860">
|
|
57
59
|
</picture>
|
|
58
60
|
</p>
|
|
59
61
|
|
|
@@ -86,8 +88,14 @@ Then work as usual. After a few tasks:
|
|
|
86
88
|
openreflex context "fix the login redirect bug" # preview the context a task would receive
|
|
87
89
|
openreflex status # what has been captured and learned
|
|
88
90
|
openreflex doctor # installation checks and recent hook errors
|
|
91
|
+
openreflex update --check # check the latest stable release
|
|
89
92
|
```
|
|
90
93
|
|
|
94
|
+
Package updates preserve local memory and project configuration. Managed `pipx` and `uv tool` installs can use
|
|
95
|
+
`openreflex update`, `openreflex update --reinstall`, or `openreflex self reinstall`. To remove only the package,
|
|
96
|
+
use `openreflex self uninstall --yes`; project memory is preserved. A fresh bootstrap still starts with
|
|
97
|
+
`pipx install openreflex` or `uv tool install openreflex` because the `openreflex` command does not exist before installation.
|
|
98
|
+
|
|
91
99
|
## Use it with your agent
|
|
92
100
|
|
|
93
101
|
OpenReflex installs per project with `openreflex install <agent>`, or as a plugin.
|
|
@@ -115,12 +123,11 @@ Execution -failed_with-> ToolCall -resolved_by-> ToolCall
|
|
|
115
123
|
Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
|
|
116
124
|
```
|
|
117
125
|
|
|
118
|
-
- **Before a task:** similar experiences are retrieved and
|
|
119
|
-
`
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
injected; nothing is injected without relevant experience.
|
|
126
|
+
- **Before a task:** similar experiences are retrieved and OpenReflex first identifies the work mode. **BUILD**
|
|
127
|
+
uses `inspect-first`, `test-first`, and `incremental`; **INVESTIGATE** uses `source-first`,
|
|
128
|
+
`cross-check`, and `broad-then-deep`; **THINK** uses `reason-first`, `compare-options`, and
|
|
129
|
+
`evidence-first`. Paths are ranked using past evidence, estimated cost, risk, uncertainty and reversibility.
|
|
130
|
+
A compact context is injected only when relevant experience exists.
|
|
124
131
|
- **During a task:** when a detector finds a failure loop, repeated calls, stalled progress, context growth,
|
|
125
132
|
or work past the budget, OpenReflex estimates the marginal value of more work. The current path's success
|
|
126
133
|
estimate is updated with each call that makes no progress or fails, and compared with the cost of the work
|
|
@@ -128,9 +135,9 @@ Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
|
|
|
128
135
|
to another strategy, or **stop** and ask the user. Each problem, pivot, or stop is raised once, with a cooldown
|
|
129
136
|
between messages.
|
|
130
137
|
- **After a task:** outcome and chosen path come from the agent's `record_outcome` / `choose_path` MCP calls when
|
|
131
|
-
available, and are otherwise inferred from
|
|
132
|
-
|
|
133
|
-
are
|
|
138
|
+
available, and are otherwise inferred from work-mode-appropriate evidence. The **Path check** says either
|
|
139
|
+
`better option: <path>` when comparable completed tasks support it or `better option: none proven`.
|
|
140
|
+
Recommendations are never presented as paths that were actually executed.
|
|
134
141
|
|
|
135
142
|
Every recommendation is stored as a decision snapshot with a **Reflex Score** (0-100): how strong the
|
|
136
143
|
recommendation is, which is separate from the estimated chance that the task succeeds. `openreflex why` explains
|
|
@@ -151,7 +158,7 @@ Agents can also query OpenReflex directly through its MCP server.
|
|
|
151
158
|
| `get_execution_context` | Plan a task: similar past tasks, the suggested strategy with alternatives, a budget, likely files, lessons. Optional `max_tool_calls`, `max_minutes`, `max_context_tokens`. |
|
|
152
159
|
| `check_progress` | Whether more work on the current path is worth it: continue, pivot or stop. |
|
|
153
160
|
| `choose_path` | Declare the strategy being followed when it differs from the suggestion. |
|
|
154
|
-
| `record_outcome` | Record a
|
|
161
|
+
| `record_outcome` | Record a confirmed outcome (tests/builds, cross-checked research, user confirmation, or failure) and learn from it. |
|
|
155
162
|
| `explain_decision` | Why the latest recommendation was made: Reflex Score, signals, confidence, next-best route. |
|
|
156
163
|
| `get_execution_trace` | The decision timeline of the most recent task. |
|
|
157
164
|
| `get_reflex_score` | The latest Reflex Score and its components as JSON. |
|
|
@@ -169,12 +176,16 @@ Agents can also query OpenReflex directly through its MCP server.
|
|
|
169
176
|
|---|---|
|
|
170
177
|
| `install <agent> [--dry-run]` | Write project hooks and MCP config, and enable the project |
|
|
171
178
|
| `uninstall <agent> [--dry-run]` | Remove OpenReflex's project hooks and MCP config; captured memory is kept |
|
|
179
|
+
| `update [--check] [--reinstall]` | Check or update a managed pipx/uv-tool installation; optionally force a reinstall |
|
|
180
|
+
| `self reinstall` | Repair/reinstall the managed OpenReflex package while preserving memory/config |
|
|
181
|
+
| `self uninstall --yes` | Remove only the managed OpenReflex package; memory/config remain on disk |
|
|
172
182
|
| `approve` / `revoke` | Enable or disable capture for the current project |
|
|
173
183
|
| `context "<task>"` | Preview the Execution Context a task would receive |
|
|
174
|
-
| `status [--json]` | What has been captured, reused, and
|
|
184
|
+
| `status [--json]` | What has been captured, reused, learned, and how model-token usage compares |
|
|
175
185
|
| `why` / `trace` | Explain the latest recommendation, or show the decision timeline |
|
|
176
186
|
| `doctor` | Installation, project resolution, and recent hook activity checks |
|
|
177
187
|
| `forget --yes` | Delete the project's data |
|
|
188
|
+
| `tokens enable` / `tokens status` / `tokens disable` | Opt in to local Claude Code token accounting, inspect it, or remove OpenReflex-owned telemetry settings |
|
|
178
189
|
| `benchmark` | Run the simulated benchmark |
|
|
179
190
|
| `hook <agent> <event>` / `mcp` | Used by agent configs |
|
|
180
191
|
|
|
@@ -186,8 +197,9 @@ Agents can also query OpenReflex directly through its MCP server.
|
|
|
186
197
|
| A fingerprint of the arguments | Command text |
|
|
187
198
|
| Project-relative file paths | Tool output |
|
|
188
199
|
| Pass or fail, duration, output size | Transcripts and model output |
|
|
200
|
+
| Optional model-token counts, model/source label, estimated cost | Prompt/response/tool contents from Claude telemetry |
|
|
189
201
|
| A masked one-line error signature | Paths outside the project |
|
|
190
|
-
| The prompt as a task description (up to 1,000 characters, secrets redacted) | Anything sent to
|
|
202
|
+
| The prompt as a task description (up to 1,000 characters, secrets redacted) | Anything sent to an OpenReflex-hosted service: there is none |
|
|
191
203
|
|
|
192
204
|
Data lives in `~/.openreflex/projects/<hash>/experience.sqlite3`. Set `OPENREFLEX_HOME` to move it,
|
|
193
205
|
`OPENREFLEX_DISABLE=1` to turn capture off everywhere, `openreflex forget --yes` to delete a project's data, or ask
|
|
@@ -196,9 +208,10 @@ your agent to `forget_experience` a single task.
|
|
|
196
208
|
## Research
|
|
197
209
|
|
|
198
210
|
OpenReflex is also a research project in budget-aware execution: instead of treating success as a yes or no, it
|
|
199
|
-
studies how agents choose execution paths, spend tool calls and context, respond to uncertainty, and
|
|
200
|
-
|
|
201
|
-
|
|
211
|
+
studies how agents choose execution paths, spend tool calls, model tokens and context, respond to uncertainty, and
|
|
212
|
+
whether past work makes similar future work cheaper without reducing outcome quality. The loop is experience
|
|
213
|
+
retrieval, evidence-aware path selection, budget-aware execution, work-mode-specific completion and plain-language
|
|
214
|
+
path comparison. The [Researcher view](https://openreflex.cc/?view=research) on the site explains the idea,
|
|
202
215
|
lets you step through one reflex forming in the graph, and places it next to related work.
|
|
203
216
|
|
|
204
217
|
## Community & Contributing
|
|
@@ -225,4 +238,4 @@ OpenReflex is listed in the [MCP Registry](https://registry.modelcontextprotocol
|
|
|
225
238
|
|
|
226
239
|
## License
|
|
227
240
|
|
|
228
|
-
OpenReflex is released under the [MIT License](https://github.com/vishnu-77/openreflex/blob/main/LICENSE).
|
|
241
|
+
OpenReflex is released under the [MIT License](https://github.com/vishnu-77/openreflex/blob/main/LICENSE).
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "openreflex"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "Muscle memory for AI coding agents: learns from every task, advises the next one, and flags failure loops live"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -35,7 +35,7 @@ Issues = "https://github.com/vishnu-77/openreflex/issues"
|
|
|
35
35
|
dev = ["pytest>=8,<9", "ruff>=0.12", "build>=1.2", "twine>=6"]
|
|
36
36
|
|
|
37
37
|
[project.scripts]
|
|
38
|
-
openreflex = "openreflex.
|
|
38
|
+
openreflex = "openreflex.entrypoint:main"
|
|
39
39
|
|
|
40
40
|
[tool.setuptools.packages.find]
|
|
41
41
|
where = ["src"]
|
|
@@ -206,11 +206,9 @@ def format_report(report: dict) -> str:
|
|
|
206
206
|
b, g, c = report["baseline"], report["guided"], report["relative_change"]
|
|
207
207
|
rows = [
|
|
208
208
|
("tool calls / task", b["tool_calls"], g["tool_calls"], f"{c['tool_calls']:+.0%}"),
|
|
209
|
-
("output tokens / task", b["tokens"], g["tokens"], f"{c['tokens']:+.0%}"),
|
|
209
|
+
("sim. tool-output tokens / task", b["tokens"], g["tokens"], f"{c['tokens']:+.0%}"),
|
|
210
210
|
("time / task (s)", b["seconds"], g["seconds"], f"{c['time']:+.0%}"),
|
|
211
211
|
("success rate", b["success_rate"], g["success_rate"], f"{c['success_rate_points']:+.3f} pts"),
|
|
212
|
-
("regret, first quarter", b["regret_first_quarter"], g["regret_first_quarter"], ""),
|
|
213
|
-
("regret, last quarter", b["regret_last_quarter"], g["regret_last_quarter"], ""),
|
|
214
212
|
("routing agreement (2nd half)", "-", g["routing_agreement_second_half"], ""),
|
|
215
213
|
]
|
|
216
214
|
lines = [f"SIMULATED benchmark - {report['episodes_per_arm']} tasks/arm x {report['seeds']} seeds "
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Claude Code presentation integration.
|
|
2
|
+
|
|
3
|
+
OpenReflex only installs its status line when the project has no existing custom
|
|
4
|
+
statusLine. A user-owned status line is never replaced.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
STATUSLINE_COMMAND = "openreflex statusline"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _load(path: Path) -> dict:
|
|
17
|
+
try:
|
|
18
|
+
value = json.loads(path.read_text(encoding="utf-8"))
|
|
19
|
+
return value if isinstance(value, dict) else {}
|
|
20
|
+
except (OSError, ValueError):
|
|
21
|
+
return {}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _write(path: Path, data: dict) -> None:
|
|
25
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
temp = path.with_suffix(path.suffix + ".tmp")
|
|
27
|
+
temp.write_text(json.dumps(data, indent=2) + "\n", encoding="utf-8")
|
|
28
|
+
os.replace(temp, path)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def configure_statusline(project: Path) -> str:
|
|
32
|
+
path = project / ".claude" / "settings.json"
|
|
33
|
+
data = _load(path)
|
|
34
|
+
existing = data.get("statusLine")
|
|
35
|
+
if isinstance(existing, dict):
|
|
36
|
+
if existing.get("command") == STATUSLINE_COMMAND:
|
|
37
|
+
return "already-configured"
|
|
38
|
+
return "preserved-existing"
|
|
39
|
+
data["statusLine"] = {"type": "command", "command": STATUSLINE_COMMAND, "padding": 0, "refreshInterval": 2}
|
|
40
|
+
_write(path, data)
|
|
41
|
+
return "configured"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def remove_statusline(project: Path) -> bool:
|
|
45
|
+
path = project / ".claude" / "settings.json"
|
|
46
|
+
data = _load(path)
|
|
47
|
+
current = data.get("statusLine")
|
|
48
|
+
if not isinstance(current, dict) or current.get("command") != STATUSLINE_COMMAND:
|
|
49
|
+
return False
|
|
50
|
+
data.pop("statusLine", None)
|
|
51
|
+
_write(path, data)
|
|
52
|
+
return True
|
|
@@ -117,7 +117,7 @@ def cmd_status(args) -> int:
|
|
|
117
117
|
if args.json:
|
|
118
118
|
print(json.dumps(data, indent=2))
|
|
119
119
|
return 0
|
|
120
|
-
reuse,
|
|
120
|
+
reuse, path_check, routing = data["experience_reuse"], data["path_check"], data["routing"]
|
|
121
121
|
eff = data["efficiency_observational"]
|
|
122
122
|
print(f"OpenReflex {__version__} - {project}")
|
|
123
123
|
print(f" enabled: {data['enabled']} agents: {', '.join(data['engagement']['agents']) or '-'}")
|
|
@@ -128,7 +128,10 @@ def cmd_status(args) -> int:
|
|
|
128
128
|
print(f" success rate (known outcomes): {data['outcomes']['success_rate']} verified: {data['outcomes']['verified']}")
|
|
129
129
|
print(f" tool calls with vs without prior experience: {eff['with_prior_experience']['tool_calls']} vs "
|
|
130
130
|
f"{eff['without_prior_experience']['tool_calls']} (observational)")
|
|
131
|
-
print(f"
|
|
131
|
+
print(f" model tokens with vs without prior experience: {eff['with_prior_experience']['model_tokens']} vs "
|
|
132
|
+
f"{eff['without_prior_experience']['model_tokens']} (observational)")
|
|
133
|
+
print(f" path checks: {path_check['comparisons']} better option found: {path_check['better_option_found']} "
|
|
134
|
+
f"routing agreement: {routing['agreement']}")
|
|
132
135
|
print(f" live alerts: {data['live_alerts'] or '-'}")
|
|
133
136
|
control = data["execution_control"]
|
|
134
137
|
print(f" verdicts: {control['verdicts'] or '-'} tasks within tool-call budget: {control['tasks_within_tool_call_budget']}")
|
|
@@ -168,6 +171,128 @@ def cmd_trace(args) -> int:
|
|
|
168
171
|
return 0
|
|
169
172
|
|
|
170
173
|
|
|
174
|
+
def cmd_update(args) -> int:
|
|
175
|
+
from .updater import (
|
|
176
|
+
check_for_update,
|
|
177
|
+
detect_install_plan,
|
|
178
|
+
installed_version_after_update,
|
|
179
|
+
run_reinstall,
|
|
180
|
+
run_update,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
print("OPENREFLEX / UPDATE")
|
|
184
|
+
try:
|
|
185
|
+
status = check_for_update(__version__)
|
|
186
|
+
except RuntimeError as exc:
|
|
187
|
+
print(f" current {__version__}")
|
|
188
|
+
print(f" check failed ({exc})")
|
|
189
|
+
print("\nNo changes were made.")
|
|
190
|
+
return 1
|
|
191
|
+
|
|
192
|
+
plan = detect_install_plan()
|
|
193
|
+
print(f" current {status.current}")
|
|
194
|
+
print(f" latest {status.latest}")
|
|
195
|
+
print(f" install {plan.method}")
|
|
196
|
+
|
|
197
|
+
if args.check:
|
|
198
|
+
if status.update_available:
|
|
199
|
+
print("\n update available")
|
|
200
|
+
print("Run `openreflex update` to install it.")
|
|
201
|
+
elif status.current == status.latest:
|
|
202
|
+
print("\n [ok] already up to date")
|
|
203
|
+
else:
|
|
204
|
+
print("\n [ok] current build is newer than the latest PyPI release")
|
|
205
|
+
return 0
|
|
206
|
+
|
|
207
|
+
if args.reinstall:
|
|
208
|
+
if plan.reinstall_command is None:
|
|
209
|
+
print(f"\n [--] automatic reinstall unavailable: {plan.detail}")
|
|
210
|
+
print("No changes were made.")
|
|
211
|
+
return 2
|
|
212
|
+
print(f" method {' '.join(plan.reinstall_command)}")
|
|
213
|
+
print("\nReinstalling OpenReflex...")
|
|
214
|
+
returncode = run_reinstall(plan)
|
|
215
|
+
else:
|
|
216
|
+
if not status.update_available:
|
|
217
|
+
if status.current == status.latest:
|
|
218
|
+
print("\n [ok] already up to date")
|
|
219
|
+
else:
|
|
220
|
+
print("\n [ok] current build is newer than the latest PyPI release")
|
|
221
|
+
return 0
|
|
222
|
+
if plan.command is None:
|
|
223
|
+
print(f"\n [--] automatic update unavailable: {plan.detail}")
|
|
224
|
+
print("No changes were made.")
|
|
225
|
+
return 2
|
|
226
|
+
print(f" method {' '.join(plan.command)}")
|
|
227
|
+
print("\nUpdating OpenReflex...")
|
|
228
|
+
returncode = run_update(plan)
|
|
229
|
+
|
|
230
|
+
if returncode != 0:
|
|
231
|
+
action = "reinstall" if args.reinstall else "update"
|
|
232
|
+
print(f"\n [--] {action} failed with exit code {returncode}")
|
|
233
|
+
print("Your project memory and agent configuration were not modified by OpenReflex.")
|
|
234
|
+
return returncode or 1
|
|
235
|
+
|
|
236
|
+
installed = installed_version_after_update()
|
|
237
|
+
action = "reinstalled" if args.reinstall else "updated"
|
|
238
|
+
print(f"\n [ok] {action} {installed or status.latest}")
|
|
239
|
+
if not args.reinstall and installed and installed != status.latest:
|
|
240
|
+
print(f" note expected {status.latest}; executable reports {installed}")
|
|
241
|
+
print(" memory preserved")
|
|
242
|
+
print(" config preserved")
|
|
243
|
+
print("\nRestart active Claude Code, Codex, Cursor, or OpenCode sessions to reload hooks and MCP.")
|
|
244
|
+
return 0
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def cmd_self(args) -> int:
|
|
248
|
+
from .updater import detect_install_plan, run_reinstall, run_uninstall
|
|
249
|
+
|
|
250
|
+
plan = detect_install_plan()
|
|
251
|
+
print("OPENREFLEX / SELF")
|
|
252
|
+
print(f" action {args.self_action}")
|
|
253
|
+
print(f" install {plan.method}")
|
|
254
|
+
|
|
255
|
+
if args.self_action == "reinstall":
|
|
256
|
+
if plan.reinstall_command is None:
|
|
257
|
+
print(f"\n [--] automatic reinstall unavailable: {plan.detail}")
|
|
258
|
+
print("No changes were made.")
|
|
259
|
+
return 2
|
|
260
|
+
print(f" method {' '.join(plan.reinstall_command)}")
|
|
261
|
+
print("\nReinstalling OpenReflex...")
|
|
262
|
+
returncode = run_reinstall(plan)
|
|
263
|
+
if returncode != 0:
|
|
264
|
+
print(f"\n [--] reinstall failed with exit code {returncode}")
|
|
265
|
+
return returncode or 1
|
|
266
|
+
print("\n [ok] package reinstalled")
|
|
267
|
+
print(" memory preserved")
|
|
268
|
+
print(" config preserved")
|
|
269
|
+
print("\nRestart active agent sessions to reload hooks and MCP.")
|
|
270
|
+
return 0
|
|
271
|
+
|
|
272
|
+
if args.self_action == "uninstall":
|
|
273
|
+
if not args.yes:
|
|
274
|
+
print("\nThis removes the OpenReflex executable/package but preserves ~/.openreflex memory and project configuration.")
|
|
275
|
+
print("Re-run with `openreflex self uninstall --yes` to confirm.")
|
|
276
|
+
return 1
|
|
277
|
+
if plan.uninstall_command is None:
|
|
278
|
+
print(f"\n [--] automatic uninstall unavailable: {plan.detail}")
|
|
279
|
+
print("No changes were made.")
|
|
280
|
+
return 2
|
|
281
|
+
print(f" method {' '.join(plan.uninstall_command)}")
|
|
282
|
+
print("\nUninstalling OpenReflex package...")
|
|
283
|
+
returncode = run_uninstall(plan)
|
|
284
|
+
if returncode != 0:
|
|
285
|
+
print(f"\n [--] uninstall failed with exit code {returncode}")
|
|
286
|
+
return returncode or 1
|
|
287
|
+
print("\n [ok] package uninstalled")
|
|
288
|
+
print(" memory preserved")
|
|
289
|
+
print(" config preserved")
|
|
290
|
+
print("\nProject hooks/config remain on disk but cannot run until OpenReflex is installed again.")
|
|
291
|
+
return 0
|
|
292
|
+
|
|
293
|
+
return 2
|
|
294
|
+
|
|
295
|
+
|
|
171
296
|
def _json(path: Path) -> dict:
|
|
172
297
|
try:
|
|
173
298
|
value = json.loads(path.read_text(encoding="utf-8"))
|
|
@@ -300,7 +425,21 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
300
425
|
command.add_argument("--dry-run", action="store_true")
|
|
301
426
|
command.set_defaults(func=func)
|
|
302
427
|
|
|
303
|
-
|
|
428
|
+
update = sub.add_parser("update", help="Check PyPI and safely update the managed OpenReflex installation")
|
|
429
|
+
update_group = update.add_mutually_exclusive_group()
|
|
430
|
+
update_group.add_argument("--check", action="store_true", help="Only report whether an update is available")
|
|
431
|
+
update_group.add_argument("--reinstall", action="store_true", help="Reinstall the stable package even if already current")
|
|
432
|
+
update.set_defaults(func=cmd_update)
|
|
433
|
+
|
|
434
|
+
self_cmd = sub.add_parser("self", help="Manage the installed OpenReflex package without deleting memory")
|
|
435
|
+
self_sub = self_cmd.add_subparsers(dest="self_action", required=True)
|
|
436
|
+
self_reinstall = self_sub.add_parser("reinstall", help="Reinstall the managed OpenReflex package")
|
|
437
|
+
self_reinstall.set_defaults(func=cmd_self)
|
|
438
|
+
self_uninstall = self_sub.add_parser("uninstall", help="Remove the OpenReflex package but preserve memory/config")
|
|
439
|
+
self_uninstall.add_argument("--yes", action="store_true", help="Confirm package removal")
|
|
440
|
+
self_uninstall.set_defaults(func=cmd_self)
|
|
441
|
+
|
|
442
|
+
status = sub.add_parser("status", help="Show capture, reuse, token efficiency, path checks, and routing metrics")
|
|
304
443
|
status.add_argument("--project")
|
|
305
444
|
status.add_argument("--json", action="store_true")
|
|
306
445
|
status.set_defaults(func=cmd_status)
|