# SecretSage

```
   ___                      _    ___
  / __|  ___  __  _ _  ___ | |_ / __|  __ _   __ _   ___
  \__ \ / -_)/ _|| '_|/ -_)|  _|\__ \ / _` | / _` | / -_)
  |___/ \___|\___|_|  \___| \__||___/ \__,_| \__, | \___|
                                             |___/
```

**The missing OAuth for LLM agents.**

Terminal-based credential wizard for agent-driven development. Store credentials securely with age encryption, grant them to agents on demand, revoke when done.

## Installation

```bash
npm install -g @cyclecore/secretsage
```

Or use directly with npx:

```bash
npx @cyclecore/secretsage
```

## Quick Start

```bash
# Initialize vault (one-time setup)
secretsage init

# Add a credential
secretsage add OPENAI_API_KEY

# Grant to .env for agent use
secretsage grant OPENAI_API_KEY

# Revoke when done
secretsage revoke --all
```

## Why SecretSage?

Agents need credentials. But you don't want to:
- Paste keys into agent prompts
- Hardcode them in `.env` files committed to git
- Teach agents how to use your password manager

SecretSage provides a simple flow:
1. Store credentials once in an encrypted vault
2. Grant them to `.env` when an agent needs them
3. Revoke them when the agent is done

Think of it as OAuth for LLM agents.

## Commands

### `secretsage init`

Initialize the vault and generate encryption keypair.

```bash
secretsage init                       # Interactive, prompts for location
secretsage init --local               # Create vault in current directory
secretsage init --path ~/my-vault     # Create vault at custom path
secretsage init --yes                 # Skip prompts, use defaults
```

### `secretsage add <name>`

Add a credential to the encrypted vault.

```bash
secretsage add OPENAI_API_KEY              # Prompts for value
secretsage add API_KEY --value "sk-..."    # Provide value directly
secretsage add DATABASE_URL --from-env     # Import from existing .env
echo "secret" | secretsage add KEY --value -  # Read from stdin
```

### `secretsage list`

List credential names in the vault.

```bash
secretsage list          # Human-readable output
secretsage list --json   # Machine-readable for agents
secretsage list --all    # Include metadata
```

### `secretsage get <name>`

Retrieve a single credential value.

```bash
secretsage get OPENAI_API_KEY              # Default: human-readable "  KEY: value" form
secretsage get OPENAI_API_KEY --raw        # Raw value, no newline (use this when piping)
secretsage get OPENAI_API_KEY --json       # {"name": "...", "value": "..."}
```

**Piping to another tool**: always use `--raw`. The default mode emits a
labeled `"  KEY: value"` form intended for human inspection in the terminal —
it is unsafe to pipe because the rendered prefix bytes will be included in
the pipe output and break downstream tools. When `secretsage get` detects a
non-TTY stdout (i.e., its output is being piped), it prints a stderr warning
recommending `--raw`.

```bash
# Safe — feeds the clean credential value to gh
secretsage get GH_PAT --raw | gh auth login --with-token

# Unsafe — feeds "  GH_PAT: ghp_..." to gh, which fails authentication.
# Default mode now warns on stderr when stdout is piped.
secretsage get GH_PAT | gh auth login --with-token
```

> **Deprecation notice (v1.0)**: the default-mode rendering will change to
> `value\n` (cat-equivalent, safe to pipe) in v1.0. Scripts that rely on the
> labeled form should migrate to `--raw` or `--json` for forward
> compatibility.

### `secretsage grant [names...]`

Decrypt and write credentials to `.env`.

```bash
secretsage grant                         # Interactive selection
secretsage grant OPENAI_API_KEY          # Specific credential
secretsage grant --all                   # All credentials
secretsage grant API_KEY --yes           # Non-interactive (for agents)
```

### `secretsage revoke [names...]`

Remove credentials from `.env` (vault remains intact).

```bash
secretsage revoke                    # Interactive selection
secretsage revoke OPENAI_API_KEY     # Specific credential
secretsage revoke --all              # All credentials
```

### `secretsage config`

View or update configuration.

```bash
secretsage config                              # Show current config
secretsage config --path                       # Show config file path
secretsage config --set agent.autoGitignore=false
```

### `secretsage remove <name>`

Permanently delete a credential from the vault.

```bash
secretsage remove OLD_API_KEY          # Interactive confirmation
secretsage remove OLD_API_KEY --yes    # Skip confirmation
```

### `secretsage rotate <name>`

Update the value of an existing credential.

