folder-crypt
Encrypt or decrypt a file or folder with a password via a Python CLI (AES-256-GCM). Password and paths can be prompted, passed as args, or read from SkillCred .env (FOLDER is a comma-separated list).
SKILL.mdskills/security/folder-crypt/SKILL.md
GitHubTO COPY
folder-crypt
Per-workspace registration slice. Credentials live in {SKILL_PATH}/.env.
Working directory
Placeholders changed by /meta-skills at copy time (NAME => {PLACEHOLDER}):
IS_GLOBAL => {IS_GLOBAL} TYPE_OF_AI_TOOLS => {TYPE_OF_AI_TOOLS} SKILL_PATH => {SKILL_PATH}
Bash / zsh:
export CURRENT_SKILL_DIRECTORY="{SKILL_PATH}"
export PROJECT_PATH="<main project folder>"
~/.meta-skills/.venv/bin/python ~/.meta-skills/skills/security/folder-crypt/scripts/cli.py env
PowerShell (Windows):
$env:CURRENT_SKILL_DIRECTORY = "{SKILL_PATH}"
$env:PROJECT_PATH = "<main project folder>"
& "$HOME/.meta-skills/.venv/Scripts/python.exe" "$HOME/.meta-skills/skills/security/folder-crypt/scripts/cli.py" env
PROJECT_PATH is the main project folder. Relative FOLDER paths start there.
After a successful encrypt, ask before editing git — do not assume --remove, never print PASSWORD:
- “Add <path> (and optionally <path>.fcr) to .gitignore?”
- “Add a before-commit hook that runs encrypt?”
END TO COPY
folder-crypt
Password-protect a file or a folder: pack it as tar.gz, encrypt with AES-256-GCM (key from PBKDF2-HMAC-SHA256). Decrypt restores that file or folder. A file archive holds one file; a folder archive holds the directory tree. Existing folder archives still decrypt.
skill_env.py loads .env via SkillCred — do not source it in the shell.
CURRENT_SKILL_DIRECTORY is the only required SkillCred export.
PROJECT_PATH is the main project folder: relative FOLDER paths start there.
Prefer ~/.meta-skills/.venv/bin/python from
~/.meta-skills/skills/security/folder-crypt/.
When to use
Trigger phrases: "encrypt this file", "encrypt this folder", "password-protect a directory",
"decrypt the .fcr archive", /folder-crypt_*.
After a successful encrypt, always ask whether to add the plaintext path(s)
to .gitignore, and whether to add a before-commit hook that runs encrypt.
Do not assume --remove.
Confirm with the user before encrypt --remove (deletes the original file or folder).
Prerequisites
cd ~/.meta-skills/skills/security/folder-crypt
~/.meta-skills/install.sh pip init .
Credentials — SkillCred .env (optional)
Both keys are optional. When omitted, the CLI prompts (TTY) or requires flags.
| Variable | Notes |
|---|---|
FOLDER |
Comma-separated files or folders (encrypt), or those paths / .fcr archives (decrypt). Whitespace around commas is ignored. Relative paths start at PROJECT_PATH. |
PASSWORD |
Default password — never print it |
PROJECT_PATH is a shell export (the main project folder), not a .env key.
Set it before the CLI. Absolute FOLDER entries stay absolute.
cp ~/.meta-skills/skills/security/folder-crypt/.env.example "{SKILL_PATH}/.env"
python scripts/cli.py env # FOLDER is the raw string, folders is the parsed list; PASSWORD is only "set"/"missing"
Example .env:
FOLDER=to_encrypt,secrets,notes
PASSWORD=change-me
Interactive (no .env):
python scripts/cli.py encrypt
# File or folder: /path/to/secret.txt
# Password: ********
# Confirm password: ********
Non-interactive (.env or args):
python scripts/cli.py encrypt /path/to/secret.txt # this file only (one JSON object)
python scripts/cli.py encrypt /path/to/secret # this folder only
python scripts/cli.py decrypt /path/to/secret.fcr
python scripts/cli.py encrypt # every path in FOLDER, same PASSWORD
python scripts/cli.py decrypt # every FOLDER entry; a file or folder uses the sibling .fcr
python scripts/cli.py encrypt -o /path/to/out.fcr # error when FOLDER lists more than one path
Prefer .env or the prompt over --password (avoids shell history).
-o / --output is valid for a single target only (one positional arg, or a FOLDER list of one). Several FOLDER paths plus -o exits with a JSON error and encrypts nothing.
With no positional arg, stdout is one object {ok, action, items:[…]}. Each item is one path. A failure on one path does not drop the others; ok is false and the exit code is 1 when any item failed. A positional arg keeps the single-object JSON.
Slash commands
| Slash | CLI | Description |
|---|---|---|
/folder-crypt_env |
python scripts/cli.py env |
Resolve .env (does not print the password) |
/folder-crypt_encrypt |
python scripts/cli.py encrypt [PATH] [-o ARCHIVE.fcr] [--remove] |
Encrypt one file or folder, or every FOLDER entry → .fcr |
/folder-crypt_decrypt |
python scripts/cli.py decrypt [ARCHIVE.fcr|PATH] [-o DEST] |
Decrypt one archive, or every FOLDER entry |
Default archive path: <path>.fcr next to the file or folder. Default decrypt dest: archive name without .fcr (a file comes back as a file). A FOLDER entry that is a file or directory uses that sibling .fcr. A path that already ends in .fcr is the archive.
Stdout is JSON.
How to run
export CURRENT_SKILL_DIRECTORY="{SKILL_PATH}"export PROJECT_PATH="<main project folder>"— relativeFOLDERpaths start herecd ~/.meta-skills/skills/security/folder-crypt- First run:
~/.meta-skills/install.sh pip init . ~/.meta-skills/.venv/bin/python scripts/cli.py …- After encrypt succeeds, ask to gitignore the plaintext file(s) or folder(s) (and optionally the
.fcr), then ask whether to add a before-commit hook that runsencrypt. Do not assume--remove.
After encrypt — .gitignore
Required after every successful encrypt. Do this yourself as the agent. Do not edit git until the user says yes. Do not assume --remove.
- Resolve the plaintext path(s) just encrypted (JSON
folder, oritems[].folder— this field is the file or folder) and the matching.fcr(archive) when that archive sits in a git repo. - Ask, and wait for an answer: “Add <path> (and optionally <path>.fcr) to .gitignore?”
- If they say yes, for each path inside a git work tree:
- Repo root is
git rev-parse --show-toplevel. - Append entries relative to the repo root (
notes.txtfor a file,secrets/for a directory, plusnotes.txt.fcrorsecrets.fcrfor the archive). - Skip a line that is already present.
- If
.gitignoredoes not exist, create it at the repo root.
- Repo root is
- If a path is outside any git repo, say so and skip it. Do not create a
.gitignorethere. - Do not gitignore
.cursor/skills/folder-crypt/.envas this step. That file should already be ignored. Never commit.envor printPASSWORD.
After encrypt — before-commit hook
Ask this separately from the .gitignore question, and wait: “Add a before-commit hook that runs encrypt?”
Do not add the hook until they say yes. The hook is only the encrypt command. No --remove, no --password, no extra checks. PASSWORD stays in .env. The command encrypts every FOLDER entry, so those paths need to be listed there.
- If the repo root cannot be resolved, say so and skip.
- Hook file:
$(git rev-parse --git-path hooks)/pre-commit(this followscore.hooksPathwhen set, otherwise.git/hooks/pre-commit). - If that file already exists, append the command. Do not replace the file. If it does not exist, create it with a
#!/usr/bin/env bashshebang andchmod +x. - Skip when the marker
# folder-crypt encryptis already present.
# folder-crypt encrypt
export CURRENT_SKILL_DIRECTORY="{SKILL_PATH}"
export PROJECT_PATH="<main project folder>"
~/.meta-skills/.venv/bin/python ~/.meta-skills/skills/security/folder-crypt/scripts/cli.py encrypt
Use the real skill directory and the repo root in place of the placeholders. A non-zero exit from encrypt stops the commit. Encrypt replaces an existing .fcr.
- A hook under
.git/hooks/is local to this clone. Ifcore.hooksPathpoints at a tracked directory, say that the hook file is inside the work tree. Do not commit it unless the user asks. - Never commit
.envor printPASSWORD.
Safety
- After encrypt, always prompt for
.gitignore, then ask about a before-commit hook that runsencrypt(no--remove). Do not assume--remove. - Confirm before
--remove. - Encrypt replaces an existing
.fcr. Decrypt replaces an existing file or folder. A wrong password leaves the destination unchanged. - Never commit
.envor printPASSWORD. - Never put the output
.fcrinside the folder being encrypted. - Wrong password → JSON error, no files written.