Skip to content

Commit 26b24ee

Browse files
authored
v0.8.3: drift maintenance + RPG-first tool preference + sub-agent dispatch
Third RPG release cycle. Focus: (a) make RPG the default reach for LLM agents on any structural code question (instead of grep/cat/find), (b) harden the lifting pipeline against drift when code changes, (c) add runtime-neutral sub-agent dispatch guidance so large repos don't burn caller context. ## Highlights - `stale_entity_ids` drift tracking on `RpgServer` — populated on auto-sync, drained on re-lift, surfaced in `lifting_status`. Closes the "coverage 100% but features outdated" silent-failure mode. - `build_rpg` + `lifting_status` + `get_entities_for_lifting` + `submit_lift_results` all compose coherently for a stale-only re-lift flow. No more dead-end recipes. - `build_rpg` response now actively directs the agent to lift immediately, scale-aware (small = foreground, large = dispatch sub-agent). - `USE RPG FIRST` mapping table in server prompt, tool descriptions, SKILL.md, README — agents see the RPG-before-grep directive at every touchpoint. - Runtime-neutral dispatch guidance — no Claude-Code-specific `Task()` syntax leaking into the MCP layer. - Canonical lock-order invariant documented on `RpgServer`, every nested-lock site audited. ## Audit trail Nine review rounds: six by Codex, two by independent Opus 4.6 agents, one final verification pass. Final state: no HIGH or MEDIUM findings open. See CHANGELOG.md for the full v0.8.3 entry.
1 parent a2782ec commit 26b24ee

15 files changed

Lines changed: 1033 additions & 145 deletions

File tree

.claude/skills/rpg/SKILL.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,37 @@
11
---
22
name: rpg
3-
description: 'Build and query semantic code graphs using RPG-Encoder. Use when the user wants to understand codebase structure, search for code by intent, explore dependencies, analyze change impact, or perform semantic lifting.'
3+
description: 'Build and query semantic code graphs using RPG-Encoder. Use BEFORE grep/cat/find for any question about code structure, behavior, relationships, impact, dependencies, or cross-file patterns.'
44
allowed-tools: Bash(rpg-encoder *), Read, Glob, Grep
55
---
66

7-
# RPG-Encoder CLI Skill
7+
# RPG-Encoder — USE BEFORE grep/cat/find
8+
9+
## Reach for RPG first, shell commands second
10+
11+
Whenever the user asks about code structure, behavior, relationships, impact,
12+
dependencies, or cross-file patterns, reach for RPG commands BEFORE falling
13+
back to `grep`, `cat`, `find`, `wc`, or `Read`. RPG is indexed, semantically
14+
organized, and answers structural questions in one call that would otherwise
15+
require dozens of chained text searches.
16+
17+
| If you'd otherwise... | Use this instead |
18+
|---|---|
19+
| `grep -r` by intent | `rpg-encoder search "describe what it does"` |
20+
| `grep -r` by name | `rpg-encoder search "name" --mode snippets` |
21+
| `cat file` for a function | `rpg-encoder fetch "file:func"` |
22+
| chained greps for callers | `rpg-encoder explore ENTITY --direction up` |
23+
| chained greps for callees | `rpg-encoder explore ENTITY --direction down` |
24+
| `wc -l` / `find` / `tree` | `rpg-encoder info` |
25+
| reading many files | Use the MCP `semantic_snapshot` tool if available |
26+
27+
Fall back to `grep` / `cat` / `Read` only when the query is about literal text
28+
(string search, comments, TODOs, log messages) — not structure or semantics.
29+
30+
If you have the RPG MCP server connected, prefer its tools (`search_node`,
31+
`fetch_node`, `explore_rpg`, `impact_radius`, `plan_change`, `semantic_snapshot`,
32+
`context_pack`) over the CLI — they're faster and return structured data.
33+
34+
---
835

