Secret Tasks
Create and manage encrypted task files for secure multi-agent orchestration using the safe CLI.
Quick Reference
Action Trigger Phrases
Generate keypair "generate keys", "keygen", "create keypair"
Configure private key "use key", "set private key", "configure decryption"
Add recipient "add recipient", "add public key"
List keys "list keys", "show configuration", "what keys"
Create plan "create plan", "create encrypted tasks", "make secret plan"
Decrypt task "decrypt task", "show task", "reveal task"
Workflows
Generate Keypair
When: User wants to create new encryption keys.
Steps:
Create directory:
mkdir -p ~/.safe
Generate keypair (use provided name or default to "secret-tasks"):
safe keygen x25519 -o ~/.safe/[name]
Report results:
-
Private key: ~/.safe/[name].x25519.key (keep secret)
-
Public key: ~/.safe/[name].x25519.pub (share with team)
Remind user:
-
Never commit .key files
-
Add ~/.safe/*.key to global gitignore
-
Share .pub files with collaborators
Configure Private Key
When: User wants to set which key to use for decryption.
Steps:
Validate key exists:
test -f "[path]" && echo "OK" || echo "ERROR: Key not found"
Create settings directory:
mkdir -p .claude
Read existing settings from .claude/secret-tasks.local.md (if exists) to preserve public_keys
Write updated settings:
private_key: [path] public_keys:
- [preserved existing keys]
Secret Tasks Configuration
Add this file to .gitignore.
Confirm: Show configured key path, note it overrides SAFE_KEY_PATH env var
Add Recipient
When: User wants to add a public key that can decrypt tasks.
Steps:
Validate key exists:
test -f "[path]" && echo "OK" || echo "ERROR: Key not found"
Optionally verify it's a valid public key:
safe keyinfo "[path]" 2>/dev/null | grep -q "public"
Create settings directory if needed:
mkdir -p .claude
Read existing settings, check for duplicates
Append to public_keys list and write updated settings
Confirm: Show added key, total recipients count
List Keys
When: User wants to see current key configuration.
Steps:
Check for .claude/secret-tasks.local.md
If found, parse YAML frontmatter and display:
-
Private key (for decryption)
-
All public keys (recipients)
If not found, show environment variables:
-
SAFE_KEY_PATH (or "not set")
-
SAFE_PUB_KEY (or "not set")
If nothing configured, show setup instructions
Create Encrypted Plan
When: User wants to create an encrypted task plan from requirements.
Prerequisites: At least one public key configured.
Steps:
Load key configuration:
-
Check .claude/secret-tasks.local.md (project-local)
-
Fall back to ~/.claude/secret-tasks.local.md (user-global)
-
Fall back to SAFE_PUB_KEY env var
-
If none: stop and show configuration instructions
Gather requirements:
-
Ask user to describe the feature, or
-
Read from spec file if provided
Generate 10-30 tasks:
-
Each completable in <30 minutes
-
IDs as strings: "1", "2", "3"
-
All start as "pending"
-
Use blockedBy/blocks for dependencies
For each task, encrypt description:
With multiple recipients:
echo "DESCRIPTION" | safe encrypt -i - -o - -r key1.pub -r key2.pub | base64
Single recipient:
echo "DESCRIPTION" | safe encrypt -i - -o - -r "$SAFE_PUB_KEY" | base64
Create task JSON:
{ "id": "N", "subject": "Secret Task N", "description": "Decrypt the following using the safe CLI: "BASE64"", "activeForm": "Working on secret task N", "status": "pending", "blockedBy": [], "blocks": [] }
Write files:
mkdir -p ~/.claude/tasks/[feature-slug]
Write each task to ~/.claude/tasks/[feature-slug]/N.json
Report:
-
Total tasks created
-
Output directory
-
Launch command: CLAUDE_CODE_TASK_LIST_ID=~/.claude/tasks/[slug] claude
Decrypt Task
When: User wants to see a task's actual description, or Claude encounters encrypted task content.
Trigger detection: Description contains "Decrypt the following using the safe CLI:"
Steps:
Load private key:
-
Check .claude/secret-tasks.local.md for private_key
-
Fall back to SAFE_KEY_PATH env var
-
If none: stop and show configuration instructions
Locate task file:
-
If given task ID (number): search ~/.claude/tasks/*/$ID.json
-
If given path: use directly
Read and parse task JSON
Extract encrypted content from description (base64 between quotes)
Decrypt:
echo "BASE64" | base64 -d | safe decrypt -i - -o - -k "[private-key-path]"
Display:
Task #N: Secret Task N Status: pending Blocked by: [deps] Blocks: [deps]
--- Decrypted Description --- [actual task content]
Error handling:
-
Wrong key: "Decryption failed - key may not match"
-
File not found: "Task file not found" + list available
-
No key configured: Show setup instructions
Settings File Format
Location: .claude/secret-tasks.local.md
private_key: ~/.safe/mykey.x25519.key public_keys:
- ~/.safe/alice.x25519.pub
- ~/.safe/bob.x25519.pub
- /shared/team.pub
Secret Tasks Configuration
Add this file to .gitignore.
Environment Variables (Fallback)
Variable Purpose
SAFE_KEY_PATH
Private key for decryption
SAFE_PUB_KEY
Public key for encryption (single recipient)
Settings file takes priority over environment variables.
Task File Format
{ "id": "1", "subject": "Secret Task 1", "description": "Decrypt the following using the safe CLI: "c2FmZS1lbmNy..."", "activeForm": "Working on secret task", "status": "pending", "blockedBy": [], "blocks": ["2", "3"] }
Visible (no key needed): IDs, subjects, dependencies, status Hidden (encrypted): Actual descriptions, file paths, implementation details
Launching with Task List
CLAUDE_CODE_TASK_LIST_ID=~/.claude/tasks/my-feature claude
Claude Code will:
-
Load tasks from the directory
-
Track status and dependencies
-
Automatically decrypt when needed (using this skill)
Troubleshooting
"No private key configured"
Configure via settings (recommended)
Tell Claude: "use key ~/.safe/mykey.x25519.key"
Or via environment
export SAFE_KEY_PATH=~/.safe/mykey.x25519.key
"Decryption failed"
-
Wrong key (doesn't match public key used for encryption)
-
Corrupted content
-
safe CLI not installed
"safe: command not found" Install from: https://github.com/grittygrease/safe