aifr — AI File Reader
A read-only filesystem and git-tree access tool, with both a standalone CLI and a JSON-RPC co-process mode which happens to fit the MCP schema for AI agents.
AI agents (Claude Code, Cursor, etc.) resort to shell pipelines
(sed -n, find | grep, head/tail) that trigger security checks and
produce brittle, unstructured output. aifr replaces all of those with a
single binary that is always safe (never writes) and always scoped (enforces
allow/deny lists with a built-in sensitive-file blocklist).
The aifr tool can read files, read git state, read "getent" system files,
some basic system information, and more. Everything read-only (except the
MCP self reload task). No network access, but some network state querying.
It never runs external commands, there is no possibility for shell injection
attacks. All functionality is "native" to this tool.
A number of filters traditionally done with the Unix pipe handling are moved
left into aifr, to limit the output without needing a pipeline. This avoids
triggering security checks for a shell invocation, even when using aifr
purely as a CLI tool, let alone when you start it as a co-process server so
that it can quickly answer many questions. The queries often support options
to filter which data rows are returned, which columns, to sort, and more.
Outside of AI, scripts which do a lot of git operations often end up repeatedly shelling out to git. With this agent running as a co-process, they can query configuration and contents and some history with a read-only tool: safe, because it will not touch anything or break the repo; at worst, it will fail to parse something, not break your setup.
Combine with tools such as ast-grep and
ripgrep. aifr does not seek to
replace good tools, it seeks to replace permission-triggering pipeline
invocations.
Install
Binary releases are available; currently hosted at: https://github.com/PennockTech/aifr/releases
Or you can build from source.
# From source go install go.pennock.tech/aifr/cmd/aifr@latest # Or build from the repo task build
MCP Server for Claude Code
claude mcp add --scope user aifr -- aifr mcp
This registers aifr as an MCP server using stdio transport. Claude Code
will then have access to aifr_read, aifr_cat, aifr_stat, aifr_list,
aifr_search, aifr_find, aifr_refs, aifr_log, and aifr_diff tools.
Skill File
The MCP server's built-in instructions are intentionally brief. For richer agent guidance (tool routing, advanced patterns, error handling), install the skill file:
# Symlink into user-level skills (recommended — stays in sync with repo) mkdir -p ~/.claude/skills ln -s "$(pwd)/skills/aifr" ~/.claude/skills/aifr # Or copy if you prefer a snapshot cp -r skills/aifr ~/.claude/skills/aifr
You can also generate the embedded (shorter) skill file at any time:
aifr skill > /tmp/aifr-skill.mdHTTP Transport
For HTTP transport (multi-client setups):
aifr mcp --transport http --addr :8080
Quick Start
# Read a file aifr read src/main.go # Read first 50 lines aifr read --lines 1:50 src/main.go # Read a file from git history aifr read HEAD~3:src/main.go # Concatenate all Go files, skipping vendor aifr cat --name '*.go' --exclude-path '**/vendor/**' . # Head: first 10 lines of each Go file with dividers aifr cat --name '*.go' --lines 10 --divider plain --format text . # Search for a pattern aifr search 'func.*Handler' ./src/ # Find files by name aifr find --name '*.yaml' --max-depth 2 . # List directory aifr list --depth -1 --type f . # Git refs and log aifr refs --branches --tags aifr log --max-count 5 # Compare files across refs aifr diff HEAD~1:README.md README.md
All commands output JSON by default. Use --format text for human-readable
output.
Configuration
Create .aifr.toml in the working directory or ~/.config/aifr/config.toml:
allow = ["~/projects/**"] deny = ["~/projects/secrets/**"] [git.repos] myapp = "~/projects/myapp"
If no config is found, aifr operates in "current directory only" mode —
it allows the cwd and everything beneath it.
See configs/aifr.example.toml for the full config reference.
Access Control
Every path request is evaluated in order:
- Resolve symlinks to canonical path
- Sensitive list (built-in, 120+ patterns) → blocked, always
- Deny list (from config) → blocked
- Allow list (from config, or cwd fallback) → permitted
- Default → blocked
Sensitive files (SSH keys, cloud credentials, .env, shell history, etc.)
return a distinct ACCESS_DENIED_SENSITIVE error. The agent is expected to
tell the user to read the file themselves if needed, and must not retry.
Run aifr sensitive to see the full pattern list.
Commands
| Command | Description |
|---|---|
read |
Read file contents (chunked, with continuation tokens) |
cat |
Concatenate multiple files with dividers (find+cat in one) |
stat |
File/directory metadata |
list |
Directory listing with depth, pattern, type filters |
search |
Content search (RE2 regexp, context lines, include/exclude) |
find |
Find files by name, type, size, age |
diff |
Compare files or git refs |
refs |
List git branches, tags, remotes |
log |
Git commit log with files changed |
config |
Show effective configuration |
sensitive |
List built-in sensitive file patterns |
skill |
Emit SKILL.md for Claude Code |
mcp |
Start MCP server (stdio or HTTP) |
Git Path Syntax
Git objects are addressed as [repo:]<ref>:<path>:
| Input Spec | Semantic meaning |
|---|---|
HEAD:README.md |
auto-detected repo, HEAD |
main:src/lib.go |
branch "main" |
v2.0:config.toml |
tag "v2.0" |
HEAD~3:file.go |
3 commits back |
a1b2c3d:pkg/auth.go |
short commit hash |
myrepo:main:terraform/main.tf |
named repo from config |
All git reads go directly through the object store — no checkout, no side effects on the working tree.
Building
task build # build with version ldflags task test # run tests with race detector task check # fmt + lint + test task release:snapshot # goreleaser snapshot build
Build targets: Linux (amd64), macOS (arm64), FreeBSD (amd64).