Readit News logoReadit News
Posted by u/cyrusradfar 16 days ago
Show HN: Unfucked - version all changes (by any tool) - local-first/source availunfudged.io/...
I built unf after I pasted a prompt into the wrong agent terminal and it overwrote hours of hand-edits across a handful of files. Git couldn't help because I hadn't finished/committed my in progress work. I wanted something that recorded every save automatically so I could rewind to any point in time. I wanted to make it difficult for an agent to permanently screw anything up, even with an errant rm -rf

unf is a background daemon that watches directories you choose (via CLI) and snapshots every text file on save. It stores file contents in an object store, tracks metadata in SQLite, and gives you a CLI to query and restore any version. The install includes a UI, as well to explore the history through time.

The tool skips binaries and respects `.gitignore` if one exists. The interface borrows from git so it should feel familiar: unf log, unf diff, unf restore.

I say "UN-EF" vs U.N.F, but that's for y'all to decide: I started by calling the project Unfucked and got unfucked.ai, which if you know me and the messes I get myself into, is a fitting purchase.

The CLI command is `unf` and the Tauri desktop app is titled "Unfudged" (kids safe name).

How it works: https://unfucked.ai/tech (summary below)

The daemon uses FSEvents on macOS and inotify on Linux. When a file changes, `unf` hashes the content with BLAKE3 and checks whether that hash already exists in the object store — if it does, it just records a new metadata entry pointing to the existing blob. If not, it writes the blob and records the entry. Each snapshot is a row in SQLite. Restores read the blob back from the object store and overwrite the file, after taking a safety snapshot of the current state first (so restoring is itself reversible).

There are two processes. The core daemon does the real work of managing FSEvents/inotify subscriptions across multiple watched directories and writing snapshots. A sentinel watchdog supervises it, kept alive and aligned by launchd on macOS and systemd on Linux. If the daemon crashes, the sentinel respawns it and reconciles any drift between what you asked to watch and what's actually being watched. It was hard to build the second daemon because it felt like conceding that the core wasn't solid enough, but I didn't want to ship a tool that demanded perfection to deliver on the product promise, so the sentinel is the safety net.

Fingers crossed, I haven’t seen it crash in over a week of personal usage on my Mac. But, I don't want to trigger "works for me" trauma.

The part I like most: On the UI, I enjoy viewing files through time. You can select a time section and filter your projects on a histogram of activity. That has been invaluable in seeing what the agent was doing.

On the CLI, the commands are composable. Everything outputs to stdout so you can pipe it into whatever you want. I use these regularly and AI agents are better with the tool than I am:

  # What did my config look like before we broke it?
  unf cat nginx.conf --at 1h | nginx -t -c /dev/stdin

  # Grep through a deleted file
  unf cat old-routes.rs --at 2d | grep "pub fn"

  # Count how many lines changed in the last 10 minutes
  unf diff --at 10m | grep '^[+-]' | wc -l

  # Feed the last hour of changes to an AI for review
  unf diff --at 1h | pbcopy

  # Compare two points in time with your own diff tool
  diff <(unf cat app.tsx --at 1h) <(unf cat app.tsx --at 5m)

  # Restore just the .rs files that changed in the last 5 minutes
  unf diff --at 5m --json | jq -r '.changes[].file' | grep '\.rs$' | xargs -I{} unf restore {} --at 5m

  # Watch for changes in real time
  watch -n5 'unf diff --at 30s'
What was new for me: I came to Rust in Nov. 2025 honestly because of HN enthusiasm and some FOMO. No regrets. I enjoy the language enough that I'm now working on custom clippy lints to enforce functional programming practices. This project was also my first Apple-notarized DMG, my first Homebrew tap, and my second Tauri app (first one I've shared).

Install & Usage:

  > brew install cyrusradfar/unf/unfudged
Then unf watch in a directory. unf help covers the details (or ask your agent to coach).

EDIT: Folks are asking for the source, if you're interested watch https://github.com/cyrusradfar/homebrew-unf -- I'll migrate there if you want it.

notfried · 15 days ago
I love the website; the design, the video, the NSFW toggle, the simplicity.

I love the idea; definitely something I ran into a few times before and wish I had.

Unfortunately, I am not installing a closed-source daemon with access to the filesystem from an unknown (to me) developer. I will bookmark this and revisit in a few weeks and hope you had published the source. :)

cyrusradfar · 15 days ago
Totally understandable.

I didn't open up the source for this as I have a mono-repo with several experiments (and websites).