```bash
secretsage rotate OPENAI_API_KEY                    # Prompts for new value
secretsage rotate API_KEY --value "new-sk-..."      # Provide new value directly
echo "new-secret" | secretsage rotate KEY --value - # Read from stdin
secretsage rotate OAUTH_KEY --generate 32           # Generate random 32-byte key
secretsage rotate KEY --reason "quarterly rotation" # Add reason to audit trail
```

### `secretsage audit <name>`

Show rotation history and audit trail for a credential.

```bash
secretsage audit STRIPE_SECRET_KEY        # Human-readable history
secretsage audit STRIPE_SECRET_KEY --json # Machine-readable for agents
```

### `secretsage wizard`

Open interactive key entry wizard in new terminal (agent-human handoff).

```bash
secretsage wizard --keys STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET --reason "key rotation"
secretsage wizard -k API_KEY,SECRET_KEY -r "quarterly rotation" --timeout 600
```

The wizard:
1. Opens a new terminal window
2. Prompts for each key with validation
3. Encrypts and stores keys in vault
4. Signals completion to calling agent

### `secretsage deploy <project>`

Deploy secrets to a remote server via rsync/SSH.

```bash
secretsage deploy myapp --remote root@host:/var/www/app/
secretsage deploy mcpbodega --remote user@host:/path --restart "pm2 restart app"
secretsage deploy app --remote host:/path -f .env.production --yes
```

### `secretsage backup-codes`

Securely store and manage 2FA backup/recovery codes.

```bash
# Add backup codes for a service (interactive)
secretsage backup-codes add github
secretsage backup-codes add google --account work@company.com

# List services with stored codes
secretsage backup-codes list

# Show codes when you need them
secretsage backup-codes show github

# Mark a code as used (tracks remaining codes)
secretsage backup-codes use github
secretsage backup-codes use github --index 3
```

The command tracks which codes you've used and warns when running low.

### `secretsage export`

Export vault credentials for backup or transfer.

```bash
secretsage export                          # Decrypted JSON to stdout
secretsage export --encrypted              # Encrypted backup
secretsage export --format env             # Export as .env format
secretsage export -o backup.json           # Write to file
```

### `secretsage import`

Import credentials from backup or external source.

```bash
secretsage import -i backup.json           # Import from JSON file
secretsage import --format env -i .env     # Import from .env file
cat backup.json | secretsage import        # Import from stdin
secretsage import --merge -i new.json      # Merge with existing vault
```

### `secretsage status`

Show vault status and health check.

```bash
secretsage status          # Human-readable status
secretsage status --json   # Machine-readable for agents
```

## Agent Integration

### Automatic Grant

Agents can request credentials programmatically:

```bash
# Agent runs this when it needs a credential
npx @cyclecore/secretsage grant OPENAI_API_KEY --yes
source .env
```

### Shell Script Pattern

```bash
#!/bin/bash
if [ -z "$OPENAI_API_KEY" ]; then
  echo "Need OPENAI_API_KEY - launching SecretSage..."
  npx @cyclecore/secretsage grant OPENAI_API_KEY --yes
  source .env
fi
# Continue with agent work...
```

### JSON Output for Agents

```bash
secretsage list --json
```

```json
{
  "credentials": [
    { "name": "OPENAI_API_KEY" },
    { "name": "DATABASE_URL" }
  ],
  "count": 2
}
```

## Security

- **age encryption**: Modern, audited cryptography ([age-encryption.org](https://age-encryption.org))
- **Local storage**: Credentials never leave your machine
- **File permissions**: Identity files are stored with 0600 permissions
- **Auto-gitignore**: Automatically adds `.env` and `.secretsage/` to `.gitignore`
- **Backup on grant**: Creates `.env.backup.*` before modifying

## Vault Locations

| Location | Path | Use Case |
|----------|------|----------|
| Global | `~/.secretsage/` | Share credentials across projects |
| Local | `.secretsage/` | Project-specific credentials |
| Custom | Any path | Shared drives, team locations |

The global vault is used by default. Use `--local` flag, `--path <dir>`, or set `vault.defaultLocation` in config.

## Configuration

Global config: `~/.secretsage/config.yaml`
Local config: `.secretsage/config.yaml`

```yaml
version: "1"

vault:
  defaultLocation: global  # global | local

encryption:
  provider: age

agent:
  autoGitignore: true
  backupEnvOnGrant: true
  requireConfirmation: true
```

## License

Apache 2.0 - CycleCore Technologies

---

Created by [CycleCore Technologies](https://cyclecore.ai)
