---
name: symbols
description: LSP-powered symbolic navigation for TypeScript/JavaScript. Replaces reading entire files when you need a specific symbol. -40 to -74% tokens on files > 150 lines. Commands: list <file>, view <file> <symbol>, refs <file> <symbol>.
context: fork
---

# /symbols — LSP Symbolic Navigation

Navigate code by symbol instead of reading entire files.
Measured savings on `@ulk/core` (TypeScript): **−74%** (function signature) · **−43%** (interface fields).

## Usage

```
/symbols list <file>               # List all symbols in a file
/symbols view <file> <symbol>      # Type + docstring for a specific symbol
/symbols refs <file> <symbol>      # All references to a symbol across the workspace
```

## Decision rules — when to use LSP vs. Read

| Situation | Best approach |
|-----------|---------------|
| File > 150 lines, need a specific symbol | `/symbols view` (LSP) |
| File ≤ 150 lines | `Read` directly (cheaper) |
| File is a barrel/re-export only (index.ts) | `Read` directly (LSP returns 0 symbols) |
| Need cross-file impact of a type change | `/symbols refs` (LSP) |
| Need the full implementation, not just the signature | `Read` directly |

---

## Step 0 — Check prerequisites

Before any LSP operation, verify the server is available:

```bash
which typescript-language-server 2>/dev/null || echo "LSP_MISSING"
```

If `LSP_MISSING`:
> ⚠️ `typescript-language-server` not installed.
> Install: `npm install -g typescript-language-server typescript`
> Falling back to `Read` for this request.

Then `Read` the target file and stop — do not continue with LSP steps.

---

## Command: `/symbols list <file>`

**Purpose**: get the symbol tree of a file without reading its implementation.

1. Check line count: `wc -l <file>`
   - ≤ 150 lines → `Read` directly (cheaper than LSP overhead)
   - > 150 lines → proceed with LSP

2. Call LSP `documentSymbol`:
   ```
   operation: documentSymbol
   filePath: <file>
   line: 1, character: 1
   ```

3. If response = "No symbols found":
   - The file is likely a barrel (re-exports only) or unsupported type
   - Inform: "No local symbols — reading file directly."
   - `Read` the file instead

4. Present the symbol tree. Top-level symbols only by default; include children when the file has < 20 top-level symbols.

---

## Command: `/symbols view <file> <symbol>`

**Purpose**: get the type signature and docstring of a specific symbol.

1. Run `documentSymbol` on the file (apply fallback rules from `list` above).

2. Search the tree for `<symbol>` (case-sensitive, exact match first; prefix match if no exact match).
   - Not found → "Symbol '<symbol>' not found in <file>. Available: [list top-level names]"

3. Note the symbol's line number from the tree.

4. Call LSP `hover` at that position:
   ```
   operation: hover
   filePath: <file>
   line: <symbol_line>
   character: <first non-whitespace char + 1>
   ```

5. If hover returns no information: present the symbol line from `documentSymbol` only.

6. Output:
   ```
   📌 <symbol>  <file>:<line>
   ──────────────────────────────────────
   <type signature>

   <docstring if present>
   ```

---

## Command: `/symbols refs <file> <symbol>`

**Purpose**: find all usages of a symbol across the workspace.

1. Locate symbol line via `documentSymbol` (step 1-3 of `view` above).

2. Call LSP `findReferences`:
   ```
   operation: findReferences
   filePath: <file>
   line: <symbol_line>
   character: <first non-whitespace char + 1>
   ```

3. If > 20 references: show first 20, note total count.

4. Group by file. Output:
   ```
   🔍 References to <symbol>  (<N> total)
   ───────────────────────────────────────
   <file>:<line>
   <file>:<line>
   ...
   ```

---

## Worked examples

### Find what a function returns
```
/symbols view src/parsers/spec-parser.ts parseSpecFile
```
→ `documentSymbol` locates `parseSpecFile` at line 169  
→ `hover` returns: `function parseSpecFile(content: string, filePath?: string): SpecFile`

### Inspect an interface's fields
```
/symbols view src/types/index.ts TodoItem
```
→ `documentSymbol` shows `TodoItem (Interface)` with all 10 properties inline  
→ No `hover` needed — the tree is sufficient

### Check what a package exports
```
/symbols list src/index.ts
```
→ If barrel file returns 0 symbols → `Read src/index.ts` (42 lines, cheaper)

### Find all files that use a type
```
/symbols refs src/types/index.ts TodoItem
```
→ `findReferences` returns every call site across the workspace

---

## Token cost reference (measured on `@ulk/core`)

| Operation | Tokens | vs. Read whole file |
|-----------|--------|---------------------|
| `documentSymbol` (221L file) | ~440 | −74% |
| `documentSymbol` (191L file) | ~780 | −43% |
| `hover` (single symbol) | ~95 | — |
| `findReferences` | ~50–300 | replaces reading N files |
| `Read` (barrel, 42L) | ~260 | baseline for tiny files |