Happy to open the source up and link it from the existing website.

I've started to have an Agent migrate it out, and will review it before calling it done. Watch https://github.com/cyrusradfar/homebrew-unf

Edit: You can download the current version now: https://github.com/cyrusradfar/homebrew-unf/archive/refs/tag...

OccamsMirror · 14 days ago
I have to agree with the previous user. I'm not brew installing a closed source daemon.

I'd have to imagine that moving this out to its own repo with Claude Code would be trivial so I don't understand the resistance.

This is a great idea. I look forward to seeing a proper repo for it.

rovr138 · 14 days ago
> Edit: You can download the current version now: https://github.com/cyrusradfar/homebrew-unf/archive/refs/tag...

This does not contain the source.

popalchemist · 15 days ago
Agreed on all counts. It looks great! Just can't trust it unless it's transparent.
wazzaps · 15 days ago
FYI all Jetbrains IDEs include this, as long as they are open on the codebase. It's called "Local history".
its-kostya · 15 days ago
I love to use the terminal, and I still do. But as much as I love to unfu*k my local nvim setup, I much rather pay a company to do it for me. Set up vim bindings inside jetbrains and everything comes with batteries included, along with a kick-ass debugger. While my colleagues are fighting opencode, I pointed my IDE at the correct MCP gateway and everything "just works" with more context.

Thought I'd share the data point to support jetbrains

nurettin · 14 days ago
On behalf of everyone who dislikes jetbrains business model, I would like to say: duly noted.
gschrader · 15 days ago
I think it only keeps history for user edited files, agent edited files don't seem to end up in it for me (Claude code) but maybe it works with other agents with the proper plugins I'm not sure.
cyrusradfar · 15 days ago
+1 OP here, this is the problem I'm solving for. Agents use tools and may be in multiple places editing; therefore, you need to watch the file system.
heeen2 · 15 days ago
vscode and its forks as well (for files it saves)
gavinray · 14 days ago
In today's version of "LLM's allow a person to write thousands of lines of code to replace built-in Unix tools":

  inotifywait -mr -e modify,create,delete /your/dir |
  while read _; do
    cd /your/dir && git add -A && git commit -m "auto-$(date +%s)" --allow-empty
  done
There are +8 billion people on the planet, computing has beed around a while now and some REALLY smart people have published tools for computers. Ask yourself, "am I the first person to try to solve this problem?"

Odds are, one or more people have had this problem in the past and there's probably a nifty solution that does what you want.

cyrusradfar · 14 days ago
OP Here, hard to attempt to read and respond to this in good faith.

I think it would be dishonest if I didn't share that your approach to discourse here isn't a productive way of asking what insights I'm bringing.

If that's your concern, I agree I can't claim that nothing exists to solve pieces of the puzzle in different ways. I did my research and was happy that I could get a domain that explained the struggle -- namely unfucked.ai/unfudged.io -- moreover I do feel there are many pieces and nuances to the experience which give pause to folks who create versioning tools.

I'm open to engaging if you have a question or comment that doesn't diminish my motives, assumes I must operate in your world view "problems can only be solved once", and discourages people to try new things and learn.

Look, I'm grateful that you stopped by and hope you'll recognize I'm doing my best to manage my own sadness that my children have to exist in a world where folks think this is how we should address strangers.

gavinray · 14 days ago

  > assumes I must operate in your world view "problems can only be solved once"
I never claimed anyone else has to agree with this. That's why people are allowed different opinions.

Nobody ought to give a damn what I think, the only opinion that matters about you is your own.

But just like I won't ask you adopt my view, I also won't go around patting people on the back for TODO apps.

My opinion: people ought to spend more time contributing to solving genuine problems. The world needs more of that, and less "I built a TODO app" or "Here's my bespoke curl wrapper".

amadeuspagel · 14 days ago
Only works in a git directory, and one might want to use git only for manual version control and another tool for automatic.
gavinray · 14 days ago
Then replace git with "rsync" or "borg. But I don't see how running "git init" in a directory you have "days of work" accumulated in is a sticking point.

Git is a convenient implementation detail.

The core loop of "watch a directory for changes, create a delta-only/patch-based snapshot" has been a solved few-liner in bash for a long time...

rovr138 · 14 days ago
Create a branch, squash the branch manually when you want and merge things.

or `git reset --soft main` and then deal with the commits

or have 2 .git directories. Just add to the git commit `--git-dir=.git-backups` or whatever you want to name it.

gavinray · 14 days ago
This is happening so frequently I just wrote a blog about it to vent my frustration:

