Secrets
Secure credentials without environment variables
MUXI uses encrypted files instead of environment variables. Your API keys stay secure, portable, and never leak in logs.
Why Not Environment Variables?
We decided against environment variables because they're not portable and not secure to share.
| Problem | Environment Variables | MUXI Secrets |
|---|---|---|
| Visible in process lists | ✗ Yes | ✓ No |
| Appear in crash dumps | ✗ Yes | ✓ No |
| Leak in CI/CD logs | ✗ Often | ✓ Never |
| Portable with code | ✗ No | ✓ Yes |
| Safe to commit | ✗ Never | ✓ Encrypted file |
The sharing problem: You can share a formation with someone, but how do they know what secrets it needs? With MUXI's approach:
secretsis like.env.example- shows required keyssecrets.enccontains encrypted values - safe to commit- The recipient creates their own values for the same keys
The GitHub Actions-style notation (${{ secrets.KEY }}) makes it clear exactly where each secret is used.
Learn more about the design decision in Why Encrypted Secrets.
API Reference:
GET /v1/secrets- List secretsPOST /v1/secrets- Create secretPUT /v1/secrets/{key}- Update secretDELETE /v1/secrets/{key}- Delete secret
How It Works
formation/
├── formation.afs # References secrets like ${{ secrets.KEY }}
├── secrets.enc # Encrypted secrets (safe to commit)
├── secrets # Template showing required secrets
└── .key # Encryption key (NEVER commit!)
Reference secrets in YAML:
# In formation.afs
llm:
api_keys:
openai: "${{ secrets.OPENAI_API_KEY }}"
# In mcp/github.afs
schema: "1.0.0"
id: github
type: command
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
auth:
type: env
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
Set Up Secrets
-
Run the setup wizard
muxi secrets setupThe wizard scans your formation and prompts for each required secret:
Setting up secrets for my-assistant... Required secrets: OPENAI_API_KEY (from llm.api_keys) BRAVE_API_KEY (from mcps.web-search) Enter OPENAI_API_KEY: **** Enter BRAVE_API_KEY: **** ✓ Secrets encrypted and saved -
Verify secrets are saved
muxi secrets listOutput (keys only, not values):
OPENAI_API_KEY BRAVE_API_KEY
Manage Individual Secrets
Set a Secret
muxi secrets set GITHUB_TOKEN
# Enter value when prompted
Or from a file/pipe:
echo $GITHUB_TOKEN | muxi secrets set GITHUB_TOKEN --stdin
Get a Secret
muxi secrets get OPENAI_API_KEY
# Displays the value (use carefully!)
Delete a Secret
muxi secrets delete OLD_API_KEY
File Structure
my-formation/
├── secrets.enc # Encrypted - SAFE to commit
├── secrets # Template - SAFE to commit
└── .key # Encryption key - NEVER commit!
.gitignore
Always include:
# MUXI secrets
.key
Never commit .key to version control. Without the key, secrets.enc is unreadable - this is a security feature.
secrets
Document required secrets for your team:
# Required secrets for this formation
OPENAI_API_KEY=
BRAVE_API_KEY=
DATABASE_URL=
Using Secrets in Formations
In LLM Config
llm:
api_keys:
openai: ${{ secrets.OPENAI_API_KEY }}
anthropic: ${{ secrets.ANTHROPIC_API_KEY }}
In MCP Config Files
# mcp/database.afs
schema: "1.0.0"
id: database
type: command
command: npx
args: ["-y", "@modelcontextprotocol/server-postgres"]
auth:
type: env
DATABASE_URL: "${{ secrets.DATABASE_URL }}"
# mcp/github.afs
schema: "1.0.0"
id: github
type: command
command: npx
args: ["-y", "@modelcontextprotocol/server-github"]
auth:
type: env
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
Team Sharing
To share a formation with teammates:
- Commit
secrets.encandsecretsto git - Share
.keysecurely (password manager, secure channel) - Or have teammates run
muxi secrets setupwith their own keys
Backup and Recovery
Backup
Store .key in a secure location:
- Password manager (1Password, Bitwarden)
- Secret vault (HashiCorp Vault, AWS Secrets Manager)
- Secure backup separate from the repository
Recovery
If you lose .key:
# No recovery possible - must recreate
rm secrets.enc
muxi secrets setup
# Re-enter all secrets
There's no backdoor. Lost key = re-enter all secrets. This is intentional security.
Troubleshooting
"Missing secret" error
The secret isn't set. Add it:
muxi secrets set MISSING_KEY
"Cannot decrypt" error
Wrong .key file or corrupted secrets.enc:
rm secrets.enc
muxi secrets setup
Secrets not loading
Check files exist and permissions:
ls -la secrets.enc .key
# Both should exist and be readable
Best Practices
- Never commit
.key- Add to.gitignore - Keep
secretsupdated - Document all required secrets - Backup
.keysecurely - Can't recover without it - Use descriptive names -
OPENAI_API_KEYnotKEY1 - Rotate periodically - Update secrets regularly
- Least privilege - Each tool gets only the secrets it needs
Next Steps
Why Encrypted Secrets - Design rationale
Tools - Use secrets with MCP servers
Security - Full security model