research-git 0.0.3__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. {research_git-0.0.3/src/research_git.egg-info → research_git-0.0.4}/PKG-INFO +21 -12
  2. {research_git-0.0.3 → research_git-0.0.4}/README.md +20 -11
  3. {research_git-0.0.3 → research_git-0.0.4}/pyproject.toml +1 -1
  4. {research_git-0.0.3 → research_git-0.0.4/src/research_git.egg-info}/PKG-INFO +21 -12
  5. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/_plugin/skills/rgit-capture/SKILL.md +4 -1
  6. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/agent_guidance.py +14 -6
  7. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/astmap.py +26 -31
  8. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/cli.py +448 -41
  9. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/curation.py +4 -1
  10. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/gitutil.py +203 -1
  11. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/hooks.py +13 -2
  12. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/installer.py +21 -0
  13. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/segmenter.py +47 -8
  14. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/store/db.py +4 -1
  15. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/store/models.py +1 -0
  16. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/store/store.py +5 -3
  17. {research_git-0.0.3 → research_git-0.0.4}/tests/test_agent_guidance.py +18 -1
  18. {research_git-0.0.3 → research_git-0.0.4}/tests/test_astmap.py +26 -0
  19. research_git-0.0.4/tests/test_cli.py +1247 -0
  20. {research_git-0.0.3 → research_git-0.0.4}/tests/test_curation.py +31 -0
  21. {research_git-0.0.3 → research_git-0.0.4}/tests/test_e2e.py +41 -0
  22. {research_git-0.0.3 → research_git-0.0.4}/tests/test_gitutil.py +207 -0
  23. {research_git-0.0.3 → research_git-0.0.4}/tests/test_hooks.py +28 -0
  24. {research_git-0.0.3 → research_git-0.0.4}/tests/test_installer.py +21 -0
  25. {research_git-0.0.3 → research_git-0.0.4}/tests/test_segmenter.py +59 -0
  26. {research_git-0.0.3 → research_git-0.0.4}/tests/test_store.py +37 -0
  27. research_git-0.0.3/tests/test_cli.py +0 -551
  28. {research_git-0.0.3 → research_git-0.0.4}/LICENSE +0 -0
  29. {research_git-0.0.3 → research_git-0.0.4}/setup.cfg +0 -0
  30. {research_git-0.0.3 → research_git-0.0.4}/src/research_git.egg-info/SOURCES.txt +0 -0
  31. {research_git-0.0.3 → research_git-0.0.4}/src/research_git.egg-info/dependency_links.txt +0 -0
  32. {research_git-0.0.3 → research_git-0.0.4}/src/research_git.egg-info/entry_points.txt +0 -0
  33. {research_git-0.0.3 → research_git-0.0.4}/src/research_git.egg-info/requires.txt +0 -0
  34. {research_git-0.0.3 → research_git-0.0.4}/src/research_git.egg-info/top_level.txt +0 -0
  35. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/__init__.py +0 -0
  36. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/_plugin/.claude-plugin/marketplace.json +0 -0
  37. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/_plugin/.claude-plugin/plugin.json +0 -0
  38. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/_plugin/agents/capsule-regenerator.md +0 -0
  39. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/_plugin/agents/capsule-segmenter.md +0 -0
  40. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/_plugin/agents/edge-judge.md +0 -0
  41. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/_plugin/skills/rgit-recall/SKILL.md +0 -0
  42. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/ablation.py +0 -0
  43. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/agent_platforms.py +0 -0
  44. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/compare.py +0 -0
  45. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/compose.py +0 -0
  46. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/edges.py +0 -0
  47. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/graphview.py +0 -0
  48. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/mcp_server.py +0 -0
  49. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/metricdir.py +0 -0
  50. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/metrics.py +0 -0
  51. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/provenance.py +0 -0
  52. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/ranking.py +0 -0
  53. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/recall.py +0 -0
  54. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/runner.py +0 -0
  55. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/store/__init__.py +0 -0
  56. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/store/ids.py +0 -0
  57. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/store/objects.py +0 -0
  58. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/tables.py +0 -0
  59. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/toggles.py +0 -0
  60. {research_git-0.0.3 → research_git-0.0.4}/src/rgit/watch.py +0 -0
  61. {research_git-0.0.3 → research_git-0.0.4}/tests/test_ablation.py +0 -0
  62. {research_git-0.0.3 → research_git-0.0.4}/tests/test_active_edges.py +0 -0
  63. {research_git-0.0.3 → research_git-0.0.4}/tests/test_compare.py +0 -0
  64. {research_git-0.0.3 → research_git-0.0.4}/tests/test_compose.py +0 -0
  65. {research_git-0.0.3 → research_git-0.0.4}/tests/test_db.py +0 -0
  66. {research_git-0.0.3 → research_git-0.0.4}/tests/test_edges.py +0 -0
  67. {research_git-0.0.3 → research_git-0.0.4}/tests/test_graphview.py +0 -0
  68. {research_git-0.0.3 → research_git-0.0.4}/tests/test_guidance_coupling.py +0 -0
  69. {research_git-0.0.3 → research_git-0.0.4}/tests/test_mcp_server.py +0 -0
  70. {research_git-0.0.3 → research_git-0.0.4}/tests/test_metricdir.py +0 -0
  71. {research_git-0.0.3 → research_git-0.0.4}/tests/test_metricdir_store.py +0 -0
  72. {research_git-0.0.3 → research_git-0.0.4}/tests/test_metrics.py +0 -0
  73. {research_git-0.0.3 → research_git-0.0.4}/tests/test_models.py +0 -0
  74. {research_git-0.0.3 → research_git-0.0.4}/tests/test_objects.py +0 -0
  75. {research_git-0.0.3 → research_git-0.0.4}/tests/test_provenance.py +0 -0
  76. {research_git-0.0.3 → research_git-0.0.4}/tests/test_ranking.py +0 -0
  77. {research_git-0.0.3 → research_git-0.0.4}/tests/test_recall.py +0 -0
  78. {research_git-0.0.3 → research_git-0.0.4}/tests/test_review_fixes.py +0 -0
  79. {research_git-0.0.3 → research_git-0.0.4}/tests/test_runner.py +0 -0
  80. {research_git-0.0.3 → research_git-0.0.4}/tests/test_tables.py +0 -0
  81. {research_git-0.0.3 → research_git-0.0.4}/tests/test_toggles.py +0 -0
  82. {research_git-0.0.3 → research_git-0.0.4}/tests/test_watch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: research-git
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Summary: A memory system that captures code ideas as semantic capsules you can regenerate onto today's codebase
5
5
  Author: Stepzero Lab
