From easy-cheese
Replaces cat/head/tail/ls/tree/find with AST-aware file reading via tilth MCP. Shows file contents, directory listings, line ranges, and dependencies without shell fallbacks.
How this skill is triggered — by the user, by Claude, or both
Slash command
/easy-cheese:cheez-readThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
> **Hard dependency**: If `mcp__tilth__tilth_read` is unavailable, stop immediately and report
Hard dependency: If
mcp__tilth__tilth_readis unavailable, stop immediately and report "tilth MCP server is not loaded — cannot proceed." Do NOT fall back tocat,Read,Glob, or any host tool. Install viatilth install <host>(see README "Installing tilth MCP").
Before the first call, verify tilth is reachable:
mcp__tilth__tilth_read is available. If absent, stop and report "tilth MCP server is not loaded — cannot proceed."tilth_read(path: "README.md", section: "1-1"). If the response is a JSON-RPC error or transport failure, stop and report "tilth MCP server present but unhealthy: <error>".Smart code reading via tilth MCP (tilth_read, tilth_files, tilth_deps).
tilth replaces cat/head/tail with AST-aware file reading that understands code structure.
src/auth.ts"tilth_read(path: "src/auth.ts")
Small files come back with full content and a header (# src/auth.ts (258 lines, ~3.4k tokens) [full]); large files get the structural outline
automatically.
handleAuth function in edit mode so I can change it"tilth_read(path: "src/auth.ts", section: "44-89", edit: true)
44:b2c|export function handleAuth(req, res, next) {
45:c3d| const token = req.headers.authorization?.split(' ')[1];
...
89:e1d|}
The edit: true flag (or --edit in CLI mode) emits hash anchors. Capture
44:b2c and 89:e1d and pass them to cheez-write.
src/handlers/"tilth_files(glob: "*.ts", scope: "src/handlers/")
src/handlers/auth.ts (~1.8k tokens)
src/handlers/orders.ts (~3.1k tokens)
src/handlers/webhooks.ts (~620 tokens)
Token estimates inform what to read in full vs outline before spending any context on it.
tilth decides what to show based on file size and structure:
This avoids wasting tokens on a giant lockfile or minified bundle.
tilth_read owns source code files in tracked, parseable languages — anything that may later need symbol navigation, hash anchors, or cheez-write edits. Smart outlining, edit-mode anchors, session deduplication, and .gitignore-aware listings all live here.
The tilth MCP server is launched against one repository — whatever directory the harness booted it in. There is no persistent index: tilth walks the working tree on demand, parses files with Tree-sitter, and respects .gitignore. Practical consequences:
~/..., system paths, dependency caches like node_modules, .cargo/registry, site-packages).Read per file directly, or use code-review-graph's cross-repo tools — see cheez-search's When code-review-graph beats tilth section./cheez-readInside /cheez-read, the contract is hard: tilth-only, no host fallback. The reads below are out of scope for the skill — don't enter cheez-read for them in the first place. They're listed here so workflow skills know where to route instead, consistent with the README rule "anything that touches source code goes through cheez-*; everything else stays on host tools".
| File (don't use cheez-read) | Route to | Why |
|---|---|---|
| Binary content (images, PDFs) | host Read (multimodal) from the calling workflow skill | tilth can't render these |
| Streaming output, process logs, huge CSVs | host Bash with head/tail, awk, jq from the calling workflow skill | Format-specific tools beat outline mode here |
| Lockfiles, minified bundles, generated artifacts | don't read by hand — regenerate from source | tilth deliberately skips these |
Files outside the repo (system paths, sibling worktrees, ~/...) | host Read from the calling workflow skill | tilth is repo-scoped (see above) |
Dependency source (node_modules, .cargo/registry, site-packages, vendor caches) | LSP textDocument/definition from the calling workflow skill if a server is reachable; otherwise don't read by hand | Reading dependency source by hand is almost always wrong; the LSP resolves the right module version |
If the file is code in this repo, always cheez-read — the hash anchors are non-negotiable for safe edits later, and the tilth-only contract holds inside the skill.
easy-cheese does not install LSP — it is whatever language servers the harness already exposes. When an LSP is reachable for the file's language and the navigation question is type-grounded, prefer the LSP method:
| Goal | LSP method (when available) | Why LSP wins |
|---|---|---|
| Jump to where a symbol is defined, following imports / re-exports | textDocument/definition | Resolves the actual import graph; tilth surfaces every textual definition with that name |
| Read the resolved type / generic instantiation at a call site | textDocument/hover | Returns the typechecker's view of the symbol, not just the source declaration |
| Open the file declaring the type of a value | textDocument/typeDefinition | Walks through type aliases and generic parameters |
| Browse symbols across the whole project, semantically ranked | workspace/symbol | LSP indexes the project's type graph; tilth indexes the tree |
If no LSP is installed for the language, or the file is in a broken / incomplete state where the server cannot resolve, stay on tilth. tilth still wins on outline reading, hash-anchored prep for edits, polyglot directory listings, and any read where a .gitignore-aware token estimate is required.
Serena is an LSP-driven MCP. When Serena is configured for the codebase (.serena/project.yml present) and the read is symbol-shaped, the calling workflow skill should route directly to Serena rather than entering /cheez-read:
| Goal | Serena tool | Why |
|---|---|---|
| Just the symbol table of one file (no source lines) | mcp__serena__get_symbols_overview | Cheaper than tilth outline mode — LSP-indexed, no parse pass |
| Read a single symbol's body by name (no line range needed) | mcp__serena__find_symbol with body inclusion | Skips the "outline → drill into 44-89" round-trip |
/cheez-read itself stays tilth-only — its allowed-tools frontmatter does not include mcp__serena__* and shouldn't. The routing decision happens in the workflow skill before it enters /cheez-read. Enter /cheez-read when you need hash anchors (any edit follows up), a tilth_files directory listing with token estimates, token-budgeted preview mode, or when Serena is unavailable. Serena gives you the symbol; tilth gives you the anchor — if you're going to edit afterwards, prefer tilth so the anchor is already in hand. See cheez-write for the symmetric "When Serena beats tilth_edit" guidance.
tilth_read(path: "src/auth.ts")
Output for small files:
# src/auth.ts (258 lines, ~3.4k tokens) [full]
1 │ import express from 'express';
2 │ import jwt from 'jsonwebtoken';
...
Output for large files (automatic outline):
# src/auth.ts (1240 lines, ~16k tokens) [outline]
[1-12] imports: express(2), jsonwebtoken, @/config
[14-22] interface AuthConfig
[24-42] fn validateToken(token: string): Claims | null
[44-89] export fn handleAuth(req, res, next)
[91-258] export class AuthManager
[99-130] fn authenticate(credentials)
[132-180] fn authorize(user, resource)
Drilling into sections:
# Line range
tilth_read(path: "src/auth.ts", section: "44-89")
# Markdown heading
tilth_read(path: "docs/guide.md", section: "## Installation")
Multiple files in one call:
tilth_read(paths: ["src/auth.ts", "src/routes.ts", "src/middleware.ts"])
When reading files in edit mode, tilth outputs hash-anchored lines:
42:a3f| let x = compute();
43:f1b| return x;
The format is <line>:<hash>|<content>.
Plain reads use a
│(U+2502) column separator. Edit-mode reads (the ones required for cheez-write) use:<hash>|— note the ASCII pipe and the colon. Anchors are only emitted when tilth is run in--editmode.
Why this matters:
tilth_edit (cheez-write) for precise editsMemorize anchors for functions to edit:
Replaces ls, find, pwd, and the Glob tool.
tilth_files(glob: "**/*.ts", scope: "src/")
Output:
src/auth.ts (~3.4k tokens)
src/routes.ts (~2.1k tokens)
src/middleware.ts (~1.8k tokens)
Token estimates inform what to read in full vs outline.
Common patterns:
# All TypeScript files
tilth_files(glob: "**/*.ts")
# Test files only
tilth_files(glob: "**/*.test.ts")
# Specific directory
tilth_files(glob: "*", scope: "src/handlers/")
# Exclude patterns (negation in the same glob)
tilth_files(glob: "!*_test.go", scope: ".")
tilth_deps(path: "src/auth.ts")
Use only before refactoring (rename, signature change, removal). For
output format and the file-vs-symbol distinction, see the shared reference
in cheez-search:
../cheez-search/references/tilth-deps.md.
tilth tracks reads within the current session:
[shown earlier] instead of full contentImplication: Read once, memorize anchors, reference later.
Start with outline (let tilth auto-decide):
tilth_read(path: "src/auth.ts")
Drill into relevant sections:
tilth_read(path: "src/auth.ts", section: "44-89")
Check dependencies if needed:
tilth_deps(path: "src/auth.ts")
Read the target section to get hash anchors:
tilth_read(path: "src/auth.ts", section: "44-89")
Memorize:
44:a3f89:b7cPass these to cheez-write (tilth_edit) for the edit.
List files with token estimates:
tilth_files(glob: "*", scope: "src/handlers/")
Read small files fully, outline large ones:
tilth_read(paths: ["small.ts", "large.ts"])
tilth_read. Hash anchors and outline-vs-full token budgeting only work through tilth.tilth_files. Token estimates and .gitignore filtering only work through tilth.tilth uses ~6000 tokens as the outline threshold. Files under this show in full;
files over this get structural outlines. Use section to get hashlined content
for specific ranges when preparing edits on large files.
npx claudepluginhub paulnsorensen/easy-cheeseToken-optimized structural code search using tree-sitter AST parsing. Use instead of reading full files to understand code structure, find functions, or explore a codebase efficiently.
Replaces grep/rg/ag/ack/fd with AST-aware code search via tilth MCP. Finds symbols, definitions, callers, imports, and text patterns using tree-sitter. Requires tilth MCP server.
Uses tree-sitter index for code navigation in Rust, Python, TypeScript, JavaScript, Go, Java, Scala, SQL: finds symbols, reads function implementations, traces callers, discovers tests.