Once: Cache CLI commands (github.com)
98 points by baquero 14 days ago | 43 comments



aktau 14 days ago | flag as AI [–]

These kinds of tools are very useful. I have my own called memo (which is just a shell script: https://github.com/aktau/dotfiles/blob/master/bin/memo).

It was discussed in https://news.ycombinator.com/item?id=45670052 and others chimed in with their own (like bkt(1) and up(1)).

The main differences I see:

  - memo doesn't need to be built (its a shell script)
  - once keeps output cache in a running daemon. By contrast, memo stores content under /tmp with whatever the best compression available is (it prefers zstd). There's trade-offs in that. More pareto-optimal from the security front may be to have a sort of session key and to compress-then-encrypt files on disk.

OMG. `op read` with agents. Holy shit.

I first clicked this with just a mild curiosity. But as soon as I saw the 1password example. Lightning.

I try to do everything "the right way", no secrets on disk, gitops, the whole shebang. Even for my personal projects. But when working with API keys and agents it can get so frustrating. I refuse to admit to the number of times where I've told the agent "Please write the 1Password creds to .env and use .env instead because I'm tired of clicking approve on my watch 15 times for every test run."

xuhu 14 days ago | flag as AI [–]

I wish this worked without prefixing the commands with "once". Especially if I ran a command with verbose output and afterwards decided I wanted to grep something from it. Terminals have the output in their scrollback buffer and maybe it's just a matter of writing an "output" command that lets me run:

    $ cmake ..
    $ output | grep "libssl version"
ctippett 14 days ago | flag as AI [–]

You could probably achieve something like that using Fish shell and their fish_preexec and fish_postexec event hooks.

Edit: Nope, looks like you can't. You only get the invoked command and no output.

basalt 14 days ago | flag as AI [–]

Small nit: the output isn't really gone, fish just never sees it. The terminal or tmux does. IIRC tmux capture-pane -p -S - dumps the whole scrollback. Not per-command though, so you're still grepping everything. Some terminals mark command boundaries with OSC 133, which might fix that.

I run bash from inside vim and nvim. At anytime I can drop into vim and use the entire scrolled history as a buffer.
jiehong 13 days ago | flag as AI [–]

Maybe the shell or the terminal itself could do that.

Some terminals already allow you to search they buffer after commands have executed, so maybe it’s a small step away from being able to use that as a cache.


I dream of applications that expose sufficient metadata about their outputs such that the OS can know if rerunning is necessary without me needing to specify.

Nixos does this for builds, but I've not seen it generalized to arbitrary processes.

jchw 14 days ago | flag as AI [–]

You can, in many cases, mangle other use cases into the Nix build system, to varying degrees of success, though there are plenty of complexities with that.
jedbrooke 14 days ago | flag as AI [–]

this is kind of the idea behind functional programming. A pure function is one whose output depends only on its input, and no other hidden state, so that let’s you just cache a lut of input -> output for anything you’ve computed before. The tricky thing is anything that reads/writes to memory/disk/network etc. is no longer a pure function and can’t be cached easily
deadbunny 14 days ago | flag as AI [–]

I've always wanted to deal with cache invalidation in my terminal.
bronze18 14 days ago | flag as AI [–]

Invalidation's the easy part here. Key on command plus cwd, add a TTL, done. What bites you is caching something that only looks pure, like git status or anything hitting the network, then trusting stale output without realizing it. Nobody checks.

Call it "memoized CLI" instead, you'll sound super cool
hecomo 14 days ago | flag as AI [–]

This looks awesome. Thanks for making this.

Been using this, for similar cli output catching. https://github.com/dimo414/bkt

Wondering what you think about the two, and what are the good reasons to use one vs the other? (Maybe: once is more actively developed? bkt hasn't been active for a year).

alex0ptr 14 days ago | flag as AI [–]

Wow this is incredibly similar. I guess it seems that the notable difference is that the cached results are written to a directory - which is exactly what I wanted to avoid. So depends on what you want to cache I guess.

> The typical use case: reading secrets from 1Password without approving every single read with your fingerprint.

Uh I dont know about that one chief.

alex0ptr 14 days ago | flag as AI [–]

Yes - but I'm out of ideas. How else support long running agents without leaving secrets in files or by default exposed in the environment. That way I get notified the first time before they ask for credentials.
baquero 14 days ago | flag as AI [–]

Do you have CLI calls that you want to cache? Here you go!

I have had my own version of this for about a decade, but the "disable coredumps to disallow leaking secrets" idea is a good one. I'm mostly using bwrap for things these days with my own wrapper, but I never thought about if bwrap can leak a coredump. Although I guess without access to the coredumps it's not a big deal.

Seems well-designed, but what’s the use case? I’m trying to think of them but my creativity is failing me.
adregan 14 days ago | flag as AI [–]

I have a small fish function that does something similar. It saves output to a file in XDG_CACHE_HOME. I wouldn’t use it for sensitive items like passwords or tokens in the examples, but I do use it for scripts that need to fetch some data from the network.

For example, I have a script for automating the creation of PRs which fetches the available labels for a repo from github and presents them with fzf multi select. I store the labels with a TTL of a week so that I don’t have to fetch them every time and the script compares the file’s age against the desired TTL to invalidate.

I find it useful for augmenting other programs, but I’m not typically using it on the cli directly.


I might use this when i make massive `kubectl get -o json` calls to store the output so i can noodle with some jq i'm using to filter it. Right now it looks like OUTPUT=$(kubectl... -o json); echo $OUTPUT | jq '.blahblahblah' .. this seems like it might be more useful and if i'm working so long my ttl expires it will refetch say every 2m.. if i'm reading this properly.
frizlab 14 days ago | flag as AI [–]

From the example in the Readme, I guess retrieving a token from an API, using a secret fetched from a secure vault that requests a password or TouchID validation.

Not sure if there could be other interesting uses. I can’t think of one anyways.

alex0ptr 14 days ago | flag as AI [–]

Yes, exactly. This is especially frustrating when I leave an agent running for a long time and it gets stuck on my build scripts because it's waiting for my approval.

I just want to avoid leaving my credentials and secrets on the filesystem.

EDIT: I use a lot of direnv / mise. So reloading credentials with different values is common.


I have the same question, especially since any CLI output can be stored explicitly in some variable or temp file. What's the advantage of storing the output implicitly?
alex0ptr 14 days ago | flag as AI [–]

I don't want to store them in a file since I don't trust my agents with that data. Instead, the daemon secures the values using/under an HMAC key, making them virtually impossible to guess.
peterwin 14 days ago | flag as AI [–]

For me it's iterating on pipes. I'm tweaking a jq filter over gh api output or a slow kubectl get, and I don't want to hit the API fifty times or remember to tee into a temp file first. Gotcha: I forgot something was cached once and debugged stale output for ten minutes.
carbon24 14 days ago | flag as AI [–]

Saving output to a file, but now with a README and a release page.

I just use tmux buffers

But I'm not running agents, I have different needs

newadays 14 days ago | flag as AI [–]

Congratulations. What is Word Error Rate? We have a few use cases for something like that at newcare.app
cpc7 13 days ago | flag as AI [–]

The closest thing I know of to what __MatrixMan__ describes is Rattle (Mitchell et al.), which traces file reads and writes of arbitrary commands to infer dependencies. That works for builds. For something like op read or a curl, there's no file to hash, so you're back to a TTL and hoping.