openreflex 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 (33) hide show
  1. openreflex-0.1.0/LICENSE +21 -0
  2. openreflex-0.1.0/PKG-INFO +250 -0
  3. openreflex-0.1.0/README.md +218 -0
  4. openreflex-0.1.0/pyproject.toml +57 -0
  5. openreflex-0.1.0/setup.cfg +4 -0
  6. openreflex-0.1.0/src/openreflex/__init__.py +3 -0
  7. openreflex-0.1.0/src/openreflex/__main__.py +5 -0
  8. openreflex-0.1.0/src/openreflex/benchmark.py +225 -0
  9. openreflex-0.1.0/src/openreflex/cli.py +238 -0
  10. openreflex-0.1.0/src/openreflex/detect.py +82 -0
  11. openreflex-0.1.0/src/openreflex/engine.py +445 -0
  12. openreflex-0.1.0/src/openreflex/hooks.py +239 -0
  13. openreflex-0.1.0/src/openreflex/install.py +114 -0
  14. openreflex-0.1.0/src/openreflex/integrations/opencode.ts +75 -0
  15. openreflex-0.1.0/src/openreflex/learning.py +151 -0
  16. openreflex-0.1.0/src/openreflex/mcp_server.py +112 -0
  17. openreflex-0.1.0/src/openreflex/metrics.py +123 -0
  18. openreflex-0.1.0/src/openreflex/models.py +195 -0
  19. openreflex-0.1.0/src/openreflex/privacy.py +119 -0
  20. openreflex-0.1.0/src/openreflex/project.py +103 -0
  21. openreflex-0.1.0/src/openreflex/routing.py +66 -0
  22. openreflex-0.1.0/src/openreflex/store.py +183 -0
  23. openreflex-0.1.0/src/openreflex.egg-info/PKG-INFO +250 -0
  24. openreflex-0.1.0/src/openreflex.egg-info/SOURCES.txt +31 -0
  25. openreflex-0.1.0/src/openreflex.egg-info/dependency_links.txt +1 -0
  26. openreflex-0.1.0/src/openreflex.egg-info/entry_points.txt +2 -0
  27. openreflex-0.1.0/src/openreflex.egg-info/requires.txt +8 -0
  28. openreflex-0.1.0/src/openreflex.egg-info/top_level.txt +1 -0
  29. openreflex-0.1.0/tests/test_engine.py +147 -0
  30. openreflex-0.1.0/tests/test_hooks.py +132 -0
  31. openreflex-0.1.0/tests/test_install_cli.py +97 -0
  32. openreflex-0.1.0/tests/test_mcp_metrics_benchmark.py +56 -0
  33. openreflex-0.1.0/tests/test_stress.py +133 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vishnu-77
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.
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.4
2
+ Name: openreflex
3
+ Version: 0.1.0
4
+ Summary: Muscle memory for AI coding agents: learns from every task, advises the next one, and flags failure loops live
5
+ Author: vishnu-77
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/vishnu-77/openreflex
8
+ Project-URL: Repository, https://github.com/vishnu-77/openreflex
9
+ Project-URL: Issues, https://github.com/vishnu-77/openreflex/issues
10
+ Keywords: ai-agents,coding-agents,claude-code,codex,cursor,opencode,mcp,memory,hooks
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Software Development
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: mcp<2,>=1.26
25
+ Requires-Dist: pydantic<3,>=2.10
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest<9,>=8; extra == "dev"
28
+ Requires-Dist: ruff>=0.12; extra == "dev"
29
+ Requires-Dist: build>=1.2; extra == "dev"
30
+ Requires-Dist: twine>=6; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # OpenReflex
34
+
35
+ **Muscle memory for AI coding agents.**
36
+
37
+ [![CI](https://github.com/vishnu-77/openreflex/actions/workflows/ci.yml/badge.svg)](https://github.com/vishnu-77/openreflex/actions/workflows/ci.yml)
38
+ [![PyPI](https://img.shields.io/pypi/v/openreflex)](https://pypi.org/project/openreflex/)
39
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
40
+
41
+ Ambient execution intelligence for AI coding agents. Install it once and keep working normally. It records how
42
+ each task actually went (strategy, tool calls, failures, what fixed them, which files mattered). Before the next
43
+ similar task it hands the agent a short **Execution Context**. While a task runs, it steps in only when the
44
+ evidence says re-planning is worthwhile.
45
+
46
+ Everything runs locally in SQLite. There is no service, no account, and no network access.
47
+
48
+ ```
49
+ install once -> work normally -> OpenReflex learns continuously
50
+ ```
51
+
52
+ ## Install (under 2 minutes)
53
+
54
+ ```bash
55
+ pipx install openreflex # or: uv tool install openreflex (puts `openreflex` on PATH)
56
+ cd your-project
57
+ openreflex install claude-code # or codex | cursor | opencode; also enables the project
58
+ ```
59
+
60
+ `install` writes project-level hook and MCP config for one agent, merging with any existing files, and approves
61
+ the project. Use `--dry-run` to preview the changes.
62
+
63
+ ### Plugin install (no project files)
64
+
65
+ | Agent | How |
66
+ |---|---|
67
+ | Claude Code | `claude plugin marketplace add vishnu-77/openreflex` then `claude plugin install openreflex@openreflex`, then `openreflex approve` in each project |
68
+ | Codex | `codex plugin marketplace add vishnu-77/openreflex` (reads `.agents/plugins/marketplace.json`), enable the plugin, trust its hooks once in `/hooks`, then `openreflex approve` |
69
+ | Cursor | copy `plugins/openreflex` to `~/.cursor/plugins/local/openreflex`, then `openreflex approve` |
70
+
71
+ Nothing is captured in a project until it is approved. An unapproved project shows a one-line notice at most
72
+ once a day. To stop capture, run `openreflex revoke`. To delete a project's data, run `openreflex forget --yes`.
73
+
74
+ ## How it works
75
+
76
+ ```
77
+ agent hooks ──► openreflex hook <agent> <event> ──► Engine ──► Experience Graph (SQLite)
78
+ prompt normalize payload per agent │
79
+ tool start (hooks.py) ├─ before: retrieve experience, score 3 candidate
80
+ tool end │ paths, render Execution Context
81
+ compaction ├─ during: detect failure loops, repeated calls,
82
+ stop │ stagnation, context growth, over-budget
83
+ └─ after: infer outcome + chosen path, estimate
84
+ agent ◄── additionalContext / alerts ◄──────────────────── Execution Regret, extract lessons
85
+ agent ──► MCP tools (get_execution_context, choose_path, record_outcome, search_experience, ...)
86
+ ```
87
+
88
+ **Experience Graph.** The nodes are `Task`, `Context`, `CandidatePath`, `Execution`, `ToolCall`, `Outcome`,
89
+ `Experience`, and `Lesson`. They are connected by `used`, `caused`, `failed_with`, `resolved_by`, and
90
+ `recommended_for`:
91
+
92
+ ```
93
+ Task -caused-> Execution -used-> Context -used-> Experience
94
+ CandidatePath -recommended_for-> Task Lesson -recommended_for-> Task
95
+ Execution -failed_with-> ToolCall -resolved_by-> ToolCall (the edit that fixed it)
96
+ Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
97
+ ```
98
+
99
+ **Before a task.** A prompt counts as substantial if it has at least 5 words and isn't a follow-up like "yes,
100
+ continue". For those prompts, OpenReflex:
101
+ 1. Retrieves similar past experiences.
102
+ 2. Scores `inspect-first`, `test-first`, and `incremental` on success probability, time, tool calls, context
103
+ cost, risk, uncertainty, and reversibility. Each score is a Beta-style blend of a prior and observed outcomes.
104
+ 3. Injects a context of at most 1,400 characters: the suggested path, alternatives, likely relevant files, and
105
+ lessons.
106
+
107
+ Nothing is injected when there is no relevant experience, so a new project costs zero context tokens.
108
+
109
+ **During a task.** Each alert kind fires at most once per execution, with a 3-minute cooldown. Stagnation is
110
+ only judged after implementation has started, so exploratory reading does not trigger it. An alert names a
111
+ concrete alternative path and any known fix for the current error.
112
+
113
+ **After a task.** The `Stop` hook finalizes the execution. Later turns reopen it and finalize it again, so the
114
+ same task keeps one experience. Outcome and chosen path come from `record_outcome`/`choose_path` when the agent
115
+ calls them. Otherwise they are inferred: only a check that passed or failed after the last edit counts as
116
+ evidence. **Execution Regret** is the best alternative's expected utility minus the chosen path's realized
117
+ utility. It is withheld (not guessed) when the outcome is unknown.
118
+
119
+ ## Agent integrations
120
+
121
+ | | Prompt context | Tool capture | Failure signal | Alerts delivered via | Turn end |
122
+ |---|---|---|---|---|---|
123
+ | Claude Code | `UserPromptSubmit` additionalContext | Pre/PostToolUse | `PostToolUseFailure` | PostToolUse additionalContext | `Stop` |
124
+ | Codex | `UserPromptSubmit` additionalContext | Pre/PostToolUse | parsed from `tool_response` | PostToolUse additionalContext | `Stop` |
125
+ | Cursor | deferred to first `postToolUse`* | pre/postToolUse | `postToolUseFailure` | postToolUse `additional_context` | `stop` |
126
+ | OpenCode | system-prompt transform (plugin) | tool.execute.before/after | `message.part.updated` error | appended to tool output | `session.idle` |
127
+
128
+ \* Cursor's `beforeSubmitPrompt` cannot inject context, so the context is held until the first tool result.
129
+ Cursor can also run Claude Code hook configs. Those calls are attributed to Cursor and de-duplicated.
130
+
131
+ **Claude Code is verified in live sessions** (see [Testing](#testing)). The Codex, Cursor, and OpenCode adapters
132
+ follow each agent's documented hook protocol (checked September 2026) and are tested with protocol-shaped and
133
+ fuzzed payloads, but have not yet run inside live sessions of those agents.
134
+
135
+ A hook always exits 0 and never blocks. Errors go to `~/.openreflex/logs/errors.log`, which
136
+ `openreflex doctor` shows. Measured on Windows: median 381 ms per hook process, where bare Python startup
137
+ is about 255 ms. Sixteen parallel tool-call hooks were stored with no lost writes.
138
+
139
+ ## Privacy
140
+
141
+ - Stored per tool call: tool name, a coarse category (`read`/`edit`/`search`/`test`/...), a SHA-256 fingerprint
142
+ of the arguments, project-relative file paths, status, duration, output *size*, and a masked one-line error
143
+ signature. Paths outside the project, file contents, command text, tool output, and transcripts are never stored.
144
+ - Prompts are stored as task descriptions, at most 1,000 characters, with secrets (API keys, tokens, bearer
145
+ headers, private keys) redacted.
146
+ - Data lives in `~/.openreflex/projects/<hash>/experience.sqlite3`. Set `OPENREFLEX_HOME` to relocate
147
+ it, or `OPENREFLEX_DISABLE=1` to turn capture off everywhere.
148
+
149
+ ## CLI
150
+
151
+ | Command | Purpose |
152
+ |---|---|
153
+ | `install <agent> [--dry-run]` | Write project hooks + MCP config and approve the project |
154
+ | `approve` / `revoke` | Enable / disable capture for the current project |
155
+ | `status [--json]` | Capture, reuse, outcome, efficiency, regret and routing metrics |
156
+ | `context "<task>"` | Preview the Execution Context a task would get |
157
+ | `doctor` | Installation checks and recent hook errors |
158
+ | `forget --yes` | Delete the project's data |
159
+ | `benchmark` | Simulated baseline-vs-guided benchmark |
160
+ | `hook <agent> <event>` / `mcp` | Used by agent configs |
161
+
162
+ ## Measuring the success metrics
163
+
164
+ `openreflex status --json` reports these per project:
165
+
166
+ | Plan metric | Field |
167
+ |---|---|
168
+ | <2-minute activation | `activation.seconds_to_first_task` (approval → first captured task) |
169
+ | >70% first-session capture | `activation.first_session_captured` |
170
+ | >50% weekly active retention | `engagement.active_week_ratio` |
171
+ | >30% tasks benefiting | `experience_reuse.benefit_rate` |
172
+ | 20–30% fewer tool calls, 20% fewer tokens, 15% faster | `efficiency_observational.*_change` (observational only; confounded by task mix) |
173
+ | No success-rate regression | `outcomes.success_rate` |
174
+ | >70% routing agreement | `routing.agreement` vs. `routing.retrospective_best` |
175
+ | Declining regret | `execution_regret.by_class[*].early` vs `recent` |
176
+
177
+ Cross-project aggregation (retention across projects, fleet-level activation) belongs with M5 sync.
178
+
179
+ ## Benchmark (simulated)
180
+
181
+ `openreflex benchmark` runs synthetic coding tasks from five task families, in two arms, through the real
182
+ engine. Both arms send real hook events and read back the real contexts and alerts; only the guided arm acts on
183
+ them. Default run: 150 tasks per arm × 3 seeds.
184
+
185
+ | Metric | Baseline | Guided | Change | Target |
186
+ |---|---|---|---|---|
187
+ | Tool calls / task | 13.97 | 9.21 | −34% | −20…−30% |
188
+ | Output tokens / task | 13,008 | 8,394 | −36% | −20% |
189
+ | Time / task | 349 s | 230 s | −34% | −15% |
190
+ | Success rate | 0.687 | 0.809 | +0.12 | ≥ baseline |
191
+ | Regret, first → last quarter | 0.107 → 0.103 | 0.079 → 0.036 | | declining |
192
+ | Routing agreement (2nd half) | – | 0.698 | | > 0.70 (**just missed**) |
193
+
194
+ **How to read this.** These are properties of the simulator, not evidence of real-world gains. Most of the
195
+ tool-call and token reduction comes from one assumption: a relevant-files hint cuts search and read calls from
196
+ 6–9 down to 2–3. Time is modeled as calls × 25 s, so it moves exactly with calls. All assumptions are listed in
197
+ `SIMULATION_ASSUMPTIONS` in `benchmark.py` and written into the JSON report. What the benchmark does show: the
198
+ engine learns family-specific best strategies from noisy outcomes, regret declines, and alerts shorten failure
199
+ loops. Routing agreement falls short because candidate evidence is pooled per task class, so families in the
200
+ same class that prefer different strategies dilute each other.
201
+
202
+ ## Status
203
+
204
+ | Milestone | State |
205
+ |---|---|
206
+ | **M1**: local engine, schemas, telemetry, MCP, agent integration | Done, for four agents |
207
+ | **M2**: retrieval, graph, Execution Context, cross-session memory | Done. Embeddings are offline lexical feature hashing, not a semantic model |
208
+ | **M3**: candidate paths, risk/reward scoring, live inefficiency detection | Done (deterministic) |
209
+ | **M4**: regret, lessons, cross-agent support, benchmark suite | Done. The benchmark is simulated; a real-task A/B harness is still to do |
210
+ | **M5**: learned Trajectory Router, cloud sync, team sharing | Not started |
211
+
212
+ Suggested next steps, in order:
213
+ 1. Run the Codex, Cursor, and OpenCode integrations in live sessions and fix protocol drift.
214
+ 2. Weight candidate evidence by similarity instead of pooling by task class; this is the cause of the routing-agreement miss.
215
+ 3. Build a real-task A/B harness: the same task set with capture on and off.
216
+ 4. Add a pluggable semantic embedder (keep lexical as the offline default) and a vector index once there are more than ~5k experiences.
217
+ 5. M5.
218
+
219
+ ## Testing
220
+
221
+ | Layer | What runs | Where |
222
+ |---|---|---|
223
+ | Unit + integration | Engine, adapters for all 4 agents, installers, CLI subprocesses, MCP, metrics, benchmark | CI: Linux, macOS, Windows × Python 3.11–3.13 |
224
+ | Stress | 24 parallel hook-process pairs (no lost writes), 3,000-experience retrieval, 400 fuzzed hostile payloads across all agents (only unparseable JSON may be rejected) | CI matrix |
225
+ | Packaging | Build sdist + wheel, `twine check --strict`, install the wheel into a clean venv, smoke-test console script, hooks, status and MCP over stdio | CI: Linux, macOS, Windows |
226
+ | Release | Publish to TestPyPI, then install from TestPyPI on 3 OSes and rerun the smoke test before PyPI | `release.yml` |
227
+ | Live agent | Real headless Claude Code sessions (`scripts/live_claude_code.py`) | Local; needs a signed-in `claude` |
228
+
229
+ The live Claude Code scenarios assert on the captured graph and on the session transcript, not on model wording:
230
+
231
+ 1. **plugin-capture:** the plugin is loaded with `--plugin-dir`; a real bug fix is captured with categorized tool calls, an inferred success, and lessons.
232
+ 2. **context-injection:** a similar task in a new session gets an Execution Context naming the right file, and the transcript shows the model received it.
233
+ 3. **failure-loop-alert:** repeated failing test runs raise one alert, and the transcript shows it reached the model.
234
+ 4. **mcp-tools:** the plugin's MCP server starts inside Claude Code and `search_experience` returns the captured files.
235
+ 5. **project-install:** `openreflex install claude-code` works without the plugin.
236
+
237
+ ## Development
238
+
239
+ ```bash
240
+ pip install -e ".[dev]"
241
+ pytest # unit, integration, stress
242
+ ruff check src tests scripts
243
+ python scripts/live_claude_code.py # live Claude Code scenarios (real model calls, default haiku)
244
+ ```
245
+
246
+ Layout: `engine.py` (event → graph), `routing.py` (retrieval features, candidates, utility), `detect.py` (live
247
+ alerts), `learning.py` (outcome/strategy inference, regret, lessons), `hooks.py` (agent adapters),
248
+ `mcp_server.py`, `install.py`, `metrics.py`, `benchmark.py`, `integrations/opencode.ts`, and
249
+ `plugins/openreflex` (Claude Code / Codex / Cursor plugin; its hook files are checked against `install.py`
250
+ by tests).
@@ -0,0 +1,218 @@
1
+ # OpenReflex
2
+
3
+ **Muscle memory for AI coding agents.**
4
+
5
+ [![CI](https://github.com/vishnu-77/openreflex/actions/workflows/ci.yml/badge.svg)](https://github.com/vishnu-77/openreflex/actions/workflows/ci.yml)
6
+ [![PyPI](https://img.shields.io/pypi/v/openreflex)](https://pypi.org/project/openreflex/)
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+
9
+ Ambient execution intelligence for AI coding agents. Install it once and keep working normally. It records how
10
+ each task actually went (strategy, tool calls, failures, what fixed them, which files mattered). Before the next
11
+ similar task it hands the agent a short **Execution Context**. While a task runs, it steps in only when the
12
+ evidence says re-planning is worthwhile.
13
+
14
+ Everything runs locally in SQLite. There is no service, no account, and no network access.
15
+
16
+ ```
17
+ install once -> work normally -> OpenReflex learns continuously
18
+ ```
19
+
20
+ ## Install (under 2 minutes)
21
+
22
+ ```bash
23
+ pipx install openreflex # or: uv tool install openreflex (puts `openreflex` on PATH)
24
+ cd your-project
25
+ openreflex install claude-code # or codex | cursor | opencode; also enables the project
26
+ ```
27
+
28
+ `install` writes project-level hook and MCP config for one agent, merging with any existing files, and approves
29
+ the project. Use `--dry-run` to preview the changes.
30
+
31
+ ### Plugin install (no project files)
32
+
33
+ | Agent | How |
34
+ |---|---|
35
+ | Claude Code | `claude plugin marketplace add vishnu-77/openreflex` then `claude plugin install openreflex@openreflex`, then `openreflex approve` in each project |
36
+ | Codex | `codex plugin marketplace add vishnu-77/openreflex` (reads `.agents/plugins/marketplace.json`), enable the plugin, trust its hooks once in `/hooks`, then `openreflex approve` |
37
+ | Cursor | copy `plugins/openreflex` to `~/.cursor/plugins/local/openreflex`, then `openreflex approve` |
38
+
39
+ Nothing is captured in a project until it is approved. An unapproved project shows a one-line notice at most
40
+ once a day. To stop capture, run `openreflex revoke`. To delete a project's data, run `openreflex forget --yes`.
41
+
42
+ ## How it works
43
+
44
+ ```
45
+ agent hooks ──► openreflex hook <agent> <event> ──► Engine ──► Experience Graph (SQLite)
46
+ prompt normalize payload per agent │
47
+ tool start (hooks.py) ├─ before: retrieve experience, score 3 candidate
48
+ tool end │ paths, render Execution Context
49
+ compaction ├─ during: detect failure loops, repeated calls,
50
+ stop │ stagnation, context growth, over-budget
51
+ └─ after: infer outcome + chosen path, estimate
52
+ agent ◄── additionalContext / alerts ◄──────────────────── Execution Regret, extract lessons
53
+ agent ──► MCP tools (get_execution_context, choose_path, record_outcome, search_experience, ...)
54
+ ```
55
+
56
+ **Experience Graph.** The nodes are `Task`, `Context`, `CandidatePath`, `Execution`, `ToolCall`, `Outcome`,
57
+ `Experience`, and `Lesson`. They are connected by `used`, `caused`, `failed_with`, `resolved_by`, and
58
+ `recommended_for`:
59
+
60
+ ```
61
+ Task -caused-> Execution -used-> Context -used-> Experience
62
+ CandidatePath -recommended_for-> Task Lesson -recommended_for-> Task
63
+ Execution -failed_with-> ToolCall -resolved_by-> ToolCall (the edit that fixed it)
64
+ Execution -caused-> Outcome -caused-> Experience -caused-> Lesson
65
+ ```
66
+
67
+ **Before a task.** A prompt counts as substantial if it has at least 5 words and isn't a follow-up like "yes,
68
+ continue". For those prompts, OpenReflex:
69
+ 1. Retrieves similar past experiences.
70
+ 2. Scores `inspect-first`, `test-first`, and `incremental` on success probability, time, tool calls, context
71
+ cost, risk, uncertainty, and reversibility. Each score is a Beta-style blend of a prior and observed outcomes.
72
+ 3. Injects a context of at most 1,400 characters: the suggested path, alternatives, likely relevant files, and
73
+ lessons.
74
+
75
+ Nothing is injected when there is no relevant experience, so a new project costs zero context tokens.
76
+
77
+ **During a task.** Each alert kind fires at most once per execution, with a 3-minute cooldown. Stagnation is
78
+ only judged after implementation has started, so exploratory reading does not trigger it. An alert names a
79
+ concrete alternative path and any known fix for the current error.
80
+
81
+ **After a task.** The `Stop` hook finalizes the execution. Later turns reopen it and finalize it again, so the
82
+ same task keeps one experience. Outcome and chosen path come from `record_outcome`/`choose_path` when the agent
83
+ calls them. Otherwise they are inferred: only a check that passed or failed after the last edit counts as
84
+ evidence. **Execution Regret** is the best alternative's expected utility minus the chosen path's realized
85
+ utility. It is withheld (not guessed) when the outcome is unknown.
86
+
87
+ ## Agent integrations
88
+
89
+ | | Prompt context | Tool capture | Failure signal | Alerts delivered via | Turn end |
90
+ |---|---|---|---|---|---|
91
+ | Claude Code | `UserPromptSubmit` additionalContext | Pre/PostToolUse | `PostToolUseFailure` | PostToolUse additionalContext | `Stop` |
92
+ | Codex | `UserPromptSubmit` additionalContext | Pre/PostToolUse | parsed from `tool_response` | PostToolUse additionalContext | `Stop` |
93
+ | Cursor | deferred to first `postToolUse`* | pre/postToolUse | `postToolUseFailure` | postToolUse `additional_context` | `stop` |
94
+ | OpenCode | system-prompt transform (plugin) | tool.execute.before/after | `message.part.updated` error | appended to tool output | `session.idle` |
95
+
96
+ \* Cursor's `beforeSubmitPrompt` cannot inject context, so the context is held until the first tool result.
97
+ Cursor can also run Claude Code hook configs. Those calls are attributed to Cursor and de-duplicated.
98
+
99
+ **Claude Code is verified in live sessions** (see [Testing](#testing)). The Codex, Cursor, and OpenCode adapters
100
+ follow each agent's documented hook protocol (checked September 2026) and are tested with protocol-shaped and
101
+ fuzzed payloads, but have not yet run inside live sessions of those agents.
102
+
103
+ A hook always exits 0 and never blocks. Errors go to `~/.openreflex/logs/errors.log`, which
104
+ `openreflex doctor` shows. Measured on Windows: median 381 ms per hook process, where bare Python startup
105
+ is about 255 ms. Sixteen parallel tool-call hooks were stored with no lost writes.
106
+
107
+ ## Privacy
108
+
109
+ - Stored per tool call: tool name, a coarse category (`read`/`edit`/`search`/`test`/...), a SHA-256 fingerprint
110
+ of the arguments, project-relative file paths, status, duration, output *size*, and a masked one-line error
111
+ signature. Paths outside the project, file contents, command text, tool output, and transcripts are never stored.
112
+ - Prompts are stored as task descriptions, at most 1,000 characters, with secrets (API keys, tokens, bearer
113
+ headers, private keys) redacted.
114
+ - Data lives in `~/.openreflex/projects/<hash>/experience.sqlite3`. Set `OPENREFLEX_HOME` to relocate
115
+ it, or `OPENREFLEX_DISABLE=1` to turn capture off everywhere.
116
+
117
+ ## CLI
118
+
119
+ | Command | Purpose |
120
+ |---|---|
121
+ | `install <agent> [--dry-run]` | Write project hooks + MCP config and approve the project |
122
+ | `approve` / `revoke` | Enable / disable capture for the current project |
123
+ | `status [--json]` | Capture, reuse, outcome, efficiency, regret and routing metrics |
124
+ | `context "<task>"` | Preview the Execution Context a task would get |
125
+ | `doctor` | Installation checks and recent hook errors |
126
+ | `forget --yes` | Delete the project's data |
127
+ | `benchmark` | Simulated baseline-vs-guided benchmark |
128
+ | `hook <agent> <event>` / `mcp` | Used by agent configs |
129
+
130
+ ## Measuring the success metrics
131
+
132
+ `openreflex status --json` reports these per project:
133
+
134
+ | Plan metric | Field |
135
+ |---|---|
136
+ | <2-minute activation | `activation.seconds_to_first_task` (approval → first captured task) |
137
+ | >70% first-session capture | `activation.first_session_captured` |
138
+ | >50% weekly active retention | `engagement.active_week_ratio` |
139
+ | >30% tasks benefiting | `experience_reuse.benefit_rate` |
140
+ | 20–30% fewer tool calls, 20% fewer tokens, 15% faster | `efficiency_observational.*_change` (observational only; confounded by task mix) |
141
+ | No success-rate regression | `outcomes.success_rate` |
142
+ | >70% routing agreement | `routing.agreement` vs. `routing.retrospective_best` |
143
+ | Declining regret | `execution_regret.by_class[*].early` vs `recent` |
144
+
145
+ Cross-project aggregation (retention across projects, fleet-level activation) belongs with M5 sync.
146
+
147
+ ## Benchmark (simulated)
148
+
149
+ `openreflex benchmark` runs synthetic coding tasks from five task families, in two arms, through the real
150
+ engine. Both arms send real hook events and read back the real contexts and alerts; only the guided arm acts on
151
+ them. Default run: 150 tasks per arm × 3 seeds.
152
+
153
+ | Metric | Baseline | Guided | Change | Target |
154
+ |---|---|---|---|---|
155
+ | Tool calls / task | 13.97 | 9.21 | −34% | −20…−30% |
156
+ | Output tokens / task | 13,008 | 8,394 | −36% | −20% |
157
+ | Time / task | 349 s | 230 s | −34% | −15% |
158
+ | Success rate | 0.687 | 0.809 | +0.12 | ≥ baseline |
159
+ | Regret, first → last quarter | 0.107 → 0.103 | 0.079 → 0.036 | | declining |
160
+ | Routing agreement (2nd half) | – | 0.698 | | > 0.70 (**just missed**) |
161
+
162
+ **How to read this.** These are properties of the simulator, not evidence of real-world gains. Most of the
163
+ tool-call and token reduction comes from one assumption: a relevant-files hint cuts search and read calls from
164
+ 6–9 down to 2–3. Time is modeled as calls × 25 s, so it moves exactly with calls. All assumptions are listed in
165
+ `SIMULATION_ASSUMPTIONS` in `benchmark.py` and written into the JSON report. What the benchmark does show: the
166
+ engine learns family-specific best strategies from noisy outcomes, regret declines, and alerts shorten failure
167
+ loops. Routing agreement falls short because candidate evidence is pooled per task class, so families in the
168
+ same class that prefer different strategies dilute each other.
169
+
170
+ ## Status
171
+
172
+ | Milestone | State |
173
+ |---|---|
174
+ | **M1**: local engine, schemas, telemetry, MCP, agent integration | Done, for four agents |
175
+ | **M2**: retrieval, graph, Execution Context, cross-session memory | Done. Embeddings are offline lexical feature hashing, not a semantic model |
176
+ | **M3**: candidate paths, risk/reward scoring, live inefficiency detection | Done (deterministic) |
177
+ | **M4**: regret, lessons, cross-agent support, benchmark suite | Done. The benchmark is simulated; a real-task A/B harness is still to do |
178
+ | **M5**: learned Trajectory Router, cloud sync, team sharing | Not started |
179
+
180
+ Suggested next steps, in order:
181
+ 1. Run the Codex, Cursor, and OpenCode integrations in live sessions and fix protocol drift.
182
+ 2. Weight candidate evidence by similarity instead of pooling by task class; this is the cause of the routing-agreement miss.
183
+ 3. Build a real-task A/B harness: the same task set with capture on and off.
184
+ 4. Add a pluggable semantic embedder (keep lexical as the offline default) and a vector index once there are more than ~5k experiences.
185
+ 5. M5.
186
+
187
+ ## Testing
188
+
189
+ | Layer | What runs | Where |
190
+ |---|---|---|
191
+ | Unit + integration | Engine, adapters for all 4 agents, installers, CLI subprocesses, MCP, metrics, benchmark | CI: Linux, macOS, Windows × Python 3.11–3.13 |
192
+ | Stress | 24 parallel hook-process pairs (no lost writes), 3,000-experience retrieval, 400 fuzzed hostile payloads across all agents (only unparseable JSON may be rejected) | CI matrix |
193
+ | Packaging | Build sdist + wheel, `twine check --strict`, install the wheel into a clean venv, smoke-test console script, hooks, status and MCP over stdio | CI: Linux, macOS, Windows |
194
+ | Release | Publish to TestPyPI, then install from TestPyPI on 3 OSes and rerun the smoke test before PyPI | `release.yml` |
195
+ | Live agent | Real headless Claude Code sessions (`scripts/live_claude_code.py`) | Local; needs a signed-in `claude` |
196
+
197
+ The live Claude Code scenarios assert on the captured graph and on the session transcript, not on model wording:
198
+
199
+ 1. **plugin-capture:** the plugin is loaded with `--plugin-dir`; a real bug fix is captured with categorized tool calls, an inferred success, and lessons.
200
+ 2. **context-injection:** a similar task in a new session gets an Execution Context naming the right file, and the transcript shows the model received it.
201
+ 3. **failure-loop-alert:** repeated failing test runs raise one alert, and the transcript shows it reached the model.
202
+ 4. **mcp-tools:** the plugin's MCP server starts inside Claude Code and `search_experience` returns the captured files.
203
+ 5. **project-install:** `openreflex install claude-code` works without the plugin.
204
+
205
+ ## Development
206
+
207
+ ```bash
208
+ pip install -e ".[dev]"
209
+ pytest # unit, integration, stress
210
+ ruff check src tests scripts
211
+ python scripts/live_claude_code.py # live Claude Code scenarios (real model calls, default haiku)
212
+ ```
213
+
214
+ Layout: `engine.py` (event → graph), `routing.py` (retrieval features, candidates, utility), `detect.py` (live
215
+ alerts), `learning.py` (outcome/strategy inference, regret, lessons), `hooks.py` (agent adapters),
216
+ `mcp_server.py`, `install.py`, `metrics.py`, `benchmark.py`, `integrations/opencode.ts`, and
217
+ `plugins/openreflex` (Claude Code / Codex / Cursor plugin; its hook files are checked against `install.py`
218
+ by tests).
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "openreflex"
7
+ version = "0.1.0"
8
+ description = "Muscle memory for AI coding agents: learns from every task, advises the next one, and flags failure loops live"
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ authors = [{ name = "vishnu-77" }]
13
+ requires-python = ">=3.11"
14
+ dependencies = ["mcp>=1.26,<2", "pydantic>=2.10,<3"]
15
+ keywords = ["ai-agents", "coding-agents", "claude-code", "codex", "cursor", "opencode", "mcp", "memory", "hooks"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Environment :: Console",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Topic :: Software Development",
26
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/vishnu-77/openreflex"
31
+ Repository = "https://github.com/vishnu-77/openreflex"
32
+ Issues = "https://github.com/vishnu-77/openreflex/issues"
33
+
34
+ [project.optional-dependencies]
35
+ dev = ["pytest>=8,<9", "ruff>=0.12", "build>=1.2", "twine>=6"]
36
+
37
+ [project.scripts]
38
+ openreflex = "openreflex.cli:main"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.setuptools.package-data]
44
+ openreflex = ["integrations/*.ts"]
45
+
46
+ [tool.pytest.ini_options]
47
+ testpaths = ["tests"]
48
+ pythonpath = ["src"]
49
+ markers = ["slow: subprocess-heavy stress tests"]
50
+
51
+ [tool.ruff]
52
+ line-length = 110
53
+ target-version = "py311"
54
+
55
+ [tool.ruff.lint]
56
+ # Explicit rule set so results don't drift when newer ruff releases change their defaults.
57
+ select = ["E4", "E7", "E9", "F"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """Ambient, local execution intelligence."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,5 @@
1
+ import sys
2
+
3
+ from .cli import main
4
+
5
+ sys.exit(main())