openreflex 0.5.2__tar.gz → 0.7.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 (68) hide show
  1. {openreflex-0.5.2/src/openreflex.egg-info → openreflex-0.7.0}/PKG-INFO +31 -23
  2. {openreflex-0.5.2 → openreflex-0.7.0}/README.md +29 -21
  3. {openreflex-0.5.2 → openreflex-0.7.0}/pyproject.toml +2 -2
  4. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/__init__.py +1 -1
  5. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/cli.py +55 -5
  6. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/decision.py +42 -10
  7. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/engine.py +63 -25
  8. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/entrypoint.py +46 -1
  9. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/hooks.py +2 -2
  10. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/install.py +55 -15
  11. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/mcp_contracts.py +7 -0
  12. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/mcp_server.py +81 -28
  13. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/metrics.py +40 -1
  14. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/models.py +25 -0
  15. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/policies/default.toml +1 -0
  16. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/reflex_index.py +40 -9
  17. openreflex-0.7.0/src/openreflex/reflexes.py +326 -0
  18. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/store.py +64 -2
  19. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/tui.py +4 -4
  20. {openreflex-0.5.2 → openreflex-0.7.0/src/openreflex.egg-info}/PKG-INFO +31 -23
  21. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex.egg-info/SOURCES.txt +3 -0
  22. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_completion_recap_semantics.py +6 -5
  23. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_engine.py +31 -2
  24. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_install_cli.py +58 -11
  25. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_mcp_metrics_benchmark.py +18 -5
  26. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_outcome_closure.py +2 -1
  27. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_policy_recap.py +3 -2
  28. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_project_map.py +0 -1
  29. openreflex-0.7.0/tests/test_project_reflexes.py +351 -0
  30. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_reflex_index.py +29 -1
  31. openreflex-0.7.0/tests/test_release_pipeline.py +49 -0
  32. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_routing_control.py +9 -4
  33. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_tui_memory.py +26 -2
  34. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_work_modes_tokens.py +1 -1
  35. {openreflex-0.5.2 → openreflex-0.7.0}/LICENSE +0 -0
  36. {openreflex-0.5.2 → openreflex-0.7.0}/setup.cfg +0 -0
  37. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/__main__.py +0 -0
  38. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/benchmark.py +0 -0
  39. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/claude_ui.py +0 -0
  40. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/control.py +0 -0
  41. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/detect.py +0 -0
  42. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/execution_state.py +0 -0
  43. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/integrations/opencode.ts +0 -0
  44. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/learning.py +0 -0
  45. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/policy.py +0 -0
  46. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/privacy.py +0 -0
  47. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/project.py +0 -0
  48. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/project_map.py +0 -0
  49. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/project_memory.py +0 -0
  50. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/routing.py +0 -0
  51. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/updater.py +0 -0
  52. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex/usage.py +0 -0
  53. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex.egg-info/dependency_links.txt +0 -0
  54. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex.egg-info/entry_points.txt +0 -0
  55. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex.egg-info/requires.txt +0 -0
  56. {openreflex-0.5.2 → openreflex-0.7.0}/src/openreflex.egg-info/top_level.txt +0 -0
  57. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_execution_state.py +0 -0
  58. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_hooks.py +0 -0
  59. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_primer_background.py +0 -0
  60. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_project_memory.py +0 -0
  61. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_project_scope.py +0 -0
  62. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_quality_hardening.py +0 -0
  63. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_release_consistency.py +0 -0
  64. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_reliability_lifecycle.py +0 -0
  65. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_stress.py +0 -0
  66. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_token_receiver.py +0 -0
  67. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_tokens_cli.py +0 -0
  68. {openreflex-0.5.2 → openreflex-0.7.0}/tests/test_update_cli.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openreflex
3
- Version: 0.5.2
4
- Summary: Muscle memory for AI coding agents: learns from every task, advises the next one, and flags failure loops live
3
+ Version: 0.7.0
4
+ Summary: Ambient project muscle memory for AI coding agents: learns and reuses project Reflexes automatically
5
5
  Author: vishnu-77
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://openreflex.cc
@@ -54,9 +54,10 @@ Dynamic: license-file
54
54
 
55
55
  ## What is OpenReflex
56
56
 
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.
57
+ OpenReflex gives AI coding agents ambient project muscle memory across coding, investigation, and reasoning work.
58
+ Lifecycle hooks quietly record how work actually goes, compile repeated project behaviour into reusable Reflexes,
59
+ and inject only the relevant project procedure into new tasks. The model does not need to remember to call OpenReflex,
60
+ and MCP diagnostics are opt-in rather than loaded into normal agent context.
60
61
 