https://gavinray97.github.io/blog/llm-build-cheaper-than-sea...

My comment is not meant as a shallow dismissal of the authors work but rather what seems to be a growing, systemic issue

mpalmer · 15 days ago
This is so cool to have made yourself. How would you compare this to the functionality offered by jujutsu? I love the histogram, it was the first sort of thing I wanted out of jujutsu that its UI doesn't make very easy. But with jj the filesystem tracking is built in, which is a huge advantage.
cyrusradfar · 15 days ago
I'm not a user, but I looked at the site and it looks like jj snapshots when you run a jj command. UNF snapshots continuously.

If an AI agent rewrites 30 files and you haven't touched jj yet, jj has the before-state but none of the intermediate states. UNF* captured every save as it happened, at filesystem level.

jj is a VCS. UNF is a safety net that sits below your VCS.

  - UNF* works alongside git, jj, or no VCS at all
  
  - No workflow change. You don't adopt a new tool, it just runs in the background
  
  - Works on files outside any repo (configs, scratch dirs, notes) as it doesn't require git.
They're complementary, not competing.

W.r.t. to the histogram, this is my fav feature of the app as well. Session segmentation (still definitely not perfect) creates selectable regions to make it easier, too. The algo is in the CLI as well for the Agent recap (rebuilding context) features.

lexluthor38 · 15 days ago
To be fair, jujutsu has a watchman feature which uses inotify to create snapshots on file change as well. Your tool probably has a more tailored UX to handling these inter-commit changes though so there could still provide complementary value there.
benoitg · 14 days ago
One of the uses cases on their website is the agent deleted my .env file.

jj wouldn’t help with that as it would be gitignored.

JimDabell · 14 days ago
This tool doesn’t help with that either:

> The tool skips binaries and respects `.gitignore` if one exists.

ghrl · 14 days ago
This tool seems very promising and does solve a real issue I've certainly had quite a few times already where this would have been very useful.

I really like the website design and content-wise, as well as the detailed writeup here on HN. Certainly impressive work for an individual.

I've never used Time Machine but I do have kopia set up for frequent backups of important places, like the entire Documents folder. It does use a CAS as well and last time/size/hashes for determining what to save.

Coming from that I'm curious about a few aspects. Would this work well for larger folders/files? You mentioned deduplication, but does that happen on the file level or on chunks of the file, so that small changes don't store an entire new version of the file? Additionally, are the stored files compressed somehow, probably a fast compression algorithm? I think that could make it work for more than just source code.

Great project though, so far. I could see it becoming a lot more popular given an open source code base. Maybe a pricing model like the one Mac Mouse Fix uses would work, being open source and charging a fee so small it still reaches a large audience. That would likely be fair considering the developer time/agent cost of just a single unf'd problem as ROI.

oftenwrong · 14 days ago
I have used savevers.vim for many years as a way to recover old versions of files.

https://www.vim.org/scripts/script.php?script_id=89

It is comparatively unsophisticated, but I need it so infrequently that it has been good enough.

I do like the idea of maintaining a complete snapshot of all history.

This is a good application for virtual filesystems. The virtual fs would capture every write in order to maintain a complete edit history. As I understand it, Google's CitC system and Meta's EdenFS work this way.

https://cacm.acm.org/research/why-google-stores-billions-of-...

https://github.com/facebook/sapling/blob/main/eden/fs/docs/O...

mplanck · 15 days ago
Yep, I’ve needed something like this a few times. Even when trying to be careful to commit every step to a feature branch, I’ve still found myself asking for code fixes or updates in a single iteration and kicking myself when I didn’t just commit the damn thing. This will be a nice safety net.
cyrusradfar · 15 days ago
Thank you! That's great to hear.

I spent a bit of time being baffled nothing existed that does this. Then I realized that, until Agents, the velocity of changes wasn't as quick and errors were rare(er)

datawars · 15 days ago
Thank you for pointing out a problem that I had (which I do!), solving with Time Machine and trying to make myself commit more requently - and for providing a solution! Looks very cool, too. If I close the terminal I started --watch in, will the watch continue?

Writing this, I wanted to ask if the desktop app includes the CLI, but there it says it on your website :-) Thanks for thinking ahead so far, but then picking us up here and now so we can easily follow along into an unf* future!

Looking forward to try it.

rusty-jules · 15 days ago
This is a real problem! Sounds like you and dura landed on similar solutions: https://github.com/tkellogg/dura

Keep it up!