936
You have access to `rpg-encoder`, a CLI tool that builds semantic code graphs (Repository Planning Graphs) from any codebase. Use it to understand code structure, search by intent, trace dependencies, and perform autonomous semantic lifting.
1037

.gemini/extensions/rpg/CONTEXT.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@
22

33
RPG-Encoder builds semantic code graphs (Repository Planning Graphs) for AI-assisted code understanding.
44

5+
## Use RPG before grep / cat / find
6+
7+
For any question about code structure, behavior, relationships, impact, or
8+
cross-file patterns, reach for RPG tools (MCP or CLI) before shell commands.
9+
RPG answers structural questions in one call that would otherwise require
10+
dozens of chained text searches.
11+
12+
Fall back to grep / cat / file reads only when the query is about literal
13+
text (string search, comments, TODOs, log messages).
14+
15+
See the MCP server instructions for the full mapping of shell patterns to
16+
RPG tools — it's loaded automatically when the extension is active.
17+
518
## CLI Commands
619

720
- `rpg-encoder build` — Index codebase, build graph (run once)

.gemini/extensions/rpg/commands/rpg-lift.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@ The lift pipeline:
1818
1919
Progress is saved after each batch. If interrupted, re-running continues from where it stopped.
2020
21-
After completion, run `rpg-encoder info` to show the updated graph statistics.
21+
After completion, run `rpg-encoder info` to show the updated graph statistics. If an MCP RPG server is currently connected to your editor, also call its `reload_rpg` tool so it picks up the new graph from disk.
2222
"""

.gemini/extensions/rpg/gemini-extension.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rpg-encoder",
3-
"version": "0.8.2",
3+
"version": "0.8.3",
44
"description": "Build and query semantic code graphs (Repository Planning Graphs) for AI-assisted code understanding. Provides entity search, dependency exploration, and autonomous LLM-driven semantic lifting.",
55
"mcpServers": {
66
"rpg-encoder": {

CHANGELOG.md

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,185 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/),
66
and this project adheres to [Semantic Versioning](https://semver.org/).
77

8+
## [0.8.3] - 2026-04-14
9+
10+
### Added
11+
12+
- `lifting_status` now tracks stale-feature drift across calls. A
13+
persistent per-server set records entities whose source was modified
14+
after they were lifted; the dashboard reports `stale_features: N
15+
entities modified since last lift` and the NEXT STEP state machine
16+
prompts re-lift even when coverage is 100%.
17+
- `get_entities_for_lifting(scope="*")` now returns stale entities
18+
alongside unlifted ones, so a single call covers both "never lifted"
19+
and "lifted-but-outdated" work.
20+
- `lifting_status` emits a sub-agent dispatch recommendation when the
21+
remaining work (unlifted + stale) is ≥100 entities. The response
22+
contains `LOOP` / `DISPATCH` / `FALLBACK` blocks so callers delegate
23+
directly without first loading a batch of source into their own
24+
context.
25+
- `get_entities_for_lifting` batch-0 emits a one-line dispatch hint
26+
when ≥10 token-aware batches are queued, pointing back to
27+
`lifting_status` for the full recommendation.
28+
- `submit_lift_results` NEXT action is now scale-aware — when remaining
29+
work ≥100 entities, it redirects the caller to `lifting_status`
30+
instead of encouraging another foreground batch.
31+
- `build_rpg` response now emits an action-oriented NEXT STEP directing
32+
the agent to lift immediately. Small scope lifts inline; large scope
33+
dispatches a sub-agent with the LOOP pattern embedded.
34+
- New `USE RPG FIRST` top section in `server_instructions.md` with a
35+
mapping table from shell patterns (`grep -r`, `cat`, `find`, `wc -l`,
36+
chained greps) to the RPG tool that replaces them.
37+
- New `DRIFT MAINTENANCE` section in `server_instructions.md`
38+
explaining the three auto-sync notice variants and framing re-lift
39+
as part of definition-of-done for any task that wrote code.
40+
- Tool descriptions for `search_node`, `fetch_node`, `explore_rpg`,
41+
`rpg_info`, `semantic_snapshot`, `context_pack`, `impact_radius`,
42+
`plan_change`, `analyze_health`, `detect_cycles`, `find_paths`, and
43+
`slice_between` now open with a `PREFER THIS OVER ...` marker naming
44+
the shell command or workflow they replace.
45+
- `.claude/skills/rpg/SKILL.md` and `README.md` carry the same
46+
RPG-first mapping table as the server prompt.
47+
- Crate-visible `LARGE_SCOPE_ENTITIES` (100) and `LARGE_SCOPE_BATCHES`
48+
(10) constants replace duplicated magic numbers across
49+
`server.rs`/`tools.rs` with doc comments describing the
50+
heuristic-vs-authoritative relationship.
51+
- Canonical lock-order invariant documented on the `RpgServer` struct
52+
so reviewers don't have to re-derive it from scattered call sites.
53+
- `reload_config_with_warning` helper on `RpgServer` that distinguishes
54+
missing `.rpg/config.toml` (silent default) from malformed TOML
55+
(stderr warning, keeps previous in-memory config).
56+
57+
### Changed
58+
59+
- `lifting_status` NEXT STEP is runtime-neutral. No specific runtime's
60+
dispatch syntax appears in the response; callers use whatever
61+
sub-agent or cheaper-model mechanism their runtime exposes. Explicit
62+
fallbacks: scoped lifting for callers with no delegation mechanism,
63+
and `rpg-encoder lift --provider anthropic|openai` for callers with
64+
an API key and no sub-agent support.
65+
- Batch-size estimates in NEXT STEP messages read from the live
66+
`encoding.max_batch_tokens` config instead of a hard-coded `~12K`
67+
figure, so the estimate scales when the user overrides the budget.
68+
- `NEXT STEP:` remains a single parseable line; dispatch detail is
69+
emitted in labeled blocks immediately below.
70+
- Auto-sync notice now prescribes a verb: it distinguishes per-update
71+
delta from pre-existing backlog and separates new-entity drift from
72+
stale-feature drift, so an agent that commits code and sees the
73+
notice is told to re-lift rather than informed of a count.
74+
- CLI fallback in large-scope guidance is gated to cases with actual
75+
unlifted work, with a note that `rpg-encoder lift` does not re-lift
76+
stale entities (it filters to entities with no features).
77+
- `get_routing_candidates` response header no longer includes the
78+
graph revision hash — it moved to the NEXT_ACTION block at the
79+
bottom. Keeps the stable preamble (instructions + entity table)
80+
cache-eligible while still surfacing the revision where the agent
81+
needs to read it back.
82+
- `server_instructions.md` LIFTING FLOW sub-section rewritten and
83+
shortened.
84+
- `set_project_root` on project switch now loads the new project's
85+
`.rpg/config.toml` independently; on parse failure it falls back to
86+
`RpgConfig::default()` rather than preserving the previous project's
87+
config. Same-project `reload_rpg` preserves the previous config on
88+
parse failure (different flow, different correctness requirement).
89+
90+
### Fixed
91+
92+
- `lifting_status` previously reported `Graph is complete` as soon as
93+
every entity had some features, ignoring stale features from
94+
modified sources. The state machine now considers
95+
`remaining + stale_features` combined.
96+
- `get_entities_for_lifting(scope="*")` previously returned zero
97+
entities when all drift was stale (features present, sources
98+
modified) because `resolve_scope` filters to entities with no
99+
features. It now augments the resolved scope with tracked stale
100+
entities and routes them through the LLM loop.
101+
- Auto-sync notice previously conflated per-update delta with global
102+
backlog, so a one-line edit on a partially-lifted repo could claim
103+
"50 new entities unlifted" when only 1 was actually new.
104+
- `finalize_lifting` fallback guidance previously said to call it
105+
after each scoped subtree. That auto-routes pending entities
106+
against incomplete signals and locks the hierarchy early. Guidance
107+
now says to call `finalize_lifting` once after all scopes complete.
108+
- `rpg-encoder lift --provider ...` (CLI fallback) left the MCP
109+
server on a stale in-memory graph. All docs that mention the CLI
110+
fallback now specify that the caller must call `reload_rpg`
111+
afterward.
112+
- `set_project_root` and `reload_rpg` previously used
113+
`unwrap_or_default()` on config loads, collapsing missing-config
114+
and malformed-TOML into identical silent behavior.
115+
- `set_project_root` failed to refresh `self.config` on project
116+
switch; the server kept serving the previous project's encoding
117+
settings.
118+
- `lifting_status` large-scope recommendation previously ran off raw
119+
unlifted count, before auto-lift had reduced the set. On repos full
120+
of trivial entities (getters, setters, constructors) it could
121+
recommend delegation for ~0 LLM calls. The large-scope branch now
122+
signals likely-large and defers the authoritative check to the
123+
post-auto-lift batch count in `get_entities_for_lifting`.
124+
- `rpg_info` error wording ("No RPG found") was miscited as a
125+
friendly status string; corrected to "any RPG tool returns 'No RPG
126+
found'".
127+
- `build_rpg` NEXT STEP and `lifted: X/Y` header previously counted
128+
`Module` entities against the unlifted total, while
129+
`lifting_status` and `get_entities_for_lifting` exclude them. The
130+
two could disagree by hundreds of entities on large codebases,
131+
tripping the delegation threshold in `build_rpg` when
132+
`lifting_status` would still recommend foreground lifting. Both
133+
paths now use `lifting_coverage()` (non-module) for the count, and
134+
the header reads `liftable_entities: X/Y`.
135+
- `submit_lift_results` previously emitted `DONE` as soon as coverage
136+
reached 100%, which could terminate a stale-only re-lift loop after
137+
batch 1 while later batches were still queued. The NEXT/DONE
138+
branch now counts unlifted + stale remaining.
139+
- `update_rpg` now feeds `summary.modified_entity_ids` into the
140+
stale-tracking set so its `needs_relift: N` reply aligns with what
141+
`lifting_status` and `get_entities_for_lifting(scope="*")` report.
142+
- Server startup auto-update now feeds `modified_entity_ids` into
143+
the stale-tracking set and seeds the auto-sync changeset hash for a
144+
clean workdir. Previously modifications between the last lift and
145+
a session restart silently dropped off the dashboard.
146+
- `auto_lift` on a non-`*` scope now drains stale entries for every
147+
in-scope entity. The pipeline freshens features for each
148+
regardless of existing state, so stale markers for those IDs are
149+
invalid after the call; the unconditional drain also handles the
150+
identical-features case where a cosmetic edit re-lifts to the
151+
same output.
152+
- Auto-lifted features for entities previously flagged stale now
153+
drain the stale-tracking set inline in
154+
`get_entities_for_lifting`, so the count doesn't inflate when the
155+
auto-lifter writes fresh features directly.
156+
- `reload_rpg` now prunes the stale-tracking set against the newly
157+
loaded graph rather than clearing it wholesale. The CLI / isolated
158+
sub-agent re-lift flow only refreshes entities with no features —
159+
stale entities survive it, so clearing would let `lifting_status`
160+
report 100% coverage while re-lift work remained.
161+
- `reload_rpg` drift-tracking reset now sits on the success path,
162+
after `storage::load` returns `Ok`. Transient read errors no longer
163+
wipe the backlog while leaving the previous graph in memory.
164+
- `build_rpg` now prunes the stale-tracking set against the newly
165+
built graph so dead entity IDs don't accumulate across rebuilds.
166+
- `build_semantic_hierarchy` sharded init no longer acquires
167+
`hierarchy_session.write()` before `graph.read()`. The original
168+
order formed a deadlock cycle with `update_rpg`'s
169+
graph-then-session order under concurrent scheduling. The init
170+
path now collapses decision + snapshot into a single
171+
`hierarchy_session.write()` held under `graph.read()` and packages
172+
the work into an `Action` enum so there's no peek-then-trust.
173+
- `build_batch_0_domain_discovery` and `build_cluster_batch` now take
174+
`&RPGraph` and (where applicable) clusters as parameters instead
175+
of re-reading `self.graph` / `self.hierarchy_session`. Closes two
176+
TOCTOU windows: a session-clear race where a concurrent
177+
`build_rpg`/`update_rpg` could panic on `session.as_mut().unwrap()`,
178+
and a graph-replace race where a concurrent `set_project_root`
179+
could panic on `graph.as_ref().unwrap()`.
180+
- `set_project_root` tool description is no longer Claude-Code-specific
181+
in its example; reads runtime-neutral.
182+
- `get_entities_for_lifting` batch-0 dispatch NOTE no longer
183+
references "batches 2..N" (off-by-one against the 0-based
184+
`batch_index` parameter). Reads "do not request further batches in
185+
this context".
186+
8187
## [0.8.2] - 2026-04-14
9188

10189
### Added

Cargo.lock

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ members = [
1111
]
1212

1313
[workspace.package]
14-
version = "0.8.2"
14+
version = "0.8.3"
1515
edition = "2024"
1616
license = "MIT"
1717
authors = ["userFRM"]

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Then open any repo and tell your agent:
3737
3838
Your agent handles everything: indexes entities (seconds), reads each function and adds intent-level features (a few minutes), organizes them into a semantic hierarchy, and commits `.rpg/graph.json` for your team.
3939

40+
For repos with ~100+ entities, `lifting_status` will tell your agent to delegate the lifting loop to a sub-agent or a cheaper model — feature extraction is pattern-matching, not novel reasoning. If your runtime has no sub-agent mechanism, run `rpg-encoder lift --provider anthropic|openai` from the terminal with an API key — the CLI drives an external LLM directly with no agent involvement. After the CLI finishes, call `reload_rpg` in your session to load the updated graph. The CLI lifts entities with no features; re-lifting stale entities (features present but outdated after code changes) is handled by the in-session MCP flow, not the CLI.
41+
4042
Once lifted, try:
4143

4244
- *"What handles authentication?"* — finds code even when nothing is named "auth"
@@ -45,6 +47,30 @@ Once lifted, try:
4547

4648
---
4749

50+
## Use RPG before `grep`, `cat`, `find`
51+
52+
The server instructions tell your agent to reach for RPG tools FIRST for any
53+
question about code structure or behavior. That reflex matters — `grep`, `cat`,
54+
and ad-hoc file reads burn tokens and miss semantic relationships RPG already
55+
knows.
56+
57+
| If you'd otherwise reach for... | Use this instead |
58+
|---|---|
59+
| `grep -r` / `rg` (by intent) | `search_node(query="...")` |
60+
| `grep -r` / `rg` (by name) | `search_node(query="...", mode="snippets")` |
61+
| `cat` / reading a function | `fetch_node(entity_id="file:name")` |
62+
| chained greps for callers/callees | `explore_rpg(entity_id="...", direction="...")` |
63+
| recursive grep for "what depends on X" | `impact_radius(entity_id="...")` |
64+
| `wc -l` / `find` / `tree` | `rpg_info` |
65+
| reading many files for context | `semantic_snapshot` |
66+
| manual search → fetch → explore chains | `context_pack(query="...")` |
67+
| "how do I refactor X safely" | `plan_change(goal="...")` |
68+
69+
Fall back to `grep`, `cat`, or file reads only when the query is about literal text
70+
(string search, comments, TODOs, log messages) — not about structure.
71+
72+
---
73+
4874
## How It Works
4975

5076
<p align="center">

0 commit comments

Comments
 (0)