61
62
  You install it once and keep working normally. Core memory stays on your machine in a local SQLite database.
62
63
  There is no OpenReflex account or hosted service. Optional Claude token accounting uses Claude Code's local
@@ -64,17 +65,18 @@ OpenTelemetry export to a loopback-only OpenReflex receiver and stores counts on
64
65
 
65
66
  <p align="center">
66
67
  <a href="docs/walkthrough.md">
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">
68
+ <img alt="Recording of a Claude Code session with OpenReflex: OpenReflex injects compact prior context, Claude fixes the task and runs verification, and lifecycle hooks close the outcome automatically" src="https://raw.githubusercontent.com/vishnu-77/openreflex/main/docs/screenshots/claude-code-session.gif" width="860">
68
69
  </a>
69
70
  <br>
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>
71
+ <sub>A recorded Claude Code session. OpenReflex injects compact relevant context before work; lifecycle hooks capture tools and verification and close the execution automatically. MCP is not required for the normal path. The step-by-step walkthrough is in <a href="docs/walkthrough.md">docs/walkthrough.md</a>.</sub>
71
72
  </p>
72
73
 
73
74
  ## Why OpenReflex
74
75
 
75
- - **It remembers what worked.** Before a substantial task, OpenReflex retrieves similar past tasks and injects a
76
- compact Execution Context: a suggested approach with alternatives, the files that were changed, and lessons
77
- such as which edit resolved a recurring error.
76
+ - **It learns how the project behaves.** OpenReflex compiles successful work into project-scoped Reflexes such as
77
+ authentication changes, Helm configuration, database migrations or CI work. Resolution combines semantic intent,
78
+ task family and module/file locality, so a novel task can reuse a project procedure without repeating an
79
+ earlier task.
78
80
  - **It catches loops while they happen.** Repeated failing commands, identical retries, stalled progress, and
79
81
  runaway context growth raise one alert that says whether to continue, pivot to another approach, or stop and
80
82
  check in with you, never a stream of nags.
@@ -98,7 +100,7 @@ Requires Python 3.11 or newer.
98
100
  ```bash
99
101
  pipx install openreflex # or: uv tool install openreflex
100
102
  cd your-project
101
- openreflex install claude-code # writes hooks + MCP config and enables this project
103
+ openreflex install claude-code # hooks-only ambient runtime; enables this project
102
104
  ```
103
105
 
104
106
  ```
@@ -106,8 +108,8 @@ OPENREFLEX / CONNECT
106
108
  agent claude-code
107
109
  project D:\demo\shop
108
110
  config updated 2 files
111
+ D:\demo\shop\.openreflex.json
109
112
  D:\demo\shop\.claude\settings.json
110
- D:\demo\shop\.mcp.json
111
113
  memory enabled
112
114
  storage local
113
115
 
@@ -134,10 +136,10 @@ OpenReflex installs per project with `openreflex install <agent>`, or as a plugi
134
136
 
135
137
  | Agent | Connects through | Install | Verified |
136
138
  |---|---|---|---|
137
- | **Claude Code** | Plugin, or hooks + MCP | `claude plugin marketplace add vishnu-77/openreflex` then `claude plugin install openreflex@openreflex`, or `openreflex install claude-code` | Live sessions |
138
- | **Codex** | Plugin, or hooks + MCP | `codex plugin marketplace add vishnu-77/openreflex`, or `openreflex install codex`, then trust the hooks once in `/hooks` | Live sessions |
139
- | **Cursor** | Hooks + MCP | `openreflex install cursor` | Protocol and fuzz tests |
140
- | **OpenCode** | Plugin + MCP | `openreflex install opencode` | Protocol and fuzz tests |
139
+ | **Claude Code** | Plugin hooks, or project hooks | `claude plugin marketplace add vishnu-77/openreflex` then `claude plugin install openreflex@openreflex`, or `openreflex install claude-code` | Live sessions |
140
+ | **Codex** | Plugin hooks, or project hooks | `codex plugin marketplace add vishnu-77/openreflex`, or `openreflex install codex`, then trust the hooks once in `/hooks` | Live sessions |
141
+ | **Cursor** | Lifecycle hooks | `openreflex install cursor` | Protocol and fuzz tests |
142
+ | **OpenCode** | Local lifecycle plugin | `openreflex install opencode` | Protocol and fuzz tests |
141
143
 
142
144
  With a plugin install, enable each project with `openreflex approve`. Per-agent guides:
143
145
  [Claude Code](https://openreflex.cc/claude-code), [Codex](https://openreflex.cc/codex), [Cursor](https://openreflex.cc/cursor),
@@ -166,8 +168,9 @@ Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
166
168
  left and with the best untried alternative. The alert ends with a recommendation to **continue**, **pivot**
167
169
  to another strategy, or **stop** and ask the user. Each problem, pivot, or stop is raised once, with a cooldown
168
170
  between messages.
169
- - **After a task:** outcome and chosen path come from the agent's `record_outcome` / `choose_path` MCP calls when
170
- available, and are otherwise inferred from work-mode-appropriate evidence. The **Path check** says either
171
+ - **After a task:** lifecycle hooks close the execution automatically from work-mode-appropriate evidence; the model
172
+ does not need to call OpenReflex. Explicit MCP outcome/path operations remain available only for manual or diagnostic
173
+ workflows. The **Path check** says either
171
174
  `better option: <path>` when comparable completed tasks support it or `better option: none proven`.
172
175
  Recommendations are never presented as paths that were actually executed.
173
176
 
@@ -180,10 +183,13 @@ Set optional limits for every task with `OPENREFLEX_BUDGET`, for example `calls=
180
183
  Routing, scoring, budget and recap settings come from a versioned policy: the packaged defaults, overridden by