6
6
  License-Expression: MIT
@@ -43,15 +43,13 @@ Dynamic: license-file
43
43
  <strong>Git recovers history. It can't recover an entangled idea onto today's code.</strong>
44
44
  </p>
45
45
 
46
- ---
47
-
48
- **You're deep into building an agent. You've tried twenty things — a restructured system prompt, splitting one overloaded tool into three, a re-ranking step before retrieval, a scratchpad for intermediate reasoning, two different few-shot sets — half of them commented in and out, all tangled together in one working tree. Now you want *one* of those ideas back. Not the stale commit it lived in. The idea itself, re-applied to the agent you have today.**
49
-
50
- Git can't do that. Its unit is a *tree snapshot*, not an *idea*. `git checkout` drags back everything from that moment and throws away all the infrastructure you've built since. You can't pull one feature forward without rolling back the rest.
46
+ <p align="center">
47
+ <img src="assets/hero.png" alt="Capture a code idea as a clean semantic unit — regenerate it onto today's codebase." width="800" />
48
+ </p>
51
49
 
52
- research-git makes the **idea** the unit. It captures each change as a self-contained **Feature Capsule**, stores it in a graph, and — when you want it back — *regenerates* it onto your current code instead of pasting a stale patch. The capsule is a specification of intent; the code is always rebuilt against today's reality.
50
+ research-git captures experiments as Feature Capsules, then regenerates the one you need onto your current agent, using your existing Coding Plan subscription, no pay-per-use API.
53
51
 
