Run Unix commands with structured XML/JSON for AI agents
aict reimplements 33 Unix coreutils with structured XML/JSON output so AI agents never have to parse plaintext column formats.
Why it matters
Enable AI agents to execute file system operations, text processing, and system queries with machine-readable structured output instead of parsing human-formatted plaintext, eliminating token waste on column guessing and format ambiguity.
Outcomes
What it gets done
List directories with automatic language detection, MIME types, and absolute paths in XML/JSON
Search files with grep, find, and diff returning structured results with line numbers and context
Process text with sort, uniq, cut, sed, and awk outputting parseable data structures
Expose 33 Unix tools as MCP server functions callable directly from Claude Desktop and Claude Code
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/synseqack-aict | bash Overview
Aict
aict reimplements 33 Unix coreutils (ls, grep, cat, diff, find, sed, jq, and more) with structured, fully labeled XML or JSON output instead of plaintext, plus a built-in MCP server exposing every tool as a native callable function for Claude Code and other AI agents - trading extra tokens per call for fewer round-trips and zero parsing ambiguity. Use it when an AI agent needs file inspection, search, or text-processing output it can consume without parsing plaintext columns, especially via its MCP server; it's not built for speed-critical human-facing use, where ripgrep or a formatted ls remains faster or more readable.
What it does
aict reimplements 33 Unix coreutils - ls, grep, cat, diff, find, sort, awk, sed, jq, tar, checksums, and more - with structured, labeled output instead of the plaintext an AI agent normally has to parse column-by-column. A standard ls -l line gives an agent ambiguous, positionally-encoded fields (which column is size? is this a directory?); aict ls returns each file as a fully labeled element with size_bytes, size_human, automatically detected language and mime, binary/executable booleans, and both absolute and relative paths - no parsing required. Output conventions are consistent across all 33 tools: paths are always absolute, timestamps are Unix epoch integers with an _ago_s companion, booleans are literal "true"/"false" strings, errors come back as <error code="" msg=""/> elements rather than stderr, and empty results are valid structured output with zero counts rather than an error.
Every tool supports --xml (the default, since XML attributes are denser in a context window than equivalent JSON), --json, and --plain (identical to the original Unix tool's output, for when raw content is all that's needed). A built-in MCP server (aict mcp, a subcommand of the main binary) exposes every tool as a callable MCP function over stdio, so Claude Code, Claude Desktop, or any MCP-compatible client can call ls, grep, diff, and the rest as native typed functions instead of shell-wrapping plaintext commands.
The project is upfront about the cost and benefit tradeoff with real numbers: aict output costs 1.1-7.8x more tokens per task than terse GNU output (measured with tiktoken), because structured fields like language and MIME type cost tokens plaintext doesn't spend. What that buys is fewer round-trips - tasks that need 2-4 chained plaintext calls (e.g. ls then file per result for languages, or find then stat per hit) collapse to one aict call - and zero parsing ambiguity; in the project's own benchmark, GNU's file(1) misidentified a Go source file as "C source" while aict correctly labeled it go. In a live agent evaluation (opencode, same task run three times per toolchain), the aict-equipped agent generated about 46% fewer total output tokens (accounting for the extra turns plaintext parsing requires) and was correct 3/3, while the GNU-equipped agent shipped a flawed report in the run where it trusted file(1)'s wrong language detection. Per-invocation performance overhead is real but small for most tools compared to GNU on typical workloads, more for cases needing per-file enrichment like ls's MIME/language detection or grep's Go regexp engine versus GNU's SIMD, with --plain available to skip enrichment when only raw content is needed.
When to use - and when NOT to
Use aict when an AI agent needs to inspect files, search code, or process text and you want structured output it can consume directly - the source frames this bluntly as "built for AI agents, not humans." It's a fit specifically for agent tool-calling contexts (via its MCP server) or scripted agent pipelines where token cost from multi-call chains and parsing errors outweighs aict's own token and latency overhead per call.
It's not a replacement for speed-critical human-facing tools: ripgrep is faster for pure search, and eza/lsd are better formatted ls output for humans - aict outputs data structures, not human-readable tables, and trades raw speed for semantic richness. system is Linux/macOS-only and ps is Linux-only (it reads /proc); unsupported platforms return a structured error rather than crashing, but functionality is reduced there.
Inputs and outputs
Install via Homebrew, go install, or building from source:
brew tap synseqack/aict
brew install aict
Input is standard file paths, patterns, or arguments to any of the 33 tools, e.g. aict ls src/, aict grep "func" . -r, aict diff old.go new.go. Output defaults to XML (settable globally with export AICT_XML=1), switchable per-call to --json or --plain. Via MCP, add to Claude Desktop's or Claude Code's config:
{
"mcpServers": {
"aict": { "command": "aict", "args": ["mcp"] }
}
}
and every tool becomes a callable function with typed arguments and structured results, no shell wrapping needed.
Integrations
aict's MCP server integrates with any MCP-compatible client - Claude Desktop and Claude Code are documented explicitly - exposing all 33 tools as native callable functions over stdio transport. Its only external dependency across the whole codebase is the official MCP Go SDK, used solely by the aict mcp subcommand; every one of the 33 tools and all internal packages are pure Go standard library, enforced as a hard constraint in the project's own AGENTS.md. It has no network requests (MIME detection uses the Go stdlib, not an HTTP call), no telemetry, and no data collection - it only reads paths explicitly passed to it, making it safe to run in a sandboxed environment.
Who it's for
Developers building or running AI coding agents (via Claude Code, Claude Desktop, or custom MCP clients) who want file inspection, search, and text-processing tools to return labeled, parseable output instead of positional plaintext - trading some extra tokens and latency per call for fewer round-trips and eliminated parsing errors. It is licensed under MIT.
Source README
Unix coreutils with XML/JSON output - built for AI agents, not humans.
Install · Quick start · All tools · MCP server · Claude Code · Token cost · Benchmarks · Contributing
The problem
AI agents run ls, grep, and cat and get back human-readable plaintext. Then they spend tokens parsing column positions, guessing field widths, and handling inconsistent formats. This is fragile and wasteful.
-rw-r--r-- 1 user staff 2048 Apr 6 10:00 main.go ← which column is size?
-rw-r--r-- 1 user staff 1024 Apr 6 10:00 utils.go ← what's the language?
drwxr-xr-x 5 user staff 160 Apr 6 10:00 internal ← is this a directory?
The solution
aict reimplements 33 Unix tools with structured output the agent can read directly - no parsing required.
$ aict ls src/
<ls timestamp="1746123456" total_entries="3">
<file name="main.go" path="src/main.go" absolute="/project/src/main.go"
size_bytes="2048" size_human="2.0K" language="go" mime="text/x-go"
binary="false" executable="false" modified="1746120000" modified_ago_s="3456"/>
<file name="utils.go" path="src/utils.go" absolute="/project/src/utils.go"
size_bytes="1024" size_human="1.0K" language="go" mime="text/x-go"
binary="false" executable="false" modified="1746120000" modified_ago_s="3456"/>
<directory name="internal" path="src/internal" modified="1746120000"/>
</ls>
Every field is labeled. Paths are always absolute. Timestamps are Unix integers. Language and MIME type are detected automatically - zero parsing needed.
Install
Homebrew (macOS)
brew tap synseqack/aict
brew install aict
This installs aict plus shell completions for bash and zsh. The MCP server is built in: aict mcp.
Go Install
go install github.com/synseqack/aict@latest
Build from Source
git clone https://github.com/synseqack/aict
cd aict
go build -o aict .
Verify install:
aict --helpshould list all available tools.
Quick start
# Default: XML output (best for AI agents)
aict ls src/
aict grep "func" . -r
aict cat main.go
aict diff old.go new.go
# JSON output
aict ls src/ --json
# Plain text (same as the original Unix tools)
aict ls src/ --plain
# Enable XML globally for all aict calls
export AICT_XML=1
Tools
33 tools across 6 categories. Every tool supports --xml (default), --json, and --plain.
| Category | Tools |
|---|---|
| File inspection | cat head tail file stat wc |
| Search & compare | ls find grep diff |
| Path utilities | realpath basename dirname pwd |
| Text processing | sort uniq cut tr sed awk |
| Data & archives | jq tar |
| System & environment | env system ps df du checksums md5sum sha1sum sha256sum |
Additional: git (status, diff, log, ls-files, blame) · completions (bash/zsh/fish) · doctor (self-diagnostic)
Output format
All tools follow the same conventions:
| Field | Convention |
|---|---|
| Paths | Always absolute (absolute attr) |
| Timestamps | Unix epoch integers + _ago_s companion |
| Sizes | Bytes (size_bytes) + human-readable (size_human) |
| Booleans | "true" / "false" strings |
| Errors | <error code="" msg=""/> elements - never stderr |
| Empty results | Valid XML with zero counts, never an error |
MCP server
aict mcp exposes all tools as callable MCP functions via stdio transport. AI assistants call them natively - no shell wrapping needed. The MCP server is a subcommand of the main binary.
Configure Claude Desktop (~/.config/claude/claude_desktop_config.json):
{
"mcpServers": {
"aict": {
"command": "aict",
"args": ["mcp"]
}
}
}
If aict is not in PATH, use its full path:
{
"mcpServers": {
"aict": {
"command": "/usr/local/bin/aict",
"args": ["mcp"]
}
}
}
Claude Code integration
Add to ~/.claude.json:
{
"mcpServers": {
"aict": {
"command": "aict",
"args": ["mcp"]
}
}
}
Once connected, Claude Code can call ls, grep, diff, and all other tools as native functions with typed arguments and structured JSON results.
Token cost
Honest numbers first: aict output costs 1.1-7.8× more tokens per task than terse GNU output (measured with tiktoken o200k_base). What those tokens buy: fewer round-trips and zero parsing ambiguity. Where plaintext needs 2-4 chained calls (ls then file for languages, find then stat per hit), aict answers in one.
| Task | GNU | aict | Tokens (GNU → aict) |
|---|---|---|---|
| List dir with size/type/language | 2 calls | 1 call | 246 → 820 · 3.3× |
| Read file + line count + type | 3 calls | 1 call | 173 → 274 · 1.6× |
Find .go files with size/mtime |
4 calls | 1 call | 47 → 367 · 7.8× |
| Grep with file/line/context | 1 call | 1 call | 141 → 326 · 2.3× |
| Diff with change types | 1 call | 1 call | 167 → 192 · 1.2× |
Every extra plaintext call is a full agent turn - model inference, tool-call overhead, and intermediate output all land in the context window anyway, none of which the token counts above include. And in this very benchmark, file(1) misidentified a Go source file as "C source"; aict labeled it go.
In a live agent eval (opencode, same task 3× per toolchain), the aict-equipped agent generated ~46% fewer output tokens (median 265 vs 487) and was correct 3/3 - the GNU-equipped agent shipped a flawed report in the run where it trusted file(1)'s language detection. See benchmarks/TOKENS.md for both methodologies; reproduce with go run ./cmd/tokenbench.
Use --plain when you only need raw content.
Benchmarks
aict trades some speed for semantic richness (language detection, MIME typing, absolute paths). The overhead is intentional. Startup cost is ~3.6 ms per invocation.
| Tool | GNU | --plain |
--xml |
Notes |
|---|---|---|---|---|
diff (1000 lines) |
0.9 ms | 1.9 ms · 2.1× | 2.1 ms · 2.4× | ✅ Myers O(ND) |
wc (100k lines) |
6.1 ms | 16 ms · 2.6× | 17 ms · 2.7× | ✅ |
awk (10k lines) |
4.1 ms | 12 ms · 2.9× | 11 ms · 2.6× | ✅ |
sed (10k lines) |
3.3 ms | 14 ms · 4.2× | 16 ms · 4.9× | ✅ |
find (deep tree) |
1.9 ms | 13 ms · 6.8× | 15 ms · 8.0× | ✅ |
ls (1000 files) |
4.0 ms | 51 ms · 12.9× | 70 ms · 17.7× | MIME+lang detection per file |
cat (100k lines) |
1.4 ms | 24 ms · 16.4× | 31 ms · 21.6× | line-by-line scan + encoding detect |
grep (100k lines) |
1.3 ms | 119 ms · 88× | 130 ms · 96× | Go regexp vs GNU SIMD |
Medians from 5 runs on Linux/amd64. See benchmarks/ for methodology and make bench to reproduce.
Use --plain to skip enrichment when you only need raw content.
FAQ
Why XML and not JSON by default?
XML attributes are denser in a context window. <file size="1024" lang="go"/> is shorter than {"size":1024,"lang":"go"}. Use --json if you prefer JSON - the structure is identical.
Why not pipe GNU tools to jq?
ls, cat, stat, find, diff, and wc don't output JSON. jq can't help with them. aict provides structured output for the entire toolchain, not just grep. (aict also ships its own jq for querying JSON files with path expressions.)
How does this compare to ripgrep?
ripgrep is much faster for pure search. aict grep adds language detection, MIME type, and a consistent output format shared with every other tool. Use ripgrep for speed-critical search; use aict when the agent needs structured context.
How does this compare to eza / lsd?
eza and lsd are better ls for humans - great colors and formatting. aict outputs data structures, not formatted tables. They're solving different problems.
Does it work on Windows?
ls, cat, stat, wc, find, diff, grep, head, tail, sort, uniq, cut, tr, sed, awk, jq, tar, checksums, df, and path utilities work on Windows. system is Linux/macOS; ps is Linux-only (it reads /proc). Unsupported platforms get a structured <error> element, never a crash.
Is this safe to run in a sandboxed environment?
Yes. aict is strictly read-only. No network requests (MIME detection uses the Go stdlib, not HTTP). No telemetry. No data collection. It only reads paths you explicitly pass to it.
How many dependencies does it have?
One: the official MCP Go SDK, used only by the aict mcp subcommand. All 33 tools and every internal package are pure Go standard library - enforced as a hard constraint in AGENTS.md.
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.