181
184
  `~/.openreflex/config.toml` and then by `.openreflex.toml` in the project.
182
185
 
183
- Agents can also query OpenReflex directly through its MCP server.
186
+ Normal work does **not** load OpenReflex MCP tools. If you explicitly want model-facing introspection for a project,
187
+ enable it with `openreflex diagnostics enable <agent>`. Disable it again with
188
+ `openreflex diagnostics disable <agent>`. The standalone MCP Registry package remains available for users who
189
+ deliberately install OpenReflex as an MCP server.
184
190
 
185
191
  <details>
186
- <summary><strong>The 12 MCP tools</strong></summary>
192
+ <summary><strong>The optional MCP diagnostics/admin tools</strong></summary>
187
193
 
188
194
  | Tool | What it does |
189
195
  |---|---|
@@ -206,8 +212,9 @@ Agents can also query OpenReflex directly through its MCP server.
206
212
 
207
213
  | Command | Purpose |
208
214
  |---|---|
209
- | `install <agent> [--dry-run]` | Write project hooks and MCP config, and enable the project |
210
- | `uninstall <agent> [--dry-run]` | Remove OpenReflex's project hooks and MCP config; captured memory is kept |
215
+ | `install <agent> [--dry-run]` | Install the hooks-only ambient runtime and enable the project |
216
+ | `diagnostics enable/disable <agent>` | Explicitly opt in/out of model-facing MCP diagnostics |
217
+ | `uninstall <agent> [--dry-run]` | Remove OpenReflex's integration entries; captured memory is kept |
211
218
  | `update [--check] [--reinstall]` | Check or update a managed pipx/uv-tool installation; optionally force a reinstall |
212
219
  | `self reinstall` | Repair/reinstall the managed OpenReflex package while preserving memory/config |
213
220
  | `self uninstall --yes` | Remove only the managed OpenReflex package; memory/config remain on disk |
@@ -219,7 +226,8 @@ Agents can also query OpenReflex directly through its MCP server.
219
226
  | `forget --yes` | Delete the project's data |
220
227
  | `tokens enable` / `tokens status` / `tokens disable` | Opt in to local Claude Code token accounting, inspect it, or remove OpenReflex-owned telemetry settings |
221
228
  | `benchmark` | Run the simulated benchmark |
222
- | `hook <agent> <event>` / `mcp` | Used by agent configs |
229
+ | `hook <agent> <event>` | Used by ambient agent integrations |
230
+ | `mcp` | Run the optional diagnostics/admin MCP server explicitly |
223
231
 
224
232
  ## Privacy
225
233
 
@@ -22,9 +22,10 @@
22
22
 
23
23
  ## What is OpenReflex
24
24
 
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.
25
+ OpenReflex gives AI coding agents ambient project muscle memory across coding, investigation, and reasoning work.
26
+ Lifecycle hooks quietly record how work actually goes, compile repeated project behaviour into reusable Reflexes,
27
+ and inject only the relevant project procedure into new tasks. The model does not need to remember to call OpenReflex,
28
+ and MCP diagnostics are opt-in rather than loaded into normal agent context.
28
29
 
29
30
  You install it once and keep working normally. Core memory stays on your machine in a local SQLite database.
30
31
  There is no OpenReflex account or hosted service. Optional Claude token accounting uses Claude Code's local
@@ -32,17 +33,18 @@ OpenTelemetry export to a loopback-only OpenReflex receiver and stores counts on
32
33
 
33
34
  <p align="center">
