The bareDocumentation Index
Fetch the complete documentation index at: https://docs.capy.sc/llms.txt
Use this file to discover all available pages before exploring further.
capy command is the main loop. Run it any time and Capy:
- Authenticates you (if needed) via a browser-based login.
- Unlocks your master key by co-decrypting it with the Capy service.
- Pulls the latest encrypted
keep.lockfrom the service. - Diffs remote values against your local
.env. - Prompts you to resolve any conflicts.
- Rewrites
.envin place withcapy:…snippets that encode the resolved values.
First run vs. subsequent runs
On the first run in a project, Capy treats.env as authoritative:
- Asks which organization and project to use (or creates them).
- Generates a project encryption key via the zero-trust co-decrypt flow.
- Writes
keep.lockto the project root and commits it to git. - Creates a
developmentbranch. - Encrypts every value in
.envand uploads the ciphertext. - Adds
.envand.capy/to.gitignore. - Installs git hooks (
post-checkoutandpost-merge) that runcapy statusafter branch switches and merges. - Writes a commented-out backup of your original
.envto.env.pre-capy.old(gitignored) and rewrites.envwithcapy:…snippets.
.env. Conflicts open an interactive prompt where you pick a value per variable.
Conflicts and resolution
Everycapy run is a three-way compare between:
- Pinned - hashes stored in
keep.lockfrom the last sync. - Local - what’s in your
.envright now (decrypted in memory). - Remote - what’s on the service for this branch.
(pinned, local, remote) and either applies it automatically or prompts you. Here’s every case, using A for one value, B for another, and — for “absent”:
One side changed - auto-applied
| Pinned | Local | Remote | Action |
|---|---|---|---|
| A | A | A | unchanged (not shown) |
| — | A | — | push A to remote (new locally) |
| — | — | A | pull A to local (new on remote) |
| A | B | A | push B to remote (changed locally) |
| A | A | B | pull B to local (changed on remote) |
| A | — | A | push deletion to remote (deleted locally) |
| A | A | — | prompt; typically pull the delete |
Both sides changed - conflict
| Pinned | Local | Remote | Action |
|---|---|---|---|
| A | B | C | CONFLICT — pick local or remote |
| — | B | C | CONFLICT — same name, different origins |
| A | B | B | both agree on B — apply, no prompt |
| A | B | — | CONFLICT — you edited, remote deleted |
| A | — | B | CONFLICT — you deleted, remote edited |
| A | — | — | delete propagated — no prompt |
pinned, local, remote, and delete; ↑ ↓ moves between variables; Enter confirms the row and jumps to the next unresolved one. Once every row is confirmed, Capy applies the merged set and rewrites .env in place. q cancels without writing anything.
”New on both sides” vs. “edit vs. edit”
A subtle distinction: if both sides independently added a variable with the same name but different values (pinned is—), Capy marks the conflict as isNew and the prompt frames it as two new candidates. If both sides edited a previously-synced variable (pinned is A), it’s framed as an edit conflict.
The two look the same at the value level but have different provenance. Capy determines the difference by comparing resource IDs (the capy:{resourceId}:… prefix): different IDs mean the variables were created independently; the same ID means they share a common ancestor.
Remote unreachable
If the service is down or you lack access to the branch, Capy falls back to a two-way compare of pinned vs. local. It won’t destructively overwrite anything it can’t see, and it reports every affected variable with a? marker (see capy status).
Status and push
status is read-only and does not modify anything.
What ends up in git
keep.lock- a versioning manifest with no keys and no plaintext. Committed..env- ciphertext snippets at rest, but gitignored. Capy syncs the content over the wire instead of through git..env.pre-capy.old- commented-out backup of your original.envfrom before first-run. Gitignored..capy/- local state (session tokens, cache). Gitignored.
Branches
Capy has its own concept of secret branches - independent sets of values for dev, staging, prod, or ephemeral environments. Secret branches are tracked separately from git branches, butpost-checkout hooks can auto-switch them when your git branch changes. See Branches.
What’s next
capy (CLI reference)
Every flag on the sync command.
Branches
Isolate secrets per environment.