Skip to content

Commit 039aa44

Browse files
authored
Merge pull request #1 from bwl/claude/optimize-uuid-shortcodes-011CULmz3EBo3XBgEHCKh6kM
feat: implement Git-style node references and progressive IDs
2 parents 7fa7acb + 7e603d1 commit 039aa44

9 files changed

Lines changed: 904 additions & 27 deletions

File tree

CLAUDE.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,112 @@ export function registerNodeCommands(cli: ClercInstance, clerc: ClercModule) {
155155
}
156156
```
157157

158+
### Git-Style Node References
159+
160+
Forest uses **Git-inspired progressive abbreviation** for node and edge IDs, optimizing for both brevity and backward compatibility.
161+
162+
#### Display vs. Acceptance
163+
164+
**What Forest displays** (optimized for current graph size):
165+
```bash
166+
$ forest explore
167+
ID TITLE EDGES
168+
7fa7 Optimize UUIDs 12 # Shows 4-7 chars (enough for uniqueness)
169+
ef3a Progressive IDs 8
170+
```
171+
172+
**What Forest accepts** (any unique prefix):
173+
```bash
174+
$ forest node read 7fa7 # 4 chars ✅
175+
$ forest node read 7fa7acb2 # 8 chars ✅ (backward compatible!)
176+
$ forest node read 7fa7acb2-ed4a-4f3b-9c1e-8a2b3c4d5e6f # full UUID ✅
177+
```
178+
179+
All lengths work! Forest accepts **any unique prefix**, even if display shows shorter.
180+
181+
#### Reference Types
182+
183+
Forest supports multiple reference patterns (unified resolution in `src/cli/shared/utils.ts:resolveNodeReference()`):
184+
185+
**1. UUID Prefixes** (case-insensitive, works with/without dashes):
186+
```bash
187+
forest node read 7fa7 # Short prefix
188+
forest node read 7fa7acb2 # 8-char prefix
189+
forest node read 7fa7acb2-ed4a # Longer prefix
190+
```
191+
192+
**2. Recency References** (Git-style `HEAD~N`):
193+
```bash
194+
forest node read @ # Last updated node (@ or @0)
195+
forest node read @1 # Second most recently updated
196+
forest node read @2 # Third most recently updated
197+
forest node link @ @1 # Link two recent nodes
198+
```
199+
200+
**3. Tag Search** (exact match, finds unique node):
201+
```bash
202+
forest node read #typescript # Node tagged with 'typescript'
203+
forest node read #api-design # Node tagged with 'api-design'
204+
```
205+
206+
**4. Title Search** (substring match, must be unique):
207+
```bash
208+
forest node read "UUID short" # Finds node with "UUID short" in title
209+
forest node read "api" # Finds node with "api" in title (if unique)
210+
```
211+
212+
#### Disambiguation
213+
214+
When a reference matches multiple nodes, Forest shows **Git-style disambiguation**:
215+
216+
```bash
217+
$ forest node read 7fa
218+
✖ Ambiguous ID '7fa' matches 3 nodes:
219+
7fa7acb2 "Optimize UUID shortcodes" (2025-10-21)
220+
7fa2103e "Add progressive IDs" (2025-10-20)
221+
7fa8ef29 "Update scoring algorithm" (2025-10-19)
222+
223+
Use a longer prefix to disambiguate.
224+
```
225+
226+
Similar disambiguation for tag and title searches shows matching nodes with IDs for easy selection.
227+
228+
#### Progressive Display
229+
230+
**Node IDs**: Use `formatNodeIdProgressive()` in `src/cli/shared/utils.ts`
231+
- Minimum 4 chars, grows as needed to maintain uniqueness
232+
- Implementation: `src/lib/progressive-id.ts` with `buildNodePrefixMap()`
233+
234+
**Edge IDs**: Already use progressive abbreviation (4+ chars)
235+
- Stable hash generation via FNV-1a
236+
- Minimal prefix display in `forest edges` output
237+
238+
#### Backward Compatibility
239+
240+
**Zero breaking changes**: All existing 8-char references continue to work!
241+
242+
- External docs with `7fa7acb2` keep resolving correctly
243+
- Scripts using full UUIDs remain valid
244+
- API responses can return any length (recommended: 8 chars or full UUID)
245+
- `--long` flag available for full UUIDs when needed
246+
247+
#### Tab Completion
248+
249+
Shell completion scripts available in `completions/`:
250+
- `forest.bash` - Bash completion
251+
- `forest.zsh` - Zsh completion
252+
- Supports command, flag, and recency reference completion
253+
254+
**Installation**:
255+
```bash
256+
# Bash
257+
source completions/forest.bash
258+
259+
# Zsh (add to ~/.zshrc)
260+
fpath=(path/to/forest/completions $fpath)
261+
autoload -Uz compinit && compinit
262+
```
263+
158264
### 3-Layer Architecture: CLI/API Feature Parity
159265

160266
Forest uses a **3-layer architecture** to maintain feature parity between the CLI and REST API:

GIT_STYLE_REFERENCES.md

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
# Git-Style References in Forest
2+
3+
This document describes the Git-inspired UX improvements implemented in Forest for working with node and edge IDs.
4+
5+
## Overview
6+
7+
Forest now embraces Git's approach to short hashes with **progressive abbreviation** and **flexible reference types**, making the CLI more ergonomic while maintaining full backward compatibility.
8+
9+
## Key Principles (from Git)
10+
11+
### 1. Display ≠ Acceptance
12+
13+
**What Git does:**
14+
```bash
15+
$ git log --oneline
16+
7fa7acb Bump version # Shows 7 chars today
17+
18+
$ git show 7fa7acb # 7 chars ✅
19+
$ git show 7fa7acb2 # 8 chars ✅
20+
$ git show 7fa7acb2d # 9 chars ✅ - all work!
21+
```
22+
23+
**What Forest now does:**
24+
```bash
25+
$ forest explore
26+
ID TITLE
27+
7fa7 Optimize UUIDs # Shows 4-7 chars (enough for uniqueness)
28+
29+
$ forest node read 7fa7 # 4 chars ✅
30+
$ forest node read 7fa7acb2 # 8 chars ✅
31+
$ forest node read 7fa7acb2-ed4a-4f3b-9c1e-... # full UUID ✅
32+
```
33+
34+
**Backward compatibility:** All existing 8-char references in docs, scripts, and bookmarks continue to work!
35+
36+
### 2. Progressive Abbreviation
37+
38+
Forest displays the **shortest unique prefix** needed to avoid collisions:
39+
40+
- **Small graph (10 nodes):** Likely shows 4-5 char IDs
41+
- **Medium graph (100 nodes):** Likely shows 5-6 char IDs
42+
- **Large graph (1000+ nodes):** May need 7-8 char IDs
43+
44+
This scales gracefully as your knowledge base grows, just like Git scales from small repos to the Linux kernel.
45+
46+
### 3. Multiple Reference Types
47+
48+
Git accepts commits via:
49+
- SHA hashes: `7fa7acb`
50+
- Branches: `main`, `feature/foo`
51+
- Tags: `v1.0.0`
52+
- Symbolic refs: `HEAD`, `@{-1}`
53+
- Relative refs: `HEAD~3`, `main^2`
54+
55+
Forest now accepts nodes via:
56+
- **UUID prefixes:** `7fa7acb2` (any length)
57+
- **Recency refs:** `@`, `@1`, `@2` (last updated nodes)
58+
- **Tag search:** `#typescript` (finds node tagged 'typescript')
59+
- **Title search:** `"API design"` (finds node with matching title)
60+
61+
All resolved through a unified function (`resolveNodeReference()`) that tries each pattern in order.
62+
63+
## Implementation Details
64+
65+
### Progressive Node IDs
66+
67+
**File:** `src/lib/progressive-id.ts`
68+
69+
```typescript
70+
// Generate minimal unique prefix for a node
71+
getNodePrefix(nodeId, allNodeIds, minLength = 4): string
72+
73+
// Build map of all nodes to their minimal prefixes
74+
buildNodePrefixMap(nodeIds, minLength = 4): Map<string, string>
75+
76+
// Normalize UUID (remove dashes, lowercase)
77+
normalizeNodeId(nodeId): string
78+
```
79+
80+
**Display:**
81+
```typescript
82+
// Old way (fixed 8 chars)
83+
formatId(id) → "7fa7acb2"
84+
85+
// New way (variable, 4-8+ chars)
86+
formatNodeIdProgressive(id, allNodes) → "7fa7" or "7fa7a" if collision
87+
```
88+
89+
### Unified Reference Resolution
90+
91+
**File:** `src/cli/shared/utils.ts`
92+
93+
```typescript
94+
resolveNodeReference(ref: string): Promise<NodeRecord | null>
95+
```
96+
97+
**Resolution order:**
98+
1. If starts with `@` → recency reference (`@`, `@0`, `@1`, etc.)
99+
2. If starts with `#` → tag search (`#typescript`)
100+
3. If quoted → title search (`"API design"`)
101+
4. If hex chars → UUID prefix (case-insensitive, works with/without dashes)
102+
5. Exact UUID match
103+
104+
### Recency References
105+
106+
Inspired by Git's `HEAD`, `@{-1}`, `@{upstream}`:
107+
108+
```bash
109+
# Git
110+
git show HEAD # Last commit
111+
git diff @{-1} # Previous branch
112+
git cherry-pick @{3} # 4th recent commit
113+
114+
# Forest
115+
forest node read @ # Last updated node
116+
forest node read @1 # Second most recent
117+
forest node link @ @2 # Link recent nodes
118+
```
119+
120+
**Implementation:**
121+
```typescript
122+
resolveRecencyReference(ref: string): Promise<NodeRecord | null>
123+
```
124+
125+
Sorts all nodes by `updatedAt` descending, returns node at index N.
126+
127+
### Rich Disambiguation
128+
129+
When a reference is ambiguous, Forest shows **all matches with context** (like Git):
130+
131+
```bash
132+
$ forest node read 7fa
133+
✖ Ambiguous ID '7fa' matches 3 nodes:
134+
7fa7acb2 "Optimize UUID shortcodes" (2025-10-21)
135+
7fa2103e "Add progressive IDs" (2025-10-20)
136+
7fa8ef29 "Update scoring algorithm" (2025-10-19)
137+
138+
Use a longer prefix to disambiguate.
139+
```
140+
141+
**Implementation:**
142+
- Shows up to 10 matches sorted by recency
143+
- Displays: short ID (8 chars), title, date
144+
- Clear action: "Use a longer prefix"
145+
146+
Similar for tag/title searches - shows matching nodes with IDs for copy-paste.
147+
148+
### Case-Insensitive Matching
149+
150+
All ID resolution is case-insensitive (like Git SHAs):
151+
152+
```bash
153+
forest node read 7FA7ACB2 # ✅ Same as 7fa7acb2
154+
forest node read 7Fa7AcB2 # ✅ Same as 7fa7acb2
155+
```
156+
157+
**Implementation:** All prefix matching uses `.toLowerCase()` normalization.
158+
159+
## Updated Commands
160+
161+
### Display Commands
162+
163+
All commands that show node IDs now use progressive abbreviation:
164+
165+
- **`forest explore`** - Shows minimal node prefixes in tables
166+
- **`forest search`** - Shows minimal prefixes in results
167+
- **`forest stats`** - Shows minimal prefixes in summaries
168+
- **`forest edges`** - Already used progressive edge IDs, now nodes too
169+
- **`forest node read`** - Shows minimal prefix in header
170+
171+
All support `--long` flag for full UUIDs when needed.
172+
173+
### Reference Commands
174+
175+
All commands that accept node refs now support all patterns:
176+
177+
- **`forest node read [ref]`** - Works with `@`, `#tag`, `"title"`, UUID prefix
178+
- **`forest node edit [ref]`** - Same
179+
- **`forest node delete [ref]`** - Same
180+
- **`forest node link [ref1] [ref2]`** - Both refs support all patterns
181+
182+
## Tab Completion
183+
184+
Shell completion scripts in `completions/`:
185+
186+
**Bash** (`completions/forest.bash`):
187+
```bash
188+
source completions/forest.bash
189+
190+
forest node read @<TAB> # Suggests @, @1, @2, @3, @4, @5
191+
```
192+
193+
**Zsh** (`completions/forest.zsh`):
194+
```bash
195+
fpath=(path/to/forest/completions $fpath)
196+
autoload -Uz compinit && compinit
197+
198+
forest node <TAB> # Shows: read, edit, delete, link, recent, ...
199+
```
200+
201+
## Documentation
202+
203+
**CLAUDE.md** updated with comprehensive "Git-Style Node References" section explaining:
204+
- Display vs. Acceptance
205+
- Reference Types
206+
- Disambiguation
207+
- Progressive Display
208+
- Backward Compatibility
209+
- Tab Completion
210+
211+
## Testing
212+
213+
**Test file:** `test-progressive-ids.js` (run with `node test-progressive-ids.js`)
214+
215+
Validates:
216+
1.`normalizeNodeId` removes dashes and lowercases
217+
2. ✅ Unique IDs get minimal 4-char prefixes
218+
3. ✅ Colliding prefixes automatically expand to 5+ chars
219+
4. ✅ Case-insensitive matching works
220+
5. ✅ Backward compatibility - 8-char prefixes still resolve
221+
222+
## Migration Guide
223+
224+
**For users:**
225+
- ✅ No action needed - all existing workflows continue working
226+
- ✅ New shortcuts available: `@` for recent, `#tag` for tags
227+
- ✅ Copy shorter IDs from output (4-7 chars vs 8)
228+
229+
**For scripts/docs:**
230+
- ✅ Existing 8-char IDs: No changes needed
231+
- ✅ Full UUIDs: No changes needed
232+
- ✅ Want to future-proof? Use full UUIDs with `--long` flag
233+
234+
**For developers:**
235+
- New display: Use `formatNodeIdProgressive(id, allNodes)` instead of `formatId(id)`
236+
- New resolution: `resolveNodeReference(ref)` handles all patterns
237+
- Progressive edges: Already working via `getEdgePrefix()`
238+
239+
## Future Enhancements
240+
241+
Inspired by Git but not yet implemented:
242+
243+
1. **Relative references:** `@parent`, `@linked[0]` for graph navigation
244+
2. **Named refs:** Save commonly used queries as shortcuts
245+
3. **Range syntax:** `@1..@5` for bulk operations
246+
4. **Fuzzy matching:** `forest node read ~uuid` for approximate search
247+
248+
## Philosophy
249+
250+
Git taught us that good UX means:
251+
252+
1. **Optimize for humans** - Show short IDs, accept any length
253+
2. **Scale gracefully** - Progressive abbreviation grows with your data
254+
3. **Never break links** - Full backward compatibility
255+
4. **Rich feedback** - Helpful errors with actionable suggestions
256+
5. **Multiple entry points** - Support different mental models (@, #tag, "title")
257+
258+
Forest now applies these principles to knowledge management.

0 commit comments

Comments
 (0)