34
35
  <a href="docs/walkthrough.md">
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">
36
+ <img alt="Recording of a Claude Code session with OpenReflex: OpenReflex injects compact prior context, Claude fixes the task and runs verification, and lifecycle hooks close the outcome automatically" src="https://raw.githubusercontent.com/vishnu-77/openreflex/main/docs/screenshots/claude-code-session.gif" width="860">
36
37
  </a>
37
38
  <br>
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>
39
+ <sub>A recorded Claude Code session. OpenReflex injects compact relevant context before work; lifecycle hooks capture tools and verification and close the execution automatically. MCP is not required for the normal path. The step-by-step walkthrough is in <a href="docs/walkthrough.md">docs/walkthrough.md</a>.</sub>
39
40
  </p>
40
41
 
41
42
  ## Why OpenReflex
42
43
 
43
- - **It remembers what worked.** Before a substantial task, OpenReflex retrieves similar past tasks and injects a
44
- compact Execution Context: a suggested approach with alternatives, the files that were changed, and lessons
45
- such as which edit resolved a recurring error.
44
+ - **It learns how the project behaves.** OpenReflex compiles successful work into project-scoped Reflexes such as
45
+ authentication changes, Helm configuration, database migrations or CI work. Resolution combines semantic intent,
46
+ task family and module/file locality, so a novel task can reuse a project procedure without repeating an
47
+ earlier task.
46
48
  - **It catches loops while they happen.** Repeated failing commands, identical retries, stalled progress, and
47
49
  runaway context growth raise one alert that says whether to continue, pivot to another approach, or stop and
48
50
  check in with you, never a stream of nags.
@@ -66,7 +68,7 @@ Requires Python 3.11 or newer.
66
68
  ```bash
67
69
  pipx install openreflex # or: uv tool install openreflex
68
70
  cd your-project
69
- openreflex install claude-code # writes hooks + MCP config and enables this project
71
+ openreflex install claude-code # hooks-only ambient runtime; enables this project
70
72
  ```
71
73
 
72
74
  ```
@@ -74,8 +76,8 @@ OPENREFLEX / CONNECT
74
76
  agent claude-code
75
77
  project D:\demo\shop
76
78
  config updated 2 files
79
+ D:\demo\shop\.openreflex.json
77
80
  D:\demo\shop\.claude\settings.json
78
- D:\demo\shop\.mcp.json
79
81
  memory enabled
80
82
  storage local
81
83
 
@@ -102,10 +104,10 @@ OpenReflex installs per project with `openreflex install <agent>`, or as a plugi
102
104
 
103
105
  | Agent | Connects through | Install | Verified |
104
106
  |---|---|---|---|
105
- | **Claude Code** | Plugin, or hooks + MCP | `claude plugin marketplace add vishnu-77/openreflex` then `claude plugin install openreflex@openreflex`, or `openreflex install claude-code` | Live sessions |
106
- | **Codex** | Plugin, or hooks + MCP | `codex plugin marketplace add vishnu-77/openreflex`, or `openreflex install codex`, then trust the hooks once in `/hooks` | Live sessions |
107
- | **Cursor** | Hooks + MCP | `openreflex install cursor` | Protocol and fuzz tests |
108
- | **OpenCode** | Plugin + MCP | `openreflex install opencode` | Protocol and fuzz tests |
107
+ | **Claude Code** | Plugin hooks, or project hooks | `claude plugin marketplace add vishnu-77/openreflex` then `claude plugin install openreflex@openreflex`, or `openreflex install claude-code` | Live sessions |
108
+ | **Codex** | Plugin hooks, or project hooks | `codex plugin marketplace add vishnu-77/openreflex`, or `openreflex install codex`, then trust the hooks once in `/hooks` | Live sessions |
109
+ | **Cursor** | Lifecycle hooks | `openreflex install cursor` | Protocol and fuzz tests |
110
+ | **OpenCode** | Local lifecycle plugin | `openreflex install opencode` | Protocol and fuzz tests |
109
111
 
110
112
  With a plugin install, enable each project with `openreflex approve`. Per-agent guides:
111
113
  [Claude Code](https://openreflex.cc/claude-code), [Codex](https://openreflex.cc/codex), [Cursor](https://openreflex.cc/cursor),
@@ -134,8 +136,9 @@ Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
134
136
  left and with the best untried alternative. The alert ends with a recommendation to **continue**, **pivot**
135
137
  to another strategy, or **stop** and ask the user. Each problem, pivot, or stop is raised once, with a cooldown
136
138
  between messages.
137
- - **After a task:** outcome and chosen path come from the agent's `record_outcome` / `choose_path` MCP calls when
138
- available, and are otherwise inferred from work-mode-appropriate evidence. The **Path check** says either
139
+ - **After a task:** lifecycle hooks close the execution automatically from work-mode-appropriate evidence; the model
140
+ does not need to call OpenReflex. Explicit MCP outcome/path operations remain available only for manual or diagnostic
141
+ workflows. The **Path check** says either
139
142
  `better option: <path>` when comparable completed tasks support it or `better option: none proven`.
140
143
  Recommendations are never presented as paths that were actually executed.
141
144
 
@@ -148,10 +151,13 @@ Set optional limits for every task with `OPENREFLEX_BUDGET`, for example `calls=
148
151
  Routing, scoring, budget and recap settings come from a versioned policy: the packaged defaults, overridden by
