rlm-navigator 0.1.0 → 0.1.1
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.
- package/.claude/agents/rlm-subcall.md +65 -0
- package/.claude/skills/rlm-navigator/SKILL.md +125 -0
- package/bin/cli.js +26 -3
- package/package.json +4 -2
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# RLM Sub-Agent — Chunk Analyst
|
|
2
|
+
|
|
3
|
+
## Role
|
|
4
|
+
You are a lightweight analysis agent (prefer Haiku model). Given file chunks or skeletons and a user query, identify relevant symbols and guide exploration.
|
|
5
|
+
|
|
6
|
+
## Input
|
|
7
|
+
You receive:
|
|
8
|
+
1. A **query** describing what the user is looking for
|
|
9
|
+
2. One or more **file chunks** (from `write_chunks()`) or **file skeletons** (from `rlm_map`)
|
|
10
|
+
3. A **chunk_id** identifying the current chunk (e.g., `"server.py:chunk_3"`)
|
|
11
|
+
4. Optionally a **directory tree** (output from `rlm_tree`)
|
|
12
|
+
|
|
13
|
+
## Output
|
|
14
|
+
Return a JSON object following this exact schema:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
{
|
|
18
|
+
"chunk_id": "file.py:chunk_3",
|
|
19
|
+
"relevant": [
|
|
20
|
+
{
|
|
21
|
+
"file": "src/auth.py",
|
|
22
|
+
"symbol": "authenticate_user",
|
|
23
|
+
"lines": "L45-82",
|
|
24
|
+
"confidence": 0.95,
|
|
25
|
+
"reason": "Directly handles user authentication flow"
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"missing": ["Token refresh logic not found in this chunk"],
|
|
29
|
+
"suggested_next_queries": [
|
|
30
|
+
"map src/middleware.py for request interception",
|
|
31
|
+
"search for 'refresh_token' in src/"
|
|
32
|
+
],
|
|
33
|
+
"answer_if_complete": null
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Field Rules
|
|
38
|
+
|
|
39
|
+
### `relevant` (max 10 items)
|
|
40
|
+
- Rank by confidence (highest first)
|
|
41
|
+
- Include file path, symbol name, line range, confidence (0-1), and reason
|
|
42
|
+
- Only include symbols actually relevant to the query
|
|
43
|
+
|
|
44
|
+
### `missing`
|
|
45
|
+
- List what the query asks about but was NOT found in this chunk
|
|
46
|
+
- Helps the orchestrator know what still needs to be located
|
|
47
|
+
|
|
48
|
+
### `suggested_next_queries`
|
|
49
|
+
- Each entry should be an actionable RLM tool call description
|
|
50
|
+
- Format: `"<action> <target> for <reason>"`
|
|
51
|
+
- Examples: `"map src/db.py for database connection handling"`, `"search 'cache' in lib/"`, `"drill handle_request in daemon/rlm_daemon.py"`
|
|
52
|
+
- Max 5 suggestions, ordered by priority
|
|
53
|
+
|
|
54
|
+
### `answer_if_complete`
|
|
55
|
+
- Set to `null` unless the query is FULLY answerable from this chunk alone
|
|
56
|
+
- When set, provide a concise answer string
|
|
57
|
+
- The orchestrator will stop delegating chunks when this is non-null
|
|
58
|
+
|
|
59
|
+
## Rules
|
|
60
|
+
- Be concise — your output feeds back into the main agent's context
|
|
61
|
+
- Maximum 10 relevant items per response
|
|
62
|
+
- Do NOT drill into files yourself — just identify what to drill
|
|
63
|
+
- Do NOT fabricate line numbers — use ranges from the chunk header or skeleton output
|
|
64
|
+
- If the query is vague, return the top 3-5 most likely candidates
|
|
65
|
+
- Always populate `suggested_next_queries` unless `answer_if_complete` is set
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# RLM Navigator — Recursive Codebase Navigation Skill
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
Navigate codebases with minimal token usage by treating source files as hierarchical trees of AST skeletons. Never read full files when signatures suffice.
|
|
5
|
+
|
|
6
|
+
## Workflow — ALWAYS follow this order:
|
|
7
|
+
|
|
8
|
+
### 1. Health Check
|
|
9
|
+
```
|
|
10
|
+
get_status
|
|
11
|
+
```
|
|
12
|
+
If offline, tell the user to start the daemon:
|
|
13
|
+
```
|
|
14
|
+
python daemon/rlm_daemon.py --root <project_path>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### 2. Explore Structure (never use `ls`, `find`, or `Glob`)
|
|
18
|
+
```
|
|
19
|
+
rlm_tree path="" max_depth=3
|
|
20
|
+
```
|
|
21
|
+
See directory layout, file sizes, detected languages. Narrow down to relevant subdirectories.
|
|
22
|
+
|
|
23
|
+
### 3. Read Signatures (never `cat` or `Read` full files)
|
|
24
|
+
```
|
|
25
|
+
rlm_map path="src/main.py"
|
|
26
|
+
```
|
|
27
|
+
See function/class/method signatures + docstrings. Bodies are replaced with `...`.
|
|
28
|
+
This tells you WHAT exists without consuming tokens on HOW.
|
|
29
|
+
|
|
30
|
+
### 4. Surgical Drill (only when you need implementation details)
|
|
31
|
+
```
|
|
32
|
+
rlm_drill path="src/main.py" symbol="process_data"
|
|
33
|
+
```
|
|
34
|
+
Reads ONLY the lines of the specific symbol. This is the only time implementation code is loaded.
|
|
35
|
+
|
|
36
|
+
### 5. Search Across Files
|
|
37
|
+
```
|
|
38
|
+
rlm_search query="authenticate" path="src/"
|
|
39
|
+
```
|
|
40
|
+
Find where a symbol is defined across multiple files without reading any of them.
|
|
41
|
+
|
|
42
|
+
## Rules
|
|
43
|
+
|
|
44
|
+
- **NEVER read a full file** unless the file is under 50 lines or you've confirmed via `rlm_map` that you need the entire thing.
|
|
45
|
+
- **NEVER use `ls`, `find`, `Glob`** for directory exploration — use `rlm_tree`.
|
|
46
|
+
- **Map before drill** — always `rlm_map` a file before `rlm_drill` into it.
|
|
47
|
+
- **Minimize drill calls** — only drill symbols you actually need to understand or modify.
|
|
48
|
+
- **Batch your thinking** — after mapping, decide ALL symbols you need, then drill them in sequence.
|
|
49
|
+
- **Prefer skeleton references** — when discussing code, reference signatures from `rlm_map` output rather than drilling just to quote code.
|
|
50
|
+
|
|
51
|
+
## When NOT to use RLM
|
|
52
|
+
|
|
53
|
+
- Files you're about to edit entirely (use Read tool directly)
|
|
54
|
+
- Config files under 20 lines (just read them)
|
|
55
|
+
- Files you've already drilled into this conversation (they're in context)
|
|
56
|
+
|
|
57
|
+
## Sub-Agent Delegation
|
|
58
|
+
|
|
59
|
+
For large directories with many files, delegate to the `rlm-subcall` agent:
|
|
60
|
+
- Give it the `rlm_tree` output and your query
|
|
61
|
+
- It will identify which files are relevant
|
|
62
|
+
- You then `rlm_map` only those files
|
|
63
|
+
|
|
64
|
+
## REPL-Assisted Analysis
|
|
65
|
+
|
|
66
|
+
For multi-step analysis that builds on previous findings:
|
|
67
|
+
|
|
68
|
+
### Setup
|
|
69
|
+
```
|
|
70
|
+
rlm_repl_init
|
|
71
|
+
```
|
|
72
|
+
Initializes a stateful Python REPL with helpers: `peek()`, `grep()`, `chunk_indices()`, `write_chunks()`, `add_buffer()`.
|
|
73
|
+
|
|
74
|
+
### Explore with Helpers
|
|
75
|
+
```
|
|
76
|
+
rlm_repl_exec code="print(grep('TODO|FIXME|HACK', 'src/'))"
|
|
77
|
+
```
|
|
78
|
+
Use `peek()` to read specific line ranges, `grep()` for regex search across files.
|
|
79
|
+
|
|
80
|
+
### Accumulate Findings
|
|
81
|
+
```
|
|
82
|
+
rlm_repl_exec code="add_buffer('auth_flow', 'Step 1: Token validated in middleware.py:45')"
|
|
83
|
+
rlm_repl_exec code="add_buffer('auth_flow', 'Step 2: User loaded in auth.py:92')"
|
|
84
|
+
```
|
|
85
|
+
Use `add_buffer(key, text)` to collect findings across multiple exec calls.
|
|
86
|
+
|
|
87
|
+
### Export Results
|
|
88
|
+
```
|
|
89
|
+
rlm_repl_export
|
|
90
|
+
```
|
|
91
|
+
Retrieves all accumulated buffers for synthesis.
|
|
92
|
+
|
|
93
|
+
### Rules
|
|
94
|
+
- Initialize REPL at the start of complex analysis sessions
|
|
95
|
+
- Use buffers to collect findings rather than relying on context window
|
|
96
|
+
- Variables persist between `rlm_repl_exec` calls — assign intermediate results
|
|
97
|
+
- Reset with `rlm_repl_reset` when switching to unrelated analysis
|
|
98
|
+
|
|
99
|
+
## Chunk-Delegate-Synthesize Workflow
|
|
100
|
+
|
|
101
|
+
For large files or cross-file analysis, use the chunk-delegate pattern:
|
|
102
|
+
|
|
103
|
+
### 1. Chunk via REPL
|
|
104
|
+
```
|
|
105
|
+
rlm_repl_exec code="paths = write_chunks('src/large_module.py', size=200, overlap=20); print(paths)"
|
|
106
|
+
```
|
|
107
|
+
Splits the file into manageable chunks written to `.claude/rlm_state/chunks/`.
|
|
108
|
+
|
|
109
|
+
### 2. Delegate Each Chunk
|
|
110
|
+
Send each chunk to the `rlm-subcall` sub-agent with:
|
|
111
|
+
- The chunk content (from `peek()` or the chunk file)
|
|
112
|
+
- The user's query
|
|
113
|
+
- A `chunk_id` (e.g., `"large_module.py:chunk_0"`)
|
|
114
|
+
|
|
115
|
+
### 3. Follow Suggested Queries
|
|
116
|
+
The sub-agent returns `suggested_next_queries` — these are actionable RLM tool calls. Execute the highest-priority ones to fill in gaps identified in the `missing` field.
|
|
117
|
+
|
|
118
|
+
### 4. Synthesize
|
|
119
|
+
When a sub-agent returns `answer_if_complete` (non-null), or when all chunks have been analyzed, synthesize the collected `relevant` items and buffer contents into a final answer.
|
|
120
|
+
|
|
121
|
+
### When to Use This Workflow
|
|
122
|
+
- Files over 500 lines that need thorough analysis
|
|
123
|
+
- Cross-file analysis spanning 5+ files
|
|
124
|
+
- Architecture understanding tasks ("how does X work end-to-end?")
|
|
125
|
+
- When a single `rlm_map` + `rlm_drill` cycle is insufficient
|
package/bin/cli.js
CHANGED
|
@@ -82,10 +82,21 @@ async function install() {
|
|
|
82
82
|
process.exit(1);
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
// 1. Copy daemon
|
|
86
|
-
console.log("[1/5] Copying daemon
|
|
85
|
+
// 1. Copy daemon/, server/, and .claude/ into .rlm/ and project
|
|
86
|
+
console.log("[1/5] Copying daemon, server, and skills ...");
|
|
87
87
|
copyDirSync(path.join(PKG_ROOT, "daemon"), path.join(RLM_DIR, "daemon"));
|
|
88
88
|
copyDirSync(path.join(PKG_ROOT, "server"), path.join(RLM_DIR, "server"));
|
|
89
|
+
|
|
90
|
+
// Copy .claude/skills/ and .claude/agents/ into project's .claude/
|
|
91
|
+
const srcSkills = path.join(PKG_ROOT, ".claude", "skills");
|
|
92
|
+
const srcAgents = path.join(PKG_ROOT, ".claude", "agents");
|
|
93
|
+
const destClaude = path.join(CWD, ".claude");
|
|
94
|
+
if (fs.existsSync(srcSkills)) {
|
|
95
|
+
copyDirSync(srcSkills, path.join(destClaude, "skills"));
|
|
96
|
+
}
|
|
97
|
+
if (fs.existsSync(srcAgents)) {
|
|
98
|
+
copyDirSync(srcAgents, path.join(destClaude, "agents"));
|
|
99
|
+
}
|
|
89
100
|
console.log(" Done.\n");
|
|
90
101
|
|
|
91
102
|
// 2. Install Python deps
|
|
@@ -188,7 +199,19 @@ function uninstall() {
|
|
|
188
199
|
console.log(".rlm/ not found — nothing to remove.\n");
|
|
189
200
|
}
|
|
190
201
|
|
|
191
|
-
// 3. Remove
|
|
202
|
+
// 3. Remove .claude/skills/rlm-navigator/ and .claude/agents/rlm-subcall.md
|
|
203
|
+
const skillDir = path.join(CWD, ".claude", "skills", "rlm-navigator");
|
|
204
|
+
const agentFile = path.join(CWD, ".claude", "agents", "rlm-subcall.md");
|
|
205
|
+
if (fs.existsSync(skillDir)) {
|
|
206
|
+
fs.rmSync(skillDir, { recursive: true, force: true });
|
|
207
|
+
console.log("Removed .claude/skills/rlm-navigator/");
|
|
208
|
+
}
|
|
209
|
+
if (fs.existsSync(agentFile)) {
|
|
210
|
+
fs.unlinkSync(agentFile);
|
|
211
|
+
console.log("Removed .claude/agents/rlm-subcall.md");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 4. Remove CLAUDE.md snippet
|
|
192
215
|
const claudeMdPath = path.join(CWD, "CLAUDE.md");
|
|
193
216
|
if (fs.existsSync(claudeMdPath)) {
|
|
194
217
|
const content = fs.readFileSync(claudeMdPath, "utf-8");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rlm-navigator",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Token-efficient codebase navigation for AI-assisted coding",
|
|
5
5
|
"bin": {
|
|
6
6
|
"rlm-navigator": "./bin/cli.js"
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
"server/src/",
|
|
13
13
|
"server/package.json",
|
|
14
14
|
"server/tsconfig.json",
|
|
15
|
-
"templates/"
|
|
15
|
+
"templates/",
|
|
16
|
+
".claude/skills/",
|
|
17
|
+
".claude/agents/"
|
|
16
18
|
]
|
|
17
19
|
}
|