54
- The intelligent steps (segmenting a diff into capsules, regenerating one onto changed code) run as **subagents on your existing Claude subscription** there is **no pay-per-use API** anywhere.
52
+ > **Think of it as Git for agentic coding experiments: not just recovering old code, but bringing old ideas back into today’s code.**
55
53
 
56
54
  ---
57
55
 
@@ -104,9 +102,9 @@ Five steps: install → init → run → capture → recall.
104
102
  pip install research-git # or, from a clone: pip install -e .
105
103
 
106
104
  # wire the plugin (agents + skills) and the MCP server into your client
107
- rgit install claude-code # Claude Code (via the official `claude` CLI)
108
- rgit install codex # Codex / Gemini / opencode: symlinks the skills into ~/.agents/skills/
109
- rgit install --list # all platforms; add --dry-run to preview, --uninstall to remove
105
+ rgit install # auto-detects every agent client on this machine and wires them all
106
+ rgit install claude-code # or pick one explicitly (claude-code / codex / gemini / opencode / generic)
107
+ rgit install --list # list platforms; --uninstall to remove
110
108
  ```
111
109
 
112
110
  `codex`, `gemini`, and `opencode` share the `~/.agents/skills/` convention — the installer symlinks each skill there and prints the one-line MCP server entry to drop into that client's config. It also writes a managed research-git guidance block into the client's global guidance file when the platform has one (`~/.codex/AGENTS.md`, `~/.claude/CLAUDE.md`, or `~/.gemini/GEMINI.md`). On an interactive terminal you're asked how proactive capture should be — `default`, `manual-only`, or `none`; pass `--guidance <mode>` to choose non-interactively. Start a new agent session after install so the guidance is loaded. Prefer the manual route on Claude Code? `/plugin marketplace add StepzeroLab/research-git` then `/plugin install research-git@research-git`.
@@ -118,6 +116,14 @@ cd your-project
118
116
  rgit init # creates .rgit/ (the store) at the git root
119
117
  ```
120
118
 