149
152
  `~/.openreflex/config.toml` and then by `.openreflex.toml` in the project.
150
153
 
151
- Agents can also query OpenReflex directly through its MCP server.
154
+ Normal work does **not** load OpenReflex MCP tools. If you explicitly want model-facing introspection for a project,
155
+ enable it with `openreflex diagnostics enable <agent>`. Disable it again with
156
+ `openreflex diagnostics disable <agent>`. The standalone MCP Registry package remains available for users who
157
+ deliberately install OpenReflex as an MCP server.
152
158
 
153
159
  <details>
154
- <summary><strong>The 12 MCP tools</strong></summary>
160
+ <summary><strong>The optional MCP diagnostics/admin tools</strong></summary>
155
161
 
156
162
  | Tool | What it does |
157
163
  |---|---|
@@ -174,8 +180,9 @@ Agents can also query OpenReflex directly through its MCP server.
174
180
 
175
181
  | Command | Purpose |
176
182
  |---|---|
177
- | `install <agent> [--dry-run]` | Write project hooks and MCP config, and enable the project |
178
- | `uninstall <agent> [--dry-run]` | Remove OpenReflex's project hooks and MCP config; captured memory is kept |
183
+ | `install <agent> [--dry-run]` | Install the hooks-only ambient runtime and enable the project |
184
+ | `diagnostics enable/disable <agent>` | Explicitly opt in/out of model-facing MCP diagnostics |
185
+ | `uninstall <agent> [--dry-run]` | Remove OpenReflex's integration entries; captured memory is kept |
179
186
  | `update [--check] [--reinstall]` | Check or update a managed pipx/uv-tool installation; optionally force a reinstall |
180
187
  | `self reinstall` | Repair/reinstall the managed OpenReflex package while preserving memory/config |
181
188
  | `self uninstall --yes` | Remove only the managed OpenReflex package; memory/config remain on disk |
@@ -187,7 +194,8 @@ Agents can also query OpenReflex directly through its MCP server.
187
194
  | `forget --yes` | Delete the project's data |
188
195
  | `tokens enable` / `tokens status` / `tokens disable` | Opt in to local Claude Code token accounting, inspect it, or remove OpenReflex-owned telemetry settings |
189
196
  | `benchmark` | Run the simulated benchmark |
190
- | `hook <agent> <event>` / `mcp` | Used by agent configs |
197
+ | `hook <agent> <event>` | Used by ambient agent integrations |
198
+ | `mcp` | Run the optional diagnostics/admin MCP server explicitly |
191
199
 
192
200
  ## Privacy
193
201
 
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "openreflex"
7
- version = "0.5.2"
8
- description = "Muscle memory for AI coding agents: learns from every task, advises the next one, and flags failure loops live"
7
+ version = "0.7.0"
8
+ description = "Ambient project muscle memory for AI coding agents: learns and reuses project Reflexes automatically"
9
9
  readme = "README.md"
10
10
  license = "MIT"
11
11
  license-files = ["LICENSE"]
@@ -1,3 +1,3 @@
1
1
  """Ambient, local execution intelligence."""
2
2
 
3
- __version__ = "0.5.2"
3
+ __version__ = "0.7.0"
@@ -80,6 +80,33 @@ def cmd_install(args) -> int:
80
80
  return 0
81
81
 
82
82
 
83
+ def cmd_diagnostics(args) -> int:
84
+ from .install import install_diagnostics, uninstall_diagnostics
85
+
86
+ project = _project(args.project)
87
+ operation = install_diagnostics if args.diagnostics_action == "enable" else uninstall_diagnostics
88
+ changes = operation(args.agent, project, dry_run=args.dry_run)
89
+ verb = "would update" if args.dry_run else ("enabled" if args.diagnostics_action == "enable" else "disabled")
90
+ print("OPENREFLEX / DIAGNOSTICS")
91
+ print(f" action {args.diagnostics_action}")
92
+ print(f" agent {args.agent}")
93
+ print(f" project {project}")
94
+ if changes:
95
+ print(f" config {verb} {len(changes)} file{'s' if len(changes) != 1 else ''}")
96
+ for change in changes:
97
+ print(f" {change}")
98
+ else:
99
+ state = "already enabled" if args.diagnostics_action == "enable" else "already disabled"
100
+ print(f" config {state}")
101
+ print(" runtime ambient hooks remain active")
102
+ if not args.dry_run and args.diagnostics_action == "enable":
103
+ print("\n [ok] optional MCP diagnostics enabled")
104
+ print(" note normal OpenReflex work does not require MCP calls")
105
+ elif not args.dry_run:
106
+ print("\n [ok] model-facing MCP diagnostics disabled")
107
+ return 0
108
+
109
+
83
110
  def cmd_uninstall(args) -> int:
