monkeys

remember

Put a secret into the vault, or a value into .monkeys.

monkeys remember [@profile] <KEY> [--clipboard]
monkeys remember --public [@profile] <KEY> [--clipboard]
monkeys remember [@profile] [--all]

Reads a secret and remembers it under the key. On a terminal it prompts, and what you paste is not echoed:

monkeys remember OPENROUTER_API_KEY
secret:
remembered OPENROUTER_API_KEY
give it to a command with:
  monkeys run OPENROUTER_API_KEY <command>

--clipboard takes the secret from the clipboard instead, through whichever tool the desktop has, pbpaste, wl-paste, xclip or xsel, so a key copied from a provider's console goes straight in:

monkeys remember GITHUB_TOKEN --clipboard
remembered GITHUB_TOKEN
give it to a command with:
  monkeys run GITHUB_TOKEN <command>

When standard input is not a terminal, the secret is read from there, which is how a script remembers one:

cat token.txt | monkeys remember GITHUB_TOKEN

Inside a project the key is remembered under the project's profile, so monkeys remember STRIPE_SECRET_KEY there writes foo.test/STRIPE_SECRET_KEY. A leading @profile picks another, @namespace.profile one of another project, and a bare @ no profile:

monkeys remember @production DATABASE_URL
secret:
remembered foo.production/DATABASE_URL
give it to a command with:
  monkeys run <command>

A key you already remembered is replaced, and nothing says so.

What it writes into .monkeys

A key the project does not list is added to it, under the profile the secret went to, so the command that needs it can find it:

monkeys remember STRIPE_SECRET_KEY
secret:
remembered foo.test/STRIPE_SECRET_KEY
listed STRIPE_SECRET_KEY in .monkeys for @test

In a git checkout with no .monkeys at all, the first remember makes one at the root of the checkout, named after that directory, with test as its first profile:

monkeys remember DATABASE_URL
made .monkeys for +foo @test
remembered foo.test/DATABASE_URL
listed DATABASE_URL in .monkeys for @test

The file is made only once there is a secret to put in it, so an answer you abandon at the prompt leaves nothing behind. Outside a checkout nothing is made and the key keeps no profile, and a bare @ says so from inside one.

A profile the file does not declare is refused rather than added, since a mistyped one would otherwise become a profile of its own.

Walking a profile

With no key, inside a project, remember walks the profile's keys in the order the file lists them and prompts for each one that has no secret yet. An empty answer skips that key. At the end it shows the profile the way doctor does, with what each key got, and exits non-zero while anything is still missing:

monkeys remember
DATABASE_URL:
STRIPE_SECRET_KEY:
@test  default
  ✓ DATABASE_URL  remembered
  ✗ STRIPE_SECRET_KEY  skipped

A leading @profile walks that profile instead, one at a time; @test,production is refused. --all prompts for every key, and a key that already has a secret shows its mask in the prompt so Enter keeps it:

monkeys remember --all
DATABASE_URL (al...e 18, Enter keeps):
STRIPE_SECRET_KEY (br...e 18, Enter keeps):
@test  default
  ✓ DATABASE_URL  kept
  ✓ STRIPE_SECRET_KEY  remembered

The walk reads from the terminal only. With standard input piped, or with --clipboard, it says so and remembers nothing; both of those take one key. Outside a project there is nothing to walk, and monkeys remember with no key says a key is required.

Remembering is a human's job. An agent that types a secret puts it in its own context before it reaches the vault, so the skill tells it to ask instead.

--public

--public writes a value that is not secret, PORT=3000 and the like, into .monkeys as a KEY=value line instead of into the vault. It prompts with value: and echoes what you type, since the value will be committed, and from a pipe it reads the value the same way:

echo 3000 | monkeys remember --public PORT
echo 80 | monkeys remember --public @production PORT
wrote PORT=3000 to .monkeys for @test
wrote PORT=80 to .monkeys for @production

The line goes into the block that is that profile's alone, or into a new block at the end. A value the profile already has is replaced in place. A value the file sets for several profiles together is refused, since replacing it would change them all; split the block by hand.

--public only works inside a project, because a value has nowhere to go without .monkeys. It refuses a key the file lists as a secret for the profile, and plain remember refuses a key the file holds as a value, each naming the other form:

monkeys remember PORT
monkeys: PORT is a value in .monkeys for @test; replace it with monkeys remember --public PORT, or forget it first

Turning one into the other is forget and then remember, so a secret becomes a committed line by accident.

On this page