119
+ **Optional — capture on every commit.** `rgit install <platform>` wires the agent side only; it deliberately does **not** touch your git hooks. If you also want every `git commit` to stage its own diff as a pending proposal automatically, opt in with:
120
+
121
+ ```bash
122
+ rgit install-hooks # adds a post-commit hook (never clobbers an existing one)
123
+ ```
124
+
125
+ Good fit: solo research repos where you want nothing to slip through, even when you forget to capture. Skip it if the repo already has its own post-commit hook (the installer refuses to touch foreign hooks, so nothing breaks — it just won't install), if your team prefers deliberate manual capture, or in CI/shared clones where commit-time side effects are unwelcome. Without hooks you lose nothing: bare `rgit capture` takes the last commit when the tree is clean, `rgit capture A..B` a whole span, and `rgit review` is the gate either way — hooks only stage proposals, they never approve anything. Remove with `rgit install-hooks --uninstall`.
126
+
121
127
  ### 3. Run a variation and capture the idea
122
128
 
123
129
  Launch your work through `rgit run` — it executes your command, freezes a reproducible artifact, records the run + any metrics, and stages what changed:
@@ -134,6 +140,8 @@ rgit review # list proposals
134
140
  rgit review --approve <proposal_id> --name rerank-retrieval
135
141
  ```
136
142
 
143
+ Committed before capturing? Just run `rgit capture` — on a clean tree it captures the last commit (and says which one); `rgit capture main..HEAD` takes a whole span. (With the optional post-commit hook installed, every commit stages itself automatically.)
144
+
137
145
  ### 4. Bring an idea back onto today's code
138
146
 
139
147
  Weeks later, after the agent has moved on:
@@ -198,7 +206,8 @@ The five-step loop above is the core. These show up as your store grows — run
198
206
  | Command | What it does |
199
207
  |---------|--------------|
200
208
  | `rgit watch` | free, deterministic background capture — stages raw material as you edit, so fleeting in-between states aren't lost |
201
- | `rgit install-hooks` | stage on every commit via a post-commit hook (won't touch an existing hook) |
209
+ | `rgit capture [REV \| A..B]` | bare: auto-picks the working tree or, when clean, the last commit; pass a commit or an A..B range for precise control |
210
+ | `rgit install-hooks` | opt-in: stage every commit's diff via a post-commit hook (not installed by `rgit install`; won't touch an existing hook) — see step 2 above |
202
211
  | `rgit run --from <capsule>` | run a recalled variant and link the new run as a `variant_of` the original |
203
212
  | `rgit compare <query>` | which variant won: ranked table, Δ vs baseline, ★ winner |
204
213
  | `rgit provenance <run_id>` | per-feature clean (capsule) vs agent-adapted (frozen) diff for a run |
@@ -17,15 +17,13 @@
17
17
  <strong>Git recovers history. It can't recover an entangled idea onto today's code.</strong>
18
18
  </p>
19
19
 
20
- ---
21
-
22
- **You're deep into building an agent. You've tried twenty things — a restructured system prompt, splitting one overloaded tool into three, a re-ranking step before retrieval, a scratchpad for intermediate reasoning, two different few-shot sets — half of them commented in and out, all tangled together in one working tree. Now you want *one* of those ideas back. Not the stale commit it lived in. The idea itself, re-applied to the agent you have today.**
23
-
24
- Git can't do that. Its unit is a *tree snapshot*, not an *idea*. `git checkout` drags back everything from that moment and throws away all the infrastructure you've built since. You can't pull one feature forward without rolling back the rest.
20
+ <p align="center">
21
+ <img src="assets/hero.png" alt="Capture a code idea as a clean semantic unit — regenerate it onto today's codebase." width="800" />
22
+ </p>
25
23
 
26
- research-git makes the **idea** the unit. It captures each change as a self-contained **Feature Capsule**, stores it in a graph, and — when you want it back — *regenerates* it onto your current code instead of pasting a stale patch. The capsule is a specification of intent; the code is always rebuilt against today's reality.
24
+ research-git captures experiments as Feature Capsules, then regenerates the one you need onto your current agent, using your existing Coding Plan subscription, no pay-per-use API.
27
25
 
28
- The intelligent steps (segmenting a diff into capsules, regenerating one onto changed code) run as **subagents on your existing Claude subscription** there is **no pay-per-use API** anywhere.
26
+ > **Think of it as Git for agentic coding experiments: not just recovering old code, but bringing old ideas back into today’s code.**
29
27
 
30
28
  ---
31
29
 
@@ -78,9 +76,9 @@ Five steps: install → init → run → capture → recall.
78
76
  pip install research-git # or, from a clone: pip install -e .
79
77
 
80
78
  # wire the plugin (agents + skills) and the MCP server into your client
81
- rgit install claude-code # Claude Code (via the official `claude` CLI)
82
- rgit install codex # Codex / Gemini / opencode: symlinks the skills into ~/.agents/skills/
83
- rgit install --list # all platforms; add --dry-run to preview, --uninstall to remove
79
+ rgit install # auto-detects every agent client on this machine and wires them all
80
+ rgit install claude-code # or pick one explicitly (claude-code / codex / gemini / opencode / generic)
81
+ rgit install --list # list platforms; --uninstall to remove
84
82
  ```
85
83
 
86
84
  `codex`, `gemini`, and `opencode` share the `~/.agents/skills/` convention — the installer symlinks each skill there and prints the one-line MCP server entry to drop into that client's config. It also writes a managed research-git guidance block into the client's global guidance file when the platform has one (`~/.codex/AGENTS.md`, `~/.claude/CLAUDE.md`, or `~/.gemini/GEMINI.md`). On an interactive terminal you're asked how proactive capture should be — `default`, `manual-only`, or `none`; pass `--guidance <mode>` to choose non-interactively. Start a new agent session after install so the guidance is loaded. Prefer the manual route on Claude Code? `/plugin marketplace add StepzeroLab/research-git` then `/plugin install research-git@research-git`.
@@ -92,6 +90,14 @@ cd your-project
92
90
  rgit init # creates .rgit/ (the store) at the git root
93
91
  ```
94
92
 
93
+ **Optional — capture on every commit.** `rgit install <platform>` wires the agent side only; it deliberately does **not** touch your git hooks. If you also want every `git commit` to stage its own diff as a pending proposal automatically, opt in with:
94
+
95
+ ```bash
96
+ rgit install-hooks # adds a post-commit hook (never clobbers an existing one)
97
+ ```
98
+
99
+ Good fit: solo research repos where you want nothing to slip through, even when you forget to capture. Skip it if the repo already has its own post-commit hook (the installer refuses to touch foreign hooks, so nothing breaks — it just won't install), if your team prefers deliberate manual capture, or in CI/shared clones where commit-time side effects are unwelcome. Without hooks you lose nothing: bare `rgit capture` takes the last commit when the tree is clean, `rgit capture A..B` a whole span, and `rgit review` is the gate either way — hooks only stage proposals, they never approve anything. Remove with `rgit install-hooks --uninstall`.
100
+
95
101
  ### 3. Run a variation and capture the idea
96
102
 
97
103
  Launch your work through `rgit run` — it executes your command, freezes a reproducible artifact, records the run + any metrics, and stages what changed:
@@ -108,6 +114,8 @@ rgit review # list proposals
108
114
  rgit review --approve <proposal_id> --name rerank-retrieval
109
115
  ```
110
116
 
117
+ Committed before capturing? Just run `rgit capture` — on a clean tree it captures the last commit (and says which one); `rgit capture main..HEAD` takes a whole span. (With the optional post-commit hook installed, every commit stages itself automatically.)
118
+
111
119
  ### 4. Bring an idea back onto today's code
112
120
 
113
121
  Weeks later, after the agent has moved on:
@@ -172,7 +180,8 @@ The five-step loop above is the core. These show up as your store grows — run
172
180
  | Command | What it does |
173
181
  |---------|--------------|
174
182
  | `rgit watch` | free, deterministic background capture — stages raw material as you edit, so fleeting in-between states aren't lost |
175
- | `rgit install-hooks` | stage on every commit via a post-commit hook (won't touch an existing hook) |
183
+ | `rgit capture [REV \| A..B]` | bare: auto-picks the working tree or, when clean, the last commit; pass a commit or an A..B range for precise control |
184
+ | `rgit install-hooks` | opt-in: stage every commit's diff via a post-commit hook (not installed by `rgit install`; won't touch an existing hook) — see step 2 above |
176
185
  | `rgit run --from <capsule>` | run a recalled variant and link the new run as a `variant_of` the original |
177
186
  | `rgit compare <query>` | which variant won: ranked table, Δ vs baseline, ★ winner |
178
187
  | `rgit provenance <run_id>` | per-feature clean (capsule) vs agent-adapted (frozen) diff for a run |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "research-git"
3
- version = "0.0.3"
3
+ version = "0.0.4"
4
4
  description = "A memory system that captures code ideas as semantic capsules you can regenerate onto today's codebase"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: research-git
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Summary: A memory system that captures code ideas as semantic capsules you can regenerate onto today's codebase
5
5
  Author: Stepzero Lab
6
6
  License-Expression: MIT
@@ -43,15 +43,13 @@ Dynamic: license-file
43
43
  <strong>Git recovers history. It can't recover an entangled idea onto today's code.</strong>
44
44
  </p>
45
45
 
46
- ---
47
-
48
- **You're deep into building an agent. You've tried twenty things — a restructured system prompt, splitting one overloaded tool into three, a re-ranking step before retrieval, a scratchpad for intermediate reasoning, two different few-shot sets — half of them commented in and out, all tangled together in one working tree. Now you want *one* of those ideas back. Not the stale commit it lived in. The idea itself, re-applied to the agent you have today.**
49
-
50
- Git can't do that. Its unit is a *tree snapshot*, not an *idea*. `git checkout` drags back everything from that moment and throws away all the infrastructure you've built since. You can't pull one feature forward without rolling back the rest.
46
+ <p align="center">
47
+ <img src="assets/hero.png" alt="Capture a code idea as a clean semantic unit — regenerate it onto today's codebase." width="800" />
48
+ </p>
51
49
 
52
- research-git makes the **idea** the unit. It captures each change as a self-contained **Feature Capsule**, stores it in a graph, and — when you want it back — *regenerates* it onto your current code instead of pasting a stale patch. The capsule is a specification of intent; the code is always rebuilt against today's reality.
50
+ research-git captures experiments as Feature Capsules, then regenerates the one you need onto your current agent, using your existing Coding Plan subscription, no pay-per-use API.
53
51
 
54
- The intelligent steps (segmenting a diff into capsules, regenerating one onto changed code) run as **subagents on your existing Claude subscription** there is **no pay-per-use API** anywhere.
52
+ > **Think of it as Git for agentic coding experiments: not just recovering old code, but bringing old ideas back into today’s code.**
55
53
 
56
54
  ---
57
55
 
@@ -104,9 +102,9 @@ Five steps: install → init → run → capture → recall.
104
102
  pip install research-git # or, from a clone: pip install -e .
105
103
 
106
104
  # wire the plugin (agents + skills) and the MCP server into your client
107
- rgit install claude-code # Claude Code (via the official `claude` CLI)
108
- rgit install codex # Codex / Gemini / opencode: symlinks the skills into ~/.agents/skills/
109
- rgit install --list # all platforms; add --dry-run to preview, --uninstall to remove
105
+ rgit install # auto-detects every agent client on this machine and wires them all
106
+ rgit install claude-code # or pick one explicitly (claude-code / codex / gemini / opencode / generic)
107
+ rgit install --list # list platforms; --uninstall to remove
110
108
  ```
111
109
 
112
110
  `codex`, `gemini`, and `opencode` share the `~/.agents/skills/` convention — the installer symlinks each skill there and prints the one-line MCP server entry to drop into that client's config. It also writes a managed research-git guidance block into the client's global guidance file when the platform has one (`~/.codex/AGENTS.md`, `~/.claude/CLAUDE.md`, or `~/.gemini/GEMINI.md`). On an interactive terminal you're asked how proactive capture should be — `default`, `manual-only`, or `none`; pass `--guidance <mode>` to choose non-interactively. Start a new agent session after install so the guidance is loaded. Prefer the manual route on Claude Code? `/plugin marketplace add StepzeroLab/research-git` then `/plugin install research-git@research-git`.
@@ -118,6 +116,14 @@ cd your-project
118
116
  rgit init # creates .rgit/ (the store) at the git root
119
117
  ```
120
118
 
119
+ **Optional — capture on every commit.** `rgit install <platform>` wires the agent side only; it deliberately does **not** touch your git hooks. If you also want every `git commit` to stage its own diff as a pending proposal automatically, opt in with:
120
+
121
+ ```bash
122
+ rgit install-hooks # adds a post-commit hook (never clobbers an existing one)
123
+ ```
124
+
125
+ Good fit: solo research repos where you want nothing to slip through, even when you forget to capture. Skip it if the repo already has its own post-commit hook (the installer refuses to touch foreign hooks, so nothing breaks — it just won't install), if your team prefers deliberate manual capture, or in CI/shared clones where commit-time side effects are unwelcome. Without hooks you lose nothing: bare `rgit capture` takes the last commit when the tree is clean, `rgit capture A..B` a whole span, and `rgit review` is the gate either way — hooks only stage proposals, they never approve anything. Remove with `rgit install-hooks --uninstall`.
126
+
121
127
  ### 3. Run a variation and capture the idea
122
128
 
123
129
  Launch your work through `rgit run` — it executes your command, freezes a reproducible artifact, records the run + any metrics, and stages what changed:
@@ -134,6 +140,8 @@ rgit review # list proposals
134
140
  rgit review --approve <proposal_id> --name rerank-retrieval
135
141
  ```
136
142
 
143
+ Committed before capturing? Just run `rgit capture` — on a clean tree it captures the last commit (and says which one); `rgit capture main..HEAD` takes a whole span. (With the optional post-commit hook installed, every commit stages itself automatically.)
144
+
137
145
  ### 4. Bring an idea back onto today's code
138
146
 
139
147
  Weeks later, after the agent has moved on:
@@ -198,7 +206,8 @@ The five-step loop above is the core. These show up as your store grows — run
198
206
  | Command | What it does |
199
207
  |---------|--------------|
200
208
  | `rgit watch` | free, deterministic background capture — stages raw material as you edit, so fleeting in-between states aren't lost |
201
- | `rgit install-hooks` | stage on every commit via a post-commit hook (won't touch an existing hook) |
209
+ | `rgit capture [REV \| A..B]` | bare: auto-picks the working tree or, when clean, the last commit; pass a commit or an A..B range for precise control |
210
+ | `rgit install-hooks` | opt-in: stage every commit's diff via a post-commit hook (not installed by `rgit install`; won't touch an existing hook) — see step 2 above |
202
211
  | `rgit run --from <capsule>` | run a recalled variant and link the new run as a `variant_of` the original |
203
212
  | `rgit compare <query>` | which variant won: ranked table, Δ vs baseline, ★ winner |
204
213
  | `rgit provenance <run_id>` | per-feature clean (capsule) vs agent-adapted (frozen) diff for a run |
@@ -26,9 +26,12 @@ Every `agents/<name>.md` reference below (`agents/capsule-segmenter.md`, `agents
26
26
  If the user just made changes and there is no open proposal yet, create one:
27
27
 
28
28
  ```
29
- rgit capture --trigger manual
29
+ rgit capture # picks for you: uncommitted work, or the last commit when the tree is clean
30
+ rgit capture main..HEAD # a specific span of commits (any A..B range)
30
31
  ```
31
32
 
33
+ The bare form auto-picks its source, so it works the same before or after a `git commit`; repeated captures of the same diff dedup into the existing proposal. If the repo has the post-commit hook installed (`rgit install-hooks`), each commit is captured automatically; don't capture the same commit twice.
34
+
32
35
  This runs the libcst symbol mapping + the free heuristic, producing one or more open proposals with a raw diff and a crude candidate. Proposals also appear automatically from `rgit run`, the post-commit hook, and the `rgit watch` daemon.
33
36
 
34
37
  ### 2. Read the pending captures
@@ -45,14 +45,22 @@ def render_global_block(mode: str = "default") -> str:
45
45
  "- Do not write repo preferences for one-off session instructions.\n"
46
46
  "\n"
47
47
  "Use:\n"
48
- "- After meaningful code/research changes, consider "
49
- "`rgit capture --trigger manual` and the `rgit-capture` skill.\n"
48
+ "- After meaningful code/research changes, run `rgit capture` — it "
49
+ "captures uncommitted work, or the last commit when the tree is "
50
+ "clean, so committing first is fine. Then use the `rgit-capture` "
51
+ "skill to segment.\n"
52
+ "- For a specific span of commits: `rgit capture main..HEAD` (any "
53
+ "A..B range works).\n"
54
+ "- If a post-commit hook is installed (`rgit install-hooks`), commits "
55
+ "are captured automatically; do not capture the same commit again.\n"
56
+ "- Skip mechanical formatting, dependency churn, generated files, or "
57
+ "changes with no reusable research/code idea.\n"
50
58
  "- For recall/resurrection requests, use the `rgit-recall` skill.\n"
51
59
  "- If `.rgit/` is missing in a git repo: when operating autonomously "
52
- "(no human to ask), bootstrap the store with `rgit capture --init "
53
- "--trigger manual` (store only — never install hooks unless asked); in "
54
- "an interactive session, tell the user to run `rgit init` rather than "
55
- "initializing silently.\n"
60
+ "(no human to ask), bootstrap the store with `rgit capture --init` "
61
+ "(store only — never install hooks unless asked); in an interactive "
62
+ "session, tell the user to run `rgit init` rather than initializing "
63
+ "silently.\n"
56
64
  "- In final feedback, mention any capsules created, approved, applied, "
57
65
  "or skipped, plus important graph relations.\n"
58
66
  f"{END}\n"
@@ -1,34 +1,16 @@
1
1
  from __future__ import annotations
2
2
  import re
3
3
  from pathlib import Path
4
- from typing import Optional
4
+ from typing import Callable, Optional
5
5
 
6
6
  import libcst as cst
7
7
  from libcst.metadata import MetadataWrapper, PositionProvider
8
8
 
9
- from .gitutil import _within, parse_git_diff_header
9
+ from .gitutil import parse_git_diff_header, read_worktree_python
10
10
 
11
11
  _HUNK = re.compile(r"^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@", re.M)
12
12
 
13
13
 
14
- def _read_python_source(path: Path) -> str:
15
- """Read a .py file for parsing. ``utf-8-sig`` strips a UTF-8 BOM (common on
16
- Windows-authored files) that would otherwise make libcst miss the first
17
- symbol — and it also reads plain UTF-8 unchanged."""
18
- return path.read_text(encoding="utf-8-sig")
19
-
20
-
21
- def _python_source_path(repo: Path, file: str) -> Optional[Path]:
22
- """Repo-contained regular Python file, without following external symlinks."""
23
- path = repo / file
24
- if path.suffix != ".py" or not _within(repo, path):
25
- return None
26
- try:
27
- return path if path.is_file() else None
28
- except OSError:
29
- return None
30
-
31
-
32
14
  def _changed_line_ranges(diff: str) -> dict[str, list[tuple[int, int]]]:
33
15
  """file -> list of (start, end) ranges of *actually changed* new-side lines.
34
16
 
@@ -99,15 +81,28 @@ class _SymbolFinder(cst.CSTVisitor):
99
81
  self.found.add(node.name.value)
100
82
 
101
83
 
102
- def changed_symbols(diff: str, repo: Path) -> list[dict]:
103
- """[{file, symbol}] for each top-level def/class overlapping a diff hunk."""
84
+ def changed_symbols(diff: str, repo: Path,
85
+ read_source: Optional[Callable[[str], Optional[str]]] = None,
86
+ ) -> list[dict]:
87
+ """[{file, symbol}] for each top-level def/class overlapping a diff hunk.
88
+
89
+ `read_source(file)` supplies the new-side source text (None skips the
90
+ file); the default reads the working tree. Committed-diff capture passes a
91
+ reader pinned to the captured commit, so symbol mapping cannot drift when
92
+ the worktree has moved past — or never matched — the diff being segmented
93
+ (e.g. a partially staged commit).
94
+ """
95
+ if read_source is None:
96
+ read_source = lambda file: read_worktree_python(repo, file) # noqa: E731
104
97
  out: list[dict] = []
105
98
  for file, ranges in _changed_line_ranges(diff).items():
106
- path = _python_source_path(repo, file)
107
- if path is None or not ranges:
99
+ if not ranges:
100
+ continue
101
+ text = read_source(file)
102
+ if text is None:
108
103
  continue
109
104
  try:
110
- wrapper = MetadataWrapper(cst.parse_module(_read_python_source(path)))
105
+ wrapper = MetadataWrapper(cst.parse_module(text))
111
106
  except (cst.ParserSyntaxError, UnicodeDecodeError):
112
107
  continue
113
108
  finder = _SymbolFinder(ranges)
@@ -119,11 +114,11 @@ def changed_symbols(diff: str, repo: Path) -> list[dict]:
119
114
 
120
115
  def read_symbol_source(repo: Path, file: str, symbol: str) -> Optional[str]:
121
116
  """Current source text of a top-level def/class, or None if absent."""
122
- path = _python_source_path(repo, file)
123
- if path is None:
117
+ text = read_worktree_python(repo, file)
118
+ if text is None:
124
119
  return None
125
120
  try:
126
- module = cst.parse_module(_read_python_source(path))
121
+ module = cst.parse_module(text)
127
122
  except (cst.ParserSyntaxError, UnicodeDecodeError):
128
123
  return None
129
124
  for stmt in module.body:
@@ -134,11 +129,11 @@ def read_symbol_source(repo: Path, file: str, symbol: str) -> Optional[str]:
134
129
 
135
130
  def symbol_at_line(repo: Path, file: str, line: int) -> Optional[str]:
136
131
  """Name of the top-level def/class enclosing `line` (1-based), or None."""
137
- path = _python_source_path(repo, file)
138
- if path is None:
132
+ text = read_worktree_python(repo, file)
133
+ if text is None:
139
134
  return None
140
135
  try:
141
- wrapper = MetadataWrapper(cst.parse_module(_read_python_source(path)))
136
+ wrapper = MetadataWrapper(cst.parse_module(text))
142
137
  except (cst.ParserSyntaxError, UnicodeDecodeError):
143
138
  return None
144
139
  finder = _SymbolFinder([(line, line)])