84
111
  from .install import uninstall
85
112
 
@@ -122,6 +149,8 @@ def cmd_status(args) -> int:
122
149
  print(f"OpenReflex {__version__} - {project}")
123
150
  print(f" enabled: {data['enabled']} agents: {', '.join(data['engagement']['agents']) or '-'}")
124
151
  print(f" tasks: {data['engagement']['tasks']} experiences: {data['engagement']['experiences']} lessons: {data['lessons']}")
152
+ print(f" project reflexes: {data['project_reflexes']['visible']} "
153
+ f"({data['project_reflexes']['learned']} learned / {data['project_reflexes']['proven']} proven)")
125
154
  print(f" first session captured: {data['activation']['first_session_captured']} "
126
155
  f"seconds to first task: {data['activation']['seconds_to_first_task']}")
127
156
  print(f" tasks that used prior experience: {reuse['benefit_rate']}")
@@ -132,6 +161,13 @@ def cmd_status(args) -> int:
132
161
  f"{eff['without_prior_experience']['model_tokens']} (observational)")
133
162
  print(f" path checks: {path_check['comparisons']} better option found: {path_check['better_option_found']} "
134
163
  f"routing agreement: {routing['agreement']}")
164
+ overhead = data["openreflex_overhead"]
165
+ print(f" OpenReflex context: {overhead['estimated_context_tokens']:,} estimated tokens across "
166
+ f"{overhead['context_injected_tasks']} task(s); {overhead['zero_injection_tasks']} substantial task(s) at zero")
167
+ print(f" diagnostic MCP: {overhead['diagnostic_mcp_calls']} call(s), "
168
+ f"{overhead['diagnostic_mcp_tokens_estimate']:,} estimated result tokens")
169
+ if overhead["estimated_context_tax"] is not None:
170
+ print(f" estimated context tax: {overhead['estimated_context_tax']:.2%} of observed model-token usage")
135
171
  print(f" live alerts: {data['live_alerts'] or '-'}")
136
172
  control = data["execution_control"]
137
173
  print(f" verdicts: {control['verdicts'] or '-'} tasks within tool-call budget: {control['tasks_within_tool_call_budget']}")
@@ -240,7 +276,8 @@ def cmd_update(args) -> int:
240
276
  print(f" note expected {status.latest}; executable reports {installed}")
241
277
  print(" memory preserved")
242
278
  print(" config preserved")
243
- print("\nRestart active Claude Code, Codex, Cursor, or OpenCode sessions to reload hooks and MCP.")
279
+ print("\nRestart active Claude Code, Codex, Cursor, or OpenCode sessions to reload hooks"
280
+ " (and diagnostics MCP if you explicitly enabled it).")
244
281
  return 0
245
282
 
246
283
 
@@ -266,7 +303,8 @@ def cmd_self(args) -> int:
266
303
  print("\n [ok] package reinstalled")
267
304
  print(" memory preserved")
268
305
  print(" config preserved")
269
- print("\nRestart active agent sessions to reload hooks and MCP.")
306
+ print("\nRestart active agent sessions to reload hooks"
307
+ " (and diagnostics MCP if you explicitly enabled it).")
270
308
  return 0
271
309
 
272
310
  if args.self_action == "uninstall":
@@ -397,7 +435,7 @@ def cmd_benchmark(args) -> int:
397
435
  def build_parser() -> argparse.ArgumentParser:
398
436
  parser = argparse.ArgumentParser(
399
437
  prog="openreflex", description="Ambient execution intelligence for coding agents.",
400
- epilog="Also available: tui, memory, tokens, statusline (run `openreflex <name> --help` for details).",
438
+ epilog="Also available: tui, memory, reflexes, tokens, statusline (run `openreflex <name> --help` for details).",
401
439
  )
402
440
  parser.add_argument("--version", action="version", version=__version__)
403
441
  sub = parser.add_subparsers(dest="command", required=True)
@@ -420,14 +458,26 @@ def build_parser() -> argparse.ArgumentParser:
420
458
  command.add_argument("--project")
