mlx-code 0.0.6__tar.gz → 0.0.7__tar.gz

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.
@@ -0,0 +1,611 @@
1
+ Metadata-Version: 2.4
2
+ Name: mlx-code
3
+ Version: 0.0.7
4
+ Summary: Coding Agent for Mac
5
+ Home-page: https://github.com/JosefAlbers/mlx-code
6
+ Author: J Joe
7
+ Author-email: albersj66@gmail.com
8
+ License: Apache-2.0
9
+ Requires-Python: >=3.12.8
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+ Requires-Dist: mlx-lm>=0.31.3
13
+ Requires-Dist: numpy
14
+ Requires-Dist: httpx
15
+ Requires-Dist: pydantic
16
+ Dynamic: author
17
+ Dynamic: author-email
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: license
22
+ Dynamic: license-file
23
+ Dynamic: requires-dist
24
+ Dynamic: requires-python
25
+ Dynamic: summary
26
+
27
+ # mlx-code
28
+
29
+ A lightweight coding agent for Mac, built on Apple's MLX framework. Fast local inference, built-in prompt caching, robust tool-calling.
30
+
31
+ [![Link](https://raw.githubusercontent.com/JosefAlbers/mlx-code/main/assets/mlx-code.gif)](https://youtu.be/bizPhrHL1_w)
32
+
33
+ Modern coding agents are like luxury apartments: impressive and shiny, but you don't hold the deed. The company behind the tool can raise the rent, change the features, or change the locks whenever they please.
34
+
35
+ I wanted a [backyard shed](https://poyo.co/note/20260202T150723/) for myself. Something I understand end to end, can break on purpose, and fix without filing a support ticket.
36
+
37
+ mlx-code is that shed. It’s deliberately minimal, extremely transparent, and designed around one core idea: the feedback [loop](https://www.robert-glaser.de/what-if-iteration-is-all-we-need/) is the thing that matters, not the interface around it. The tighter and faster you can close the loop between intent and output, the better the work gets. Everything else is ceremony.
38
+
39
+ So the terminal stays the interface. Text in, text out. No full-screen TUI fighting your terminal emulator, no proprietary context format, no behavior that shifts between versions.
40
+
41
+ **Just a loop you control, composed from Unix primitives you already know.**
42
+
43
+ ## How It Works
44
+
45
+ mlx-code has two lightweight, loosely coupled pieces:
46
+
47
+ - **main.py**: A clean MLX server for Apple Silicon. It loads quantized models and exposes a standard OpenAI-compatible completions endpoint.
48
+ - **pie.py** — A minimal but powerful agent harness (Python port of Mario Zechner's awesome [pi](https://github.com/badlogic/pi-mono)).
49
+
50
+ The CLI is intentionally boring and familiar:
51
+
52
+ - `mc` — Local agent (MLX server + pie REPL)
53
+ - `me` — Remote agent (pie REPL against Claude, DeepSeek, Gemini, etc.)
54
+ - `md` — View and filter structured JSON logs
55
+
56
+ Agentic work lives on a spectrum from tight, synchronous co-driving to loose, asynchronous delegation — the right tool for both ends is a loop that closes quickly, not a UI that abstracts it away. Text streams compose. They pipe. They chain. They work the same way they did thirty years ago and will work thirty years from now. That's the constraint that shapes the whole tool.
57
+
58
+ ## Features
59
+
60
+ - **Multi-Provider Compatibility**: Translates and handles requests formatted for Claude, Gemini, Codex, and DeepSeek.
61
+ - **Built-in REPL & Tools**: `pie` is a fully-featured REPL with tool execution and reasoning token support.
62
+ - **Prompt Caching**: KV cache is saved to disk and reused across requests automatically.
63
+ - **Server Mode**: Spin up a local LLM server with one command.
64
+
65
+ ### Quick Start
66
+
67
+ Install via pip and launch the agent immediately:
68
+
69
+ ```bash
70
+ pip install mlx-code
71
+ mc
72
+ ```
73
+
74
+ ## Command Line Interfaces
75
+
76
+ ### `mc` — Local agent (MLX server + harness)
77
+
78
+ ```bash
79
+ # Default: starts local MLX server and launches pie REPL
80
+ mc
81
+
82
+
83
+ # Choose a different harness
84
+ mc --leash gemini
85
+ mc --leash codex
86
+ mc --leash claude
87
+ mc --leash pie
88
+
89
+ # Use a local model
90
+ mc --model mlx-community/Qwen3.5-4B-OptiQ-4bit
91
+ mc --leash none # server only, no harness
92
+
93
+ # Change server address
94
+ mc --host 0.0.0.0 --port 9000
95
+
96
+ # Limit available tools
97
+ mc --tools Ls ReadTree Edit
98
+
99
+ # Shell piping and chaining
100
+ echo "explain symgraph.py" | mc -d | cat - PLAN.md | mc
101
+ ```
102
+
103
+ ### `me` — Remote agent (pie REPL against any API)
104
+
105
+ ```bash
106
+ # Default: connects to local server at 127.0.0.1:8000
107
+ me
108
+
109
+ # Use a remote provider
110
+ me --api deepseek
111
+ me --api claude
112
+ me --api gemini
113
+ me --api codex
114
+
115
+ # Use a specific model
116
+ me --api deepseek --model deepseek-chat
117
+
118
+ # Point at a custom endpoint
119
+ me --url http://localhost:9000
120
+ ```
121
+
122
+ ### `md` — Log viewer
123
+
124
+ View and filter structured JSON logs from any session.
125
+
126
+ ```bash
127
+ md
128
+ md --filter lvl:10;file:main,pie
129
+ md --out picks
130
+ ```
131
+
132
+ ## Credits
133
+
134
+ - `main.py`: Built on [mlx](https://github.com/ml-explore/mlx) and [mlx-lm](https://github.com/ml-explore/mlx-lm) by Apple.
135
+ - `pie.py`: Adapted from [pi](https://github.com/badlogic/pi-mono) by Mario Zechner (MIT License).
136
+
137
+ ## Licence
138
+
139
+ Apache License 2.0 — see LICENSE for details.
140
+
141
+ <details><summary>...</summary><pre>
142
+
143
+ ~/tmp> mc
144
+
145
+ pie REPL • type /help for commands, Ctrl-D or 'exit' to quit.
146
+
147
+ ≫ hi
148
+ π The user is just saying "hi" - this is a simple greeting. I should respond in a friendly way and offer to help them with something.
149
+ Hello! How can I help you today?
150
+ ≫ how many files in current dir?
151
+ π The user wants to know how many files are in the current directory. I can use the Ls function to list the directory contents and count the files.
152
+ Ls
153
+ Looking at the directory listing, I can see:
154
+ - LICENSE (file)
155
+ - README.md (file)
156
+ - cache/ (directory)
157
+ - log.json (file)
158
+ - mlx_code/ (directory)
159
+ - mlx_code.egg-info/ (directory)
160
+ - setup.py (file)
161
+
162
+ So there are 4 files and 3 directories in the current directory.
163
+ There are **4 files** in the current directory:
164
+ - LICENSE
165
+ - README.md
166
+ - log.json
167
+ - setup.py
168
+
169
+ And **3 directories**:
170
+ - cache/
171
+ - mlx_code/
172
+ - mlx_code.egg-info/
173
+
174
+ Bye!
175
+
176
+ ~/tmp> gg **/*.py
177
+
178
+ staging: mlx_code/__init__.py
179
+ exists
180
+ staging: mlx_code/log.py
181
+ exists
182
+ staging: mlx_code/main.py
183
+ exists
184
+ staging: mlx_code/pie.py
185
+ exists
186
+ staging: mlx_code/symgraph.py
187
+ exists
188
+ staging: setup.py
189
+ exists
190
+
191
+ Diff preview:
192
+ mlx_code/__init__.py | 4 +
193
+ mlx_code/log.py | 771 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
194
+ mlx_code/main.py | 1597 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
195
+ mlx_code/pie.py | 1994 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
196
+ mlx_code/symgraph.py | 483 +++++++++++++++++++++++++++++++++++
197
+ setup.py | 18 ++
198
+ 6 files changed, 4867 insertions(+)
199
+
200
+ Show per-file diffs? [s=skip]: y
201
+
202
+ --- mlx_code/__init__.py ---
203
+ @@ -0,0 +1,4 @@
204
+ +from .main import serve, run
205
+ +from .pie import harness
206
+ +
207
+ +__all__ = ["serve", "run", "harness"]
208
+ --- mlx_code/log.py ---
209
+ ... ( 772 lines total, truncated)
210
+ + if args.out:
211
+ + with open(args.out, "w", encoding="utf-8") as f:
212
+ + for idx in sorted(marked):
213
+ + f.write(json.dumps(logs[idx]) + "\n")
214
+ + else:
215
+ + for idx in sorted(marked):
216
+ + print(json.dumps(logs[idx]))
217
+ +
218
+ +if __name__ == "__main__":
219
+ + main()
220
+ --- mlx_code/main.py ---
221
+ ... ( 1598 lines total, truncated)
222
+ + model=args.model,
223
+ + system=system,
224
+ + tools=args.tools,
225
+ + skill=args.skill,
226
+ + leash_args=leash_args,
227
+ + )
228
+ +
229
+ +if __name__ == "__main__":
230
+ + main()
231
+ +# }}}ser
232
+ --- mlx_code/pie.py ---
233
+ ... ( 1995 lines total, truncated)
234
+ + cwd=args.cwd,
235
+ + model=model,
236
+ + base_url=url,
237
+ + tools=tools,
238
+ + sdir=args.skill,
239
+ + api_key=api_key
240
+ + )
241
+ +
242
+ +if __name__ == "__main__":
243
+ + main()
244
+ --- mlx_code/symgraph.py ---
245
+ ... ( 485 lines total, truncated)
246
+ + B,H=search_symbols(A.symbols,C,lang_ext=E,include_references=not A.no_references,include_context=A.context,warn_skipped=A.warn_skipped);G=_C
247
+ + for(I,J)in H.items():
248
+ + if J is Capability.NONE:_warn(f"'{I}': no matching identifiers found (grammar may be unsupported for this file type)");G=_E
249
+ + if A.kinds:B=[B for B in B if B.kind in A.kinds]
250
+ + if A.json:print(json.dumps([A.as_dict()for A in B],indent=2))
251
+ + else:print_usages(B,F)
252
+ + if G and not B:return 2
253
+ + return 0
254
+ +if __name__=='__main__':sys.exit(main())
255
+
256
+ --- setup.py ---
257
+ ... ( 19 lines total, truncated)
258
+ + version="0.0.7",
259
+ + readme="README.md",
260
+ + description="Coding Agent for Mac",
261
+ + long_description=open("README.md").read(),
262
+ + long_description_content_type="text/markdown",
263
+ + python_requires=">=3.12.8",
264
+ + install_requires=["mlx-lm>=0.31.3", "numpy", "httpx", "pydantic"],
265
+ + packages=find_packages(),
266
+ + entry_points={"console_scripts": ["mc=mlx_code.main:main", "md=mlx_code.log:main", "me=mlx_code.pie:main"]},
267
+ +)
268
+
269
+ read> v0.0.7
270
+ Saved snapshot d2ab186ee5c02f0589552ffac658c4f4a284b36c
271
+
272
+ ~/tmp> mc
273
+
274
+ pie REPL • type /help for commands, Ctrl-D or 'exit' to quit.
275
+
276
+ ≫ explain sittree.py
277
+ π The user is asking me to explain a file called "sittree.py". I should first read this file to understand what it does. Let me use the Read function to read the file.
278
+ Read {"path": "sittree.py"}
279
+ This is a comprehensive file. Let me provide a clear explanation of what this file does.
280
+ # sittree.py — Symbol Usage Finder & Codebase Outliner
281
+
282
+ This is a **tree-sitter-based code analysis tool** for coding agents. It provides two main capabilities:
283
+
284
+ ## 🎯 Core Features
285
+
286
+ ### 1. **Codebase Outlining**
287
+ Shows all top-level symbols (functions, classes, variables, types, etc.) in a file or directory.
288
+
289
+ **Usage:**
290
+ ```bash
291
+ python sittree.py <path> # Outline symbols
292
+ python sittree.py <path> --depth 2 # Include nested symbols
293
+ python sittree.py <path> --context # Show source context
294
+ ```
295
+
296
+ ### 2. **Symbol Search**
297
+ Finds all usages of specific symbols across a codebase.
298
+
299
+ **Usage:**
300
+ ```bash
301
+ python sittree.py <path> myFunc myClass # Search for symbols
302
+ python sittree.py <path> myFunc --kinds definition # Filter by kind
303
+ ```
304
+
305
+ ## 📋 Supported Languages
306
+
307
+ | Extension | Language |
308
+ |-----------|----------|
309
+ | `.py` | Python |
310
+ | `.js`, `.jsx`, `.ts`, `.tsx` | JavaScript/TypeScript |
311
+ | `.go` | Go |
312
+ | `.rs` | Rust |
313
+ | `.java` | Java |
314
+ | `.c`, `.cpp`, `.cc`, `.cs` | C/C++/C# |
315
+ | `.rb` | Ruby |
316
+ | `.php` | PHP |
317
+ | `.swift`, `.kt` | Swift/Kotlin |
318
+ | `.lua`, `.hs`, `.ex`, `.exs` | Lua/Haskell/Elixir |
319
+ | `.r`, `.sh` | R/Bash |
320
+ | `.toml`, `.yaml`, `.yml` | Config files |
321
+
322
+ ## 🔍 Key Capabilities
323
+
324
+ ### Symbol Kinds Detected
325
+ - **definition** — Function/class/type definitions
326
+ - **assignment** — Variable declarations
327
+ - **call** — Function/method calls
328
+ - **import** — Import statements
329
+ - **reference** — Bare identifier references
330
+
331
+ ### Language-Specific Features
332
+ - **Python**: Handles `__main__` entry points, decorated functions, augmented assignments
333
+ - **JavaScript/TypeScript**: Handles ES6+ features (arrow functions, destructuring, type aliases)
334
+ - **Go**: Handles methods, type specs, package-level declarations
335
+ - **Rust**: Handles traits, structs, enums, visibility modifiers
336
+ - **Java**: Handles classes, interfaces, enums, method invocations
337
+
338
+ ## 🛠️ Technical Details
339
+
340
+ ### Tree-Sitter Integration
341
+ - Uses **bespoke queries** for languages with rich grammar support
342
+ - Falls back to **generic identifier scanning** for simpler languages
343
+ - Caches parsers and queries for performance
344
+
345
+ ### Output Formats
346
+ - **Human-readable**: Color-coded with line numbers and context
347
+ - **JSON**: Machine-parseable output via `--json` flag
348
+ - **Raw**: Paste-safe source bodies for editing
349
+
350
+ ### Advanced Features
351
+ - **Context snippets**: Show surrounding source lines
352
+ - **Entry point detection**: Identify `main()`, `__main__`, etc.
353
+ - **Export detection**: Find public/exported symbols
354
+ - **Destructuring binding extraction**: Handle complex patterns like `[a, b]` or `{x, y}`
355
+
356
+ ## 💡 Use Cases
357
+
358
+ 1. **Codebase exploration**: Get an overview of a project's structure
359
+ 2. **Symbol search**: Find all usages of a function/class
360
+ 3. **Refactoring support**: Locate all references before renaming
361
+ 4. **Documentation generation**: Extract API surface information
362
+ 5. **Agent assistance**: Provide context for code review/editing tasks
363
+
364
+ ## ⚙️ Configuration Options
365
+
366
+ | Option | Description |
367
+ |--------|-------------|
368
+ | `--lang` | Override language detection |
369
+ | `--depth` | Max nesting depth for outline |
370
+ | `--context` | Include source context |
371
+ | `--no-references` | Skip bare identifier hits |
372
+ | `--kinds` | Filter by symbol kind |
373
+ | `--warn-skipped` | Show grammar load errors |
374
+
375
+ ---
376
+
377
+ This tool is designed to work seamlessly with coding agents, providing structured code analysis that's both human-readable and machine-parseable.
378
+
379
+ Bye!
380
+
381
+ ~/tmp> mc --tools ReadTree
382
+
383
+ pie REPL • type /help for commands, Ctrl-D or 'exit' to quit.
384
+
385
+ ≫ explain sittree.py
386
+ π The user is asking me to explain sittree.py. I should first read this file to understand what it does. Let me use the ReadTree function to inspect this file.
387
+ ReadTree {"path": "sittree.py"}
388
+ This is a Python file that appears to be a tool for inspecting source code using tree-sitter. It has various functions for handling different programming languages (Python, JS, Go, Rust, Java), extracting bindings, finding symbols, and printing outlines. Let me read the full file to provide a comprehensive explanation.
389
+ ReadTree {"path": "sittree.py", "depth": "2"}
390
+ I need to read the actual file content to understand what it does. Let me read the file directly.
391
+ ReadTree {"path": "sittree.py", "symbols": "[\"main\", \"SymbolFinder\", \"Capability\", \"outline_path\", \"search_symbols\", \"print_outline\"]"}
392
+ Now I have a good understanding of the file. Let me provide a comprehensive explanation of what sittree.py does.
393
+ # sittree.py - Source Code Tree Inspector
394
+
395
+ This is a **tree-sitter-based source code analysis tool** that can inspect, search, and outline code across multiple programming languages. It's designed to work with the tree-sitter parser library for accurate AST (Abstract Syntax Tree) parsing.
396
+
397
+ ## 🎯 Main Features
398
+
399
+ ### 1. **Symbol Search**
400
+ - Find specific symbols (functions, classes, variables, etc.) in source files
401
+ - Supports multiple programming languages: Python, JavaScript, TypeScript, Go, Rust, Java
402
+ - Can search directories recursively
403
+ - Includes reference tracking and context lines
404
+
405
+ ### 2. **Code Outlining**
406
+ - Generate hierarchical outlines of files/directories
407
+ - Shows entry points, exported symbols, and line ranges
408
+ - Supports depth limiting for large projects
409
+
410
+ ### 3. **Multi-Language Support**
411
+ - Uses bespoke queries for Python, JS, Go, Rust, Java
412
+ - Falls back to generic identifier scanning when no bespoke query exists
413
+ - Handles UTF-8 encoding issues with proper character decoding
414
+
415
+ ## 📦 Key Components
416
+
417
+ ### **Capability Enum**
418
+ ```python
419
+ class Capability(str, Enum):
420
+ FULL = "full" # Bespoke queries with correct semantics
421
+ PARTIAL = "partial" # Generic identifier scan (kind is always 'reference')
422
+ NONE = "none" # Grammar has no identifier-like nodes
423
+ ```
424
+
425
+ ### **SymbolFinder Class**
426
+ - Core class for searching symbols in files
427
+ - Handles symbol matching with proper UTF-8 decoding
428
+ - Groups results by original symbol name
429
+ - Supports references and context inclusion
430
+
431
+ ### **Main Functions**
432
+ - `outline_path()`: Recursively outline files/directories
433
+ - `search_symbols()`: Search for multiple symbols in a file/directory
434
+ - `print_outline()`: Display formatted code outlines
435
+ - `print_usages()`: Display symbol usage information
436
+
437
+ ## 🚀 Command-Line Usage
438
+
439
+ ```bash
440
+ # Outline mode - show code structure
441
+ python sittree.py /path/to/file --lang py
442
+
443
+ # Search mode - find symbols
444
+ python sittree.py /path/to/file --symbols "my_function" --lang py
445
+
446
+ # Search in directory
447
+ python sittree.py /path/to/dir --symbols "class" --lang py
448
+
449
+ # JSON output
450
+ python sittree.py /path/to/file --symbols "my_function" --json
451
+ ```
452
+
453
+ ## 🔧 Technical Details
454
+
455
+ ### **Query System**
456
+ - Uses tree-sitter queries for precise symbol matching
457
+ - Supports `definition`, `assignment`, `call`, and `import` kinds
458
+ - Has priority ordering for different node kinds
459
+
460
+ ### **Language Extensions**
461
+ - Maps file extensions to language packages
462
+ - Supports both extension-based and explicit language specification
463
+ - Handles files with unexpected extensions when `--lang` is specified
464
+
465
+ ### **Error Handling**
466
+ - Returns exit code 2 for grammar failures (distinct from path errors)
467
+ - Warns when grammars are unavailable for certain file types
468
+ - Handles non-UTF-8 source files gracefully
469
+
470
+ ## 💡 Use Cases
471
+
472
+ 1. **IDE Integration**: Provides the foundation for a code search/outline feature
473
+ 2. **Static Analysis**: Find symbols across large codebases
474
+ 3. **Documentation Generation**: Create code structure maps
475
+ 4. **Refactoring Support**: Locate all usages of a symbol before renaming
476
+
477
+ The tool is particularly useful for developers who need precise, language-aware code navigation and search capabilities without relying on IDE-specific features.
478
+
479
+ ~/tmp> python log.py -o test
480
+
481
+ ┌─ logs ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐┌─ detail ──────────────────────────────────────────────────────────────────────────┐
482
+ │ TIME LVL FILE FUNC MESSAGE …││ time : 2026-05-09T17:35:17.021887+00:00 │
483
+ │ 17:35:01 DEBUG main.py main args=Namespace(model='mlx-community/Qwen3.5-4B-OptiQ-4bit', leash='…││ level : DEBUG │
484
+ │ 17:35:03 DEBUG main.py serve Server bound to http://127.0.0.1:8000 ││ logger : root │
485
+ │ 17:35:03 WARNING pie.py __init__ No api-key ││ file : tmp/main.py │
486
+ │ 17:35:15 DEBUG pie.py repl explain sittree.py ││ function : encode │
487
+ │ 17:35:15 DEBUG pie.py stream { "model": "jj", "max_tokens": 8192, "messages": [ { "role": "syste…││ line : 684 │
488
+ │ 17:35:15 DEBUG main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ id : f8e15ee6-aaa5-4532-8735-172d6a7b9707 │
489
+ │ 17:35:15 DEBUG main.py translate messages=[Message(role='system', content='Available skills (use Get…││ │
490
+ │ 17:35:15 DEBUG main.py encode ckpts=[1898] <|im_start|>system # Tools You have access to the foll…││ ── message ── │
491
+ │ 17:35:15 DEBUG main.py __call__ ckpts=[1898] len(prompt)=1909 len(self.hx)=0 cl=0 ││ ckpts=[1898] │
492
+ │ 17:35:15 DEBUG main.py load cache/mlxcommunityQwen354BOptiQ4bit_1898_21d53f79d6f145d5.safetenso…││ <|im_start|>system │
493
+ │ 17:35:15 DEBUG main.py generate Processed 1909 input tokens in 0 seconds (11222 tokens per second) ││ # Tools │
494
+ │ 17:35:16 INFO main.py generate The user is asking me to explain a file called "sittree.py". I shou…││ │
495
+ │ 17:35:16 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='The user is ask…││ You have access to the following functions: │
496
+ │ 17:35:16 INFO pie.py _execute_one # sittree.py (lines 1–1266 of 1266) """ sittree.py — Symbol usage f…││ │
497
+ │ 17:35:16 DEBUG pie.py stream { "model": "jj", "max_tokens": 8192, "messages": [ { "role": "syste…││ <tools> │
498
+ │ 17:35:16 DEBUG main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ {"type": "function", "function": {"name": "Read", "description": "Read a file. Us │
499
+ │ 17:35:16 DEBUG main.py translate messages=[Message(role='system', content='Available skills (use Get…││ e offset/limit for large files instead of reading the whole thing.", "parameters" │
500
+ │>17:35:17 DEBUG main.py encode ckpts=[1898] <|im_start|>system # Tools You have access to the foll…││ : {"type": "object", "properties": {"path": {"description": "File path to read (r │
501
+ │ 17:35:17 DEBUG main.py __call__ ckpts=[1898] len(prompt)=14602 len(self.hx)=1979 cl=1979 ││ elative to cwd)", "title": "Path", "type": "string"}, "offset": {"anyOf": [{"type │
502
+ │ 17:35:17 DEBUG main.py __call__ cont ││ ": "integer"}, {"type": "null"}], "default": null, "description": "Start line (1- │
503
+ │ 17:35:47 DEBUG main.py generate Processed 14602 input tokens in 31 seconds (476 tokens per second) ││ based)", "title": "Offset"}, "limit": {"anyOf": [{"type": "integer"}, {"type": "n │
504
+ │ 17:36:02 INFO main.py generate This is a comprehensive file. Let me provide a clear explanation of…││ ull"}], "default": null, "description": "Max lines to read", "title": "Limit"}}, │
505
+ │ 17:36:02 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='This is a compr…││ "required": ["path"]}}} │
506
+ │ ││ {"type": "function", "function": {"name": "Write", "description": "Create or over │
507
+ │ ││ write a file. Prefer 'edit' for small changes to existing files.", "parameters": │
508
+ │ ││ {"type": "object", "properties": {"path": {"description": "File path to create or │
509
+ │ ││ overwrite (relative to cwd)", "title": "Path", "type": "string"}, "content": {"d │
510
+ │ ││ escription": "Full file content", "title": "Content", "type": "string"}}, "requir │
511
+ │ ││ ed": ["path", "content"]}}} │
512
+ │ ││ {"type": "function", "function": {"name": "Edit", "description": "Replace an exac │
513
+ │ ││ t unique string in a file. Read the file first if unsure of exact text.", "parame │
514
+ │ ││ ters": {"type": "object", "properties": {"path": {"description": "File path to ed │
515
+ │ ││ it (relative to cwd)", "title": "Path", "type": "string"}, "old_text": {"descript │
516
+ │ ││ ion": "Exact text to replace (must appear exactly once)", "title": "Old Text", "t │
517
+ │ ││ ype": "string"}, "new_text": {"description": "Replacement text", "title": "New Te │
518
+ │ ││ xt", "type": "string"}}, "required": ["path", "old_text", "new_text"]}}} │
519
+ │ ││ {"type": "function", "function": {"name": "Bash", "description": "Run a shell com │
520
+ │ ││ mand, get stdout+stderr. Prefer read/grep/find/ls for file exploration.", "parame │
521
+ │ ││ ters": {"type": "object", "properties": {"command": {"description": "Shell comman │
522
+ │ ││ d to execute", "title": "Command", "type": "string"}, "timeout": {"default": 120, │
523
+ │ ││ "description": "Timeout in seconds", "title": "Timeout", "type": "integer"}}, "r │
524
+ │ ││ equired": ["command"]}}} │
525
+ │ ││ {"type": "function", "function": {"name": "Grep", "description": "Search files fo │
526
+ │ ││ r a pattern. Respects .gitignore.", "parameters": {"type": "object", "properties" │
527
+ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘└───────────────────────────────────────────────────────────────────────────────────┘
528
+ All cef534bf-5 50e0af6d-1 b578ec4d-f f8e15ee6-a d25f55fd-2 9a03247f-e 5160a1d3-1
529
+ log.json │ 18/23 (of 592) filter: lvl:10;file:main,pie │ ↑/k ↓/j · PgUp/PgDn · g/G · n/N · * highlight · o open · ; filter · h/l tabs · v mark · q quit
530
+
531
+
532
+ ┌─ logs ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐┌─ detail ──────────────────────────────────────────────────────────────────────────┐
533
+ │ TIME LVL FILE FUNC MESSAGE …││ time : 2026-05-09T17:51:22.117961+00:00 │
534
+ │ 17:50:55 DEBUG main.py main args=Namespace(model='mlx-community/Qwen3.5-4B-OptiQ-4bit', leash='…││ level : DEBUG │
535
+ │ 17:50:57 DEBUG main.py serve Server bound to http://127.0.0.1:8000 ││ logger : root │
536
+ │ 17:50:57 WARNING pie.py __init__ No api-key ││ file : tmp/main.py │
537
+ │ 17:51:13 DEBUG pie.py repl explain sittree.py ││ function : encode │
538
+ │ 17:51:13 DEBUG pie.py stream { "model": "jj", "max_tokens": 8192, "messages": [ { "role": "syste…││ line : 684 │
539
+ │ 17:51:13 DEBUG main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ id : 5160a1d3-1552-40a7-a82e-ebaf3d0995f8 │
540
+ │ 17:51:13 DEBUG main.py translate messages=[Message(role='system', content='Available skills (use Get…││ │
541
+ │ 17:51:13 DEBUG main.py encode ckpts=[698] <|im_start|>system # Tools You have access to the follo…││ ── message ── │
542
+ │ 17:51:13 DEBUG main.py __call__ ckpts=[698] len(prompt)=709 len(self.hx)=0 cl=0 ││ ckpts=[698] │
543
+ │ 17:51:13 DEBUG main.py __call__ anew ││ <|im_start|>system │
544
+ │ 17:51:13 DEBUG main.py generate save_fn 698 ││ # Tools │
545
+ │ 17:51:15 DEBUG main.py save cache/mlxcommunityQwen354BOptiQ4bit_698_6f0ceeb516faea93.safetensor…││ │
546
+ │ 17:51:15 DEBUG main.py generate Processed 709 input tokens in 2 seconds (394 tokens per second) ││ You have access to the following functions: │
547
+ │ 17:51:16 INFO main.py generate The user is asking me to explain a file called "sittree.py". I shou…││ │
548
+ │ 17:51:16 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='The user is ask…││ <tools> │
549
+ │ 17:51:16 INFO pie.py _execute_one /private/var/folders/_5/vz_p3mls23l5rtlhj3nzvwjw0000gn/T/tmp8sx8z7…││ {"type": "function", "function": {"name": "ReadTree", "description": "Inspect sou │
550
+ │ 17:51:16 DEBUG pie.py stream { "model": "jj", "max_tokens": 8192, "messages": [ { "role": "syste…││ rce code using tree-sitter. Works for any supported language (Python, JS/TS, Go, │
551
+ │ 17:51:16 DEBUG main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ Rust, Java, C/C++, Ruby, and more). Two modes:\n OUTLINE (no symbols): returns t │
552
+ │ 17:51:16 DEBUG main.py translate messages=[Message(role='system', content='Available skills (use Get…││ he symbol tree of a file or directory — class/function/method/var names with line │
553
+ │ 17:51:16 DEBUG main.py encode ckpts=[698] <|im_start|>system # Tools You have access to the follo…││ ranges. Use this first to orient yourself before reading or editing code.\n SYM │
554
+ │ 17:51:16 DEBUG main.py __call__ ckpts=[698] len(prompt)=2211 len(self.hx)=792 cl=792 ││ BOL LOOKUP (symbols=[...]): returns the full source body of every definition of t │
555
+ │ 17:51:16 DEBUG main.py __call__ cont ││ hose names, plus every call/assignment site with context. Output is paste-safe fo │
556
+ │ 17:51:19 DEBUG main.py generate Processed 2211 input tokens in 3 seconds (660 tokens per second) ││ r use as old_str in an Edit call. Accepts dotted names like 'ClassName.method' to │
557
+ │ 17:51:22 INFO main.py generate This is a Python file that appears to be a tool for inspecting sour…││ narrow results.", "parameters": {"type": "object", "properties": {"path": {"desc │
558
+ │ 17:51:22 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='This is a Pytho…││ ription": "File or directory to inspect (relative to cwd)", "title": "Path", "typ │
559
+ │ 17:51:22 INFO pie.py _execute_one # DEF outline_path /private/var/folders/_5/vz_p3mls23l5rtlhj3nzvwjw…││ e": "string"}, "symbols": {"description": "Symbol names to look up, e.g. [\"MyCla │
560
+ │ 17:51:22 DEBUG pie.py stream { "model": "jj", "max_tokens": 8192, "messages": [ { "role": "syste…││ ss\", \"my_fn\", \"ClassName.method\"]. Omit (or pass []) for outline mode. Dotte │
561
+ │ 17:51:22 DEBUG main.py do_POST self.path='/v1/chat/completions' { "model": "jj", "max_tokens": 819…││ d names are accepted — the last component is matched and results are labelled wit │
562
+ │ 17:51:22 DEBUG main.py translate messages=[Message(role='system', content='Available skills (use Get…││ h the full qualified name.", "items": {"type": "string"}, "title": "Symbols", "ty │
563
+ │>17:51:22 DEBUG main.py encode ckpts=[698] <|im_start|>system # Tools You have access to the follo…││ pe": "array"}, "depth": {"default": 1, "description": "Outline mode: nesting dept │
564
+ │ 17:51:22 DEBUG main.py __call__ ckpts=[698] len(prompt)=6534 len(self.hx)=2354 cl=2354 ││ h (1=top-level only, 2=classes+methods).", "title": "Depth", "type": "integer"}, │
565
+ │ 17:51:22 DEBUG main.py __call__ cont ││ "kinds": {"description": "Filter symbol-lookup results by kind. Valid values: def │
566
+ │ 17:51:32 DEBUG main.py generate Processed 6534 input tokens in 10 seconds (660 tokens per second) ││ inition, assignment, call, import, reference. Default: definition + assignment + │
567
+ │ 17:51:43 INFO main.py generate Now I have a good understanding of the sittree.py file. Let me prov…││ call + import (no bare references).", "items": {"type": "string"}, "title": "Kind │
568
+ │ 17:51:43 DEBUG pie.py _loop AssistantMessage(content=[ThinkingContent(thinking='Now I have a go…││ s", "type": "array"}, "lang": {"anyOf": [{"type": "string"}, {"type": "null"}], " │
569
+ │ ││ default": null, "description": "Override language detection, e.g. 'py', 'ts', 'go │
570
+ │ ││ '.", "title": "Lang"}}, "required": ["path"]}}} │
571
+ │ ││ </tools> │
572
+ │ ││ │
573
+ │ ││ If you choose to call a function ONLY reply in the following format with NO suffi │
574
+ │ ││ x: │
575
+ │ ││ │
576
+ │ ││ <tool_call> │
577
+ │ ││ <function=example_function_name> │
578
+ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘└───────────────────────────────────────────────────────────────────────────────────┘
579
+ All cef534bf-5 50e0af6d-1 b578ec4d-f f8e15ee6-a d25f55fd-2 9a03247f-e 5160a1d3-1
580
+ log.json │ 30/35 (of 592) filter: lvl:10;file:main,pie │ ↑/k ↓/j · PgUp/PgDn · g/G · n/N · * highlight · o open · ; filter · h/l tabs · v mark · q quit
581
+
582
+ ~/tmp[1 jobs]> cat prompt test | me -a deepseek
583
+
584
+ Yes, it did — and by a **substantial margin**. Here’s the comparison from the logs you provided:
585
+
586
+ | | `Read` session (full file) | `ReadTree` session (outline + symbols) |
587
+ |----------------------|----------------------------|----------------------------------------|
588
+ | Tool calls | 1 (Read whole file) | 3 (outline, depth 2, symbol bodies) |
589
+ | Token count up to<br>final assistant response | **14,602** tokens | **7,827** tokens |
590
+ | **Savings** | — | **6,775 tokens fewer (≈46% reduction)** |
591
+
592
+ (That token count comes from the `---14602` and `---7827` markers at the end of the two conversation excerpts; both are measured at the same point — after the tool responses and assistant `think`, just before the final explanations are written.)
593
+
594
+ ## What made the difference
595
+
596
+ - **`Read`** dumped the entire 1,266‑line file into the context (≈35 KB of text, including all comments, blank lines, and internal helper logic).
597
+ - **`ReadTree`** only supplied:
598
+ 1. A one‑line‑per‑symbol outline (≈70 lines).
599
+ 2. The full source for *only* the 5 requested symbols (`Capability`, `outline_path`, `SymbolFinder`, `search_symbols`, `print_outline`, `main`) plus their call sites — a fraction of the file.
600
+
601
+ Everything the agent actually needed for a high‑level explanation was in that reduced set, so the rest of the file was just noise.
602
+
603
+ ## But was it “as good”?
604
+
605
+ As we covered earlier, the `ReadTree`‑based explanation was slightly less detailed — it missed some configuration flags, language lists, and advanced features that only appeared in the comments and constants of the full file. But for **understanding the tool’s structure and main capabilities**, it was perfectly sufficient. So you saved nearly half the context window while still getting a perfectly usable answer.
606
+
607
+ **Bottom line:** `ReadTree` is a sharp tool for context efficiency — it can slash input size dramatically for tasks like code explanation, and the smaller context window often allows the model to think faster and more focused.
608
+
609
+ ~/tmp[1 jobs]> hx --capture
610
+
611
+ </pre></details><br>