Complete guide to using MUXI's encrypted secrets system with Docker Compose
MUXI uses encrypted secrets files, NOT environment variables or .env files!
- Formation-Level Secrets: Each formation has its own encrypted secrets
- Encrypted Storage: Secrets stored in
secrets.enc(encrypted) - Decryption Key:
.keyfile decrypts the secrets - Never in Environment: API keys never go in environment variables
formations/
└── my-formation/
├── formation.afs # Formation config
├── secrets.enc # Encrypted secrets ✅ (safe to commit)
├── .key # Decryption key ⚠️ (NEVER commit!)
└── secrets # Template (auto-generated)
Security:
- ✅
secrets.enc- Encrypted, safe to share ⚠️ .key- Must be kept secret (in .gitignore)- ✅
secrets- Template only, no values
mkdir -p formations/my-agent
cd formations/my-agent
cat > formation.afs << 'EOF'
schema: "1.0.0"
id: my-agent
llm:
api_keys:
openai: "${{ secrets.OPENAI_API_KEY }}"
models:
- text: "openai/gpt-4o-mini"
agents:
- id: assistant
name: "My Assistant"
system_message: "You are helpful."
EOF# From your formation directory
python ../../utils/add_secret.py
# Interactive prompts:
# Formation directory: . (or leave empty for current)
# Key name: OPENAI_API_KEY
# Value: sk-your-actual-key-hereThis creates secrets.enc and .key files.
# Return to runtime directory
cd ../../
# Start MUXI - secrets are automatically loaded!
docker compose up muxiDone! MUXI reads secrets.enc using .key at startup.
cd formations/my-formation
python ../../utils/add_secret.py
# Prompts:
# Formation: . (current directory)
# Key name: ANTHROPIC_API_KEY
# Value: sk-ant-your-keycd formations/my-formation
python ../../e2e/assets/list_secrets.pyOutput:
Secrets in formations/my-formation:
- OPENAI_API_KEY: sk-***************************
- ANTHROPIC_API_KEY: sk-ant-*********************
cd formations/my-formation
python ../../utils/delete_secret.py
# Prompts:
# Formation: . (current directory)
# Key name: ANTHROPIC_API_KEYJust add it again - overwrites the old value:
python ../../utils/add_secret.py
# Use same key name with new valueReference secrets using the template syntax:
llm:
api_keys:
openai: "${{ secrets.OPENAI_API_KEY }}"
anthropic: "${{ secrets.ANTHROPIC_API_KEY }}"
google: "${{ secrets.GOOGLE_API_KEY }}"
mcp:
servers:
- name: "github"
command: "mcp-github"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"Template Syntax: ${{ secrets.KEY_NAME }}
- Docker Compose mounts your
formations/directory - Each formation directory includes
secrets.encand.key - MUXI runtime reads and decrypts secrets on startup
- Secrets are used to populate the formation configuration
# In docker-compose.yaml
volumes:
- ${FORMATIONS_DIR:-./formations}:/formations:roThis mounts:
formations/my-agent/formation.afsformations/my-agent/secrets.encformations/my-agent/.key
All automatically!
- Keep
.keyfiles secure and backed up separately - Add
.keyto.gitignore(already done) - Commit
secrets.enc(it's encrypted) - Commit
secrets(template only) - Use different
.keyfiles per environment - Share
secrets.encwith team (key separately)
- Never commit
.keyfiles - Never put API keys in environment variables
- Never share
.keyvia insecure channels - Never hard-code secrets in YAML
- Never use same
.keyacross environments
formations/my-agent-dev/
├── formation.afs
├── secrets.enc # Dev API keys
└── .key # Dev key
formations/my-agent-prod/
├── formation.afs
├── secrets.enc # Prod API keys (different!)
└── .key # Prod key (different!)
Different .key means different encryption, even if you commit both secrets.enc files.
Step 1: Developer creates formation
# Create formation and add secrets locally
cd formations/new-feature
python ../../utils/add_secret.py
# Add OPENAI_API_KEY
# Commit encrypted secrets (NOT .key!)
git add formation.afs secrets.enc secrets
git commit -m "Add new feature formation"
git pushStep 2: Teammate pulls formation
# Pull the changes
git pull
# They need the .key file (shared securely, NOT via git)
# Get .key via: 1Password, AWS Secrets Manager, secure chat, etc.
# Put it in: formations/new-feature/.key
# Now they can run it
docker compose up muxiSecure Key Sharing Methods:
- 1Password shared vaults
- AWS Secrets Manager
- HashiCorp Vault
- Encrypted email
- Secure messaging (Signal, etc.)
- Physical transfer (USB, etc.)
Error: Could not find .key file in formations/my-agent/
Fix: Create the .key file:
cd formations/my-agent
python ../../utils/add_secret.py
# This will create .key if it doesn't existError: Failed to decrypt secrets.enc
Fix: Wrong .key file or corrupted secrets.enc:
# Regenerate from scratch
rm secrets.enc .key
python ../../utils/add_secret.py
# Re-add all secretsError: Secret OPENAI_API_KEY not found in secrets.enc
Fix: Add the secret:
cd formations/my-agent
python ../../utils/add_secret.py
# Add OPENAI_API_KEY# List secrets (shows masked values)
cd formations/my-agent
python ../../e2e/assets/list_secrets.pyllm:
api_keys:
openai: "${{ secrets.OPENAI_API_KEY }}"
anthropic: "${{ secrets.ANTHROPIC_API_KEY }}"
openai_backup: "${{ secrets.OPENAI_API_KEY_2 }}"Add each secret:
python utils/add_secret.py # OPENAI_API_KEY
python utils/add_secret.py # ANTHROPIC_API_KEY
python utils/add_secret.py # OPENAI_API_KEY_2You can use any name:
# Add custom secrets
python utils/add_secret.py
# Key: MY_CUSTOM_DATABASE_URL
# Value: postgresql://...
# Use in formation:
database:
url: "${{ secrets.MY_CUSTOM_DATABASE_URL }}"Some secrets may be optional:
llm:
api_keys:
# Required
openai: "${{ secrets.OPENAI_API_KEY }}"
# Optional - only needed for certain features
anthropic: "${{ secrets.ANTHROPIC_API_KEY || '' }}"utils/add_secret.py- Add/update secrets utilityutils/delete_secret.py- Delete secrets utilitye2e/assets/list_secrets.py- List secrets utilitydocs/secrets-management.md- Detailed MUXI secrets documentationDOCKER_COMPOSE_GUIDE.md- Docker Compose usageformations/example-formation/README.md- Example setup
Remember:
- ✅ Secrets go in
secrets.enc(encrypted, per-formation) ⚠️ .keyis required to decrypt (keep it secure!)- ❌ Never use environment variables for API keys
- ✅ Use
python utils/add_secret.pyto manage secrets - ✅ Reference with
${{ secrets.KEY_NAME }}in YAML - ✅ Docker automatically mounts formation directories
That's it! MUXI's secrets system keeps your API keys secure and encrypted. 🔐
Need help? Check DOCKER_COMPOSE_GUIDE.md for full Docker documentation.