421
459
  command.set_defaults(func=func)
422
460
 
423
- for name, func, text in (("install", cmd_install, "Connect OpenReflex hooks + MCP for an agent"),
424
- ("uninstall", cmd_uninstall, "Disconnect OpenReflex hooks + MCP while preserving memory")):
461
+ for name, func, text in (("install", cmd_install, "Connect the ambient OpenReflex hook runtime for an agent"),
462
+ ("uninstall", cmd_uninstall, "Disconnect OpenReflex while preserving memory")):
425
463
  command = sub.add_parser(name, help=text)
426
464
  command.add_argument("agent", choices=AGENT_CHOICES)
427
465
  command.add_argument("--project")
428
466
  command.add_argument("--dry-run", action="store_true")
429
467
  command.set_defaults(func=func)
430
468
 
469
+ diagnostics = sub.add_parser(
470
+ "diagnostics",
471
+ help="Opt in/out of the model-facing MCP diagnostics surface; ambient hooks do not require it",
472
+ )
473
+ diagnostics_sub = diagnostics.add_subparsers(dest="diagnostics_action", required=True)
474
+ for action in ("enable", "disable"):
475
+ command = diagnostics_sub.add_parser(action, help=f"{action.capitalize()} optional MCP diagnostics")
476
+ command.add_argument("agent", choices=AGENT_CHOICES)
477
+ command.add_argument("--project")
478
+ command.add_argument("--dry-run", action="store_true")
479
+ command.set_defaults(func=cmd_diagnostics)
480
+
431
481
  update = sub.add_parser("update", help="Check PyPI and safely update the managed OpenReflex installation")
432
482
  update_group = update.add_mutually_exclusive_group()
433
483
  update_group.add_argument("--check", action="store_true", help="Only report whether an update is available")
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  from dataclasses import asdict, dataclass, field
6
6
  from typing import Iterable
7
7
 
8
- from .models import CandidatePath, Experience
8
+ from .models import CandidatePath, Execution, Experience, Task
9
9
  from .policy import Policy
10
10
 
11
11
 
@@ -46,6 +46,7 @@ class DecisionSnapshot:
46
46
  outcome: str | None = None
47
47
  model_tokens: int | None = None
48
48
  token_usage: dict[str, int | float] = field(default_factory=dict)
49
+ reflex_name: str | None = None
49
50
 
50
51
  def as_dict(self) -> dict:
51
52
  return asdict(self)
@@ -102,7 +103,8 @@ def make_snapshot(*, now: float, phase: str, action: str, best: CandidatePath |
102
103
  actual_tool_calls: int | None = None, actual_tokens: int | None = None,
103
104
  elapsed_seconds: float | None = None, outcome: str | None = None,
104
105
  expected_regret: float | None = None, model_tokens: int | None = None,
105
- token_usage: dict[str, int | float] | None = None) -> DecisionSnapshot:
106
+ token_usage: dict[str, int | float] | None = None,
107
+ reflex_name: str | None = None) -> DecisionSnapshot:
106
108
  if best is None:
107
109
  components = {name: 0.0 for name in policy.table("score.weights")}
108
110
  score = reflex_score(components, policy)
@@ -116,7 +118,7 @@ def make_snapshot(*, now: float, phase: str, action: str, best: CandidatePath |
116
118
  reason_codes=[], visibility=_visibility(phase, event, policy), event=event,
117
119
  actual_tool_calls=actual_tool_calls, actual_tokens=actual_tokens,
118
120
  elapsed_seconds=elapsed_seconds, outcome=outcome, model_tokens=model_tokens,
119
- token_usage=token_usage or {},
121
+ token_usage=token_usage or {}, reflex_name=reflex_name,
120
122
  )
121
123
 
122
124
  components = score_components(best, paths, experiences, policy)
@@ -139,7 +141,7 @@ def make_snapshot(*, now: float, phase: str, action: str, best: CandidatePath |
139
141
  score_components=components, reason_codes=reason_codes, visibility=_visibility(phase, event, policy),
140
142
  event=event, actual_tool_calls=actual_tool_calls, actual_tokens=actual_tokens,
141
143
  elapsed_seconds=elapsed_seconds, outcome=outcome, model_tokens=model_tokens,
142
- token_usage=token_usage or {},
144
+ token_usage=token_usage or {}, reflex_name=reflex_name,
143
145
  )
144
146
 
145
147
 
