agentutils
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Fail
- rm -rf — Recursive force deletion command in demo/record.sh
- rm -rf — Recursive force deletion command in demo/setup.sh
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Small UNIX tools for letting a coding agent, or anything else you would rather not trust with your files, work on a directory.
agentutils
Small UNIX tools for letting a coding agent, or anything else you would
rather not trust with your files, work on a directory:
fsforkforks a directory: it makes a copy-on-write clone of it, and
prints where it is.confineruns a command in a fork of the working directory, or in a
directory, that may write only there, and cannot read secrets.fsdiffshows what changed in a fork since it was made, as a patch.
Each does one thing. confine forks as fsfork does, and fsdiff knows
where a fork's base is; otherwise none knows about the others. They keep no
state:
a fork is a directory, its path is its name, and ls, rm and git do
the rest.

Usage
Run Claude Code in a fork of the directory, where it may write nothing
else:
cd ~/src/turso
confine -w ~/.claude claude
confine forks the directory to ~/src/turso.1, says so, and runs Claude
Code in the fork. -w ~/.claude lets it save its sessions and settings.
With --rm, the fork is removed when Claude Code exits; with -d dir,
there is no fork, and Claude Code runs in dir itself.
When it is done, see what it changed, apply the changes, and remove the
fork:
fsdiff ../turso.1
fsdiff ../turso.1 | git apply
rm -rf ../turso.1 ../.turso.1.base
Meanwhile, you can keep working in ~/src/turso, and run more forks side by
side: turso.2, turso.3, and so on. ls -d ../turso.* lists them.
Each command has a man page: fsfork.1,confine.1, and fsdiff.1
(man ./cmd/fsfork/fsfork.1).
Install
make install
This builds the commands and installs them in ~/.local/bin, and their man
pages in ~/.local/share/man. To install them elsewhere, set PREFIX; in/usr/local, that may need make && sudo make install PREFIX=/usr/local.make uninstall, with the same PREFIX, removes them.
They run on macOS and Linux.
Requirements
- macOS: APFS, with forks on the same volume as the directory.
- Linux: Linux 5.19 or later, with Landlock enabled, for
confine. A file
system that can share blocks between files, such as Btrfs or XFS, forfsfork; on others, a fork is a full copy. git, forfsdiff.
fsfork
fsfork clones the directory twice, next to it: to the fork, turso.1,
and to its base, .turso.1.base, which keeps what the directory was when it
was forked. The fork is cloned from the base, so that the two are the same
whatever changes in the directory meanwhile. With no arguments, it forks the
working directory; given one, that directory; given two, to the second.
A fork is everything in the directory, as it is: the repository,
uncommitted changes, and build output, so builds start warm. On macOS, it is
made with clonefile, and on Linux with cp --reflink, so it takes no
space until either side is written to.
fsfork knows nothing about git: it forks exactly the directory it is
given.
fsdiff
fsdiff compares a fork with its base, so it shows what changed in the
fork, and not what changed in the directory since. Given two directories, it
compares them instead. It prints a patch that git apply applies, and
exits as diff does: 0 if nothing changed, 1 if something did, and 2 if
something went wrong.
It leaves out .git directories, and what the base's .gitignore files
ignore, such as build output. New files in the fork are left out if the
fork's .gitignore files ignore them, but a file that was in the base never
is. Only what is in the patch reaches the directory it is applied to.
The fork is read but never trusted, as the command in it could have changed
anything there, its git configuration included, to make git run any
command. So fsdiff never runs git in the fork's repository: it records
both directories in a repository of its own, made in the temporary
directory and removed after, by git with no configuration but its defaults.
Symbolic links are shown as links and never followed, so a link to a file
outside the fork cannot bring that file into the patch.
confine
confine runs a command in a fork of the working directory, or in the
directory given with -d, which the command may write to, along with
temporary directories, devices, build and package manager caches
(~/.cargo, ~/.rustup, ~/.cache, ~/.npm, ~/Library/Caches), and
paths given with -w. It cannot read ~/.ssh, ~/.aws, ~/.gnupg, or~/.config/gh. Everything else is allowed. confine then becomes the command, which exits with its
own status; with --rm, it waits for the command instead, removes the
fork, and exits as the command did.
It sets CLAUDE_CODE_SANDBOXED=1, so that Claude Code trusts the directory
without asking, which would write to ~/.claude.json.
How the command is confined depends on the platform.
macOS
The command runs under Seatbelt, the macOS sandbox, through sandbox-exec.confine writes a profile that allows everything, then denies writing
everywhere but the writable paths, and denies listing, reading, and writing
the hidden paths. Since later rules win, the directory, which may lie among
the hidden paths, is allowed last. The profile gives the paths as
parameters rather than in the text, and Seatbelt matches them after
resolving symbolic links, so they cannot be escaped by quoting or linking.
sandbox-exec cannot run inside another sandbox, so a confined command
cannot confine another.
Linux
The command runs under Landlock, which a process uses to confine itself and
the processes it starts, without privileges. confine makes a ruleset in
which reading and running files, and changing anything, are denied unless
granted, and applies it just before becoming the command. Landlock needs
Linux 5.19 or later; without it, confine fails rather than run the command
unconfined.
Landlock can only grant rights, to a file and everything under it, and
cannot take them away from something inside. So rather than denying the
hidden paths, confine grants the rights to what is around them: it lists
each directory above a hidden path, and grants reading to every entry in it
but that path, and so on down. Writing is granted the same way, to the
writable paths, and then reading and writing to the directory itself.
Because of this, on Linux:
- The command can list the files in a hidden directory, such as the names
of the keys in~/.ssh, but cannot read them. - Files made in a directory above a hidden path after the command starts,
such as a new file in the home directory, cannot be read. - The command cannot run set-user-ID programs such as
sudo, as Landlock
confines a process without privileges only if it can gain none.
Unlike sandbox-exec, Landlock works inside another Landlock sandbox, so a
confined command can confine another.
What is not confined
The network: a command can send anything it can read to anywhere, and can
push to remotes whose credentials it can reach, such as through the macOS
keychain or an SSH agent.
Commits made in a fork are not signed if signing needs ~/.gnupg or~/.ssh, which the command cannot read.
License
MIT
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found