A FastAPI-based registry server for cryptographically signed AI agent skills.
- Identity management with approval workflow
- Cryptographic verification of skill packages using SSH signatures
- Certificate Revocation List (CRL) support
- Local or S3 storage backends
- Admin API with authentication
- Web frontend for browsing registry
- Python 3.10+
ssh-keygen(for key fingerprinting)
# Clone the repository
cd /Users/rich/Projects/skill-registry
# Install dependencies
pip install -e ".[dev]"
# Copy example environment file
cp .env.example .env
# Edit .env and set a secure admin key
# REGISTRY_ADMIN_KEY=your-secret-key-hereuvicorn app.main:app --host 0.0.0.0 --port 8400 --reloadThe server will be available at http://localhost:8400
pytest tests/ -v --cov=app| Variable | Default | Description |
|---|---|---|
REGISTRY_ADMIN_KEY |
change-me-in-production |
Secret key for admin API access |
REGISTRY_STORAGE_BACKEND |
local |
Storage backend: local or s3 |
REGISTRY_DATA_DIR |
./data |
Directory for local storage backend |
REGISTRY_BASE_URL |
http://localhost:8400 |
Public base URL of the registry |
REGISTRY_TITLE |
Skill Registry |
Registry title shown in web frontend |
AWS_BUCKET_NAME |
- | S3 bucket name (for S3 backend) |
AWS_REGION |
us-west-1 |
AWS region (for S3 backend) |
GET /- Web homepageGET /identities- List approved identitiesGET /identities/crl- Certificate revocation listPOST /identities/request- Submit identity for approvalGET /skills- List all published skillsGET /skills/{name}- Get latest version of a skillGET /skills/{name}/{version}- Get specific skill versionGET /skills/{name}/{version}/download- Download skill packagePOST /skills/submit- Submit a signed skill packageGET /stats- Registry statistics
GET /admin/dashboard- Admin web dashboardGET /admin/pending- List pending identity requestsPOST /admin/identities/{id}/approve- Approve identityPOST /admin/identities/{id}/reject- Reject identityPOST /admin/identities/{id}/revoke- Revoke approved identity
- EC2 instance (t2.micro or larger)
- Caddy or nginx for reverse proxy
- systemd or launchd for process management
- Install Python 3.10+ on the EC2 instance
- Clone the repository
- Install dependencies:
pip install -e . - Create
.envfile with production settings - Set up reverse proxy (example for Caddy):
# /etc/caddy/Caddyfile
registry.yourdomain.com {
reverse_proxy localhost:8400
}
- Create systemd service (Linux) or launchd plist (macOS)
[Unit]
Description=Skill Registry
After=network.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/skill-registry
Environment="PATH=/home/ubuntu/.local/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/usr/local/bin/uvicorn app.main:app --host 127.0.0.1 --port 8400
Restart=always
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl enable skill-registry
sudo systemctl start skill-registry<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.glados.skill-registry</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/uvicorn</string>
<string>app.main:app</string>
<string>--host</string>
<string>127.0.0.1</string>
<string>--port</string>
<string>8400</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/rich/Projects/skill-registry</string>
<key>StandardOutPath</key>
<string>/tmp/skill-registry.log</string>
<key>StandardErrorPath</key>
<string>/tmp/skill-registry.log</string>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>Load the service:
launchctl load ~/Library/LaunchAgents/com.glados.skill-registry.plist- State stored in
REGISTRY_DATA_DIR/registry_state.json - Packages stored in
REGISTRY_DATA_DIR/packages/ - Atomic writes using temp files
- Auto-creates directories on startup
- State stored in S3 bucket under
state/registry_state.json - Packages stored under
packages/ - Requires AWS credentials or IAM role
- All identity requests are rate-limited (3/hour per IP)
- Admin API requires authentication via
X-Admin-Keyheader - Package uploads are limited to 10MB
- Tar archives are validated for path traversal attacks
- CRL is checked on every skill download
- All state mutations use atomic writes
skill-registry/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI app factory
│ ├── config.py # Settings (env vars)
│ ├── models.py # Pydantic models
│ ├── storage.py # Storage backends
│ ├── auth.py # Admin authentication
│ ├── routers/
│ │ ├── identities.py # Identity endpoints
│ │ ├── skills.py # Skill endpoints
│ │ ├── admin.py # Admin endpoints
│ │ └── stats.py # Stats endpoint
│ ├── templates/ # Jinja2 templates
│ └── static/ # Static files (CSS)
├── tests/ # Pytest tests
├── pyproject.toml
├── README.md
└── .env.example
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Run
pytest tests/ -v - Submit a pull request
MIT