@@ -148,8 +150,8 @@ def render_recap(snapshot: DecisionSnapshot, previous: DecisionSnapshot | None =
148
150
  summary = []
149
151
  if snapshot.outcome:
150
152
  summary.append(snapshot.outcome)
151
- if snapshot.strategy:
152
- summary.append(snapshot.strategy)
153
+ if snapshot.reflex_name:
154
+ summary.append(snapshot.reflex_name)
153
155
 
154
156
  cost = []
155
157
  if snapshot.actual_tool_calls is not None:
@@ -164,9 +166,9 @@ def render_recap(snapshot: DecisionSnapshot, previous: DecisionSnapshot | None =
164
166
  comparison = None
165
167
  if snapshot.outcome != "unknown":
166
168
  if snapshot.expected_regret is not None and snapshot.next_best_strategy:
167
- comparison = f"Path check · better option: {snapshot.next_best_strategy}"
169
+ comparison = "Path check · another approach may be better"
168
170
  else:
169
- comparison = "Path check · better option: none proven"
171
+ comparison = "Path check · no better option proven"
170
172
 
171
173
  state = {
172
174
  "success": "COMPLETE",
@@ -191,11 +193,13 @@ def render_recap(snapshot: DecisionSnapshot, previous: DecisionSnapshot | None =
191
193
  success = "?" if snapshot.success_probability is None else f"{snapshot.success_probability:.0%}"
192
194
  calls = "?" if snapshot.estimated_tool_calls is None else f"~{snapshot.estimated_tool_calls:.0f} calls"
193
195
  tokens = "?" if snapshot.estimated_tokens is None else f"~{snapshot.estimated_tokens / 1000:.0f}k tokens"
194
- return (f"{first}\n{snapshot.evidence_count} experiences · {snapshot.strategy or 'unplanned'} {success} · "
196
+ label = snapshot.reflex_name or "working approach"
197
+ return (f"{first}\n{snapshot.evidence_count} experiences · {label} · {success} · "
195
198
  f"{calls} · {tokens} · +{snapshot.context_tokens} context tokens")
196
199
 
197
200
  success = "?" if snapshot.success_probability is None else f"{snapshot.success_probability:.0%}"
198
- message = (f"{first}\n{snapshot.action} · {snapshot.strategy or 'unplanned'} {success} · "
201
+ label = snapshot.reflex_name or "working approach"
202
+ message = (f"{first}\n{snapshot.action} · {label} · {success} · "
199
203
  f"budget {snapshot.budget_used:.0%}")
200
204
  if snapshot.next_best_strategy and snapshot.action in {"pivot", "stop"}:
201
205
  message += f" · next {snapshot.next_best_strategy}"
@@ -233,3 +237,31 @@ def render_trace(snapshots: list[DecisionSnapshot]) -> str:
233
237
  detail += f" · {snapshot.event}"
234
238
  lines.append(f"{minute:02d}:{second:02d} {label:<9} {detail}")
235
239
  return "\n".join(lines)
240
+
241
+
242
+ def render_paths(execution: Execution, task: Task, paths: list[CandidatePath]) -> str:
243
+ best = min(paths, key=lambda p: (p.dominated_by is not None, not p.within_limits, -p.score))
244
+ chosen = next((p for p in paths if p.id == execution.chosen_path_id), None)
245
+ recommended = next((p for p in paths if p.id == execution.recommended_path_id), None)
246
+ lines = ["OPENREFLEX / PATHS", "",
247
+ f"Task {task.task_class} - {task.description}",
248
+ f"Recommended {recommended.strategy if recommended else 'n/a'}"]
249
+ if chosen is not None:
250
+ lines.append(f"Followed {chosen.strategy} "
251
+ f"({'inferred from tool calls' if execution.chosen_inferred else 'explicit'})")
252
+ else:
253
+ lines.append("Followed not yet determined" +
254
+ (" (execution still running)" if execution.ended_at is None
255
+ else " (no strategy could be inferred from tool-call evidence)"))
256
+ lines += ["", "CANDIDATES"]
257
+ for path in paths:
258
+ tags = ", ".join(tag for tag in (("recommended" if path is recommended else None),
259
+ ("followed" if path is chosen else None)) if tag)
260
+ note = (f"dominated by {path.dominated_by}" if path.dominated_by else
261
+ "over your limit" if not path.within_limits else
262
+ (f"{path.score:+.2f} vs {best.score:+.2f}" if path is not best else ""))
263
+ suffix = " ".join(part for part in (f"[{tags}]" if tags else "", f"({note})" if note else "") if part)
264
+ lines.append(f" {path.strategy:<14} score {path.score:+.2f} success {path.success_probability:.0%} "
265
+ f"~{path.tool_calls:.0f} calls ~{path.time_seconds / 60:.0f} min risk {path.risk:.2f} "
266
+ f"{suffix}".rstrip())
267
+ return "\n".join(lines)