This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A modern AWS spot instance deployment tool for deploying Bacalhau compute nodes and sensor simulations. Features a clean Python package structure with beautiful Rich terminal output. Requires Python 3.12+.
- Package structure: Modular design in
amauo/package - State management: JSON-based (
instances.json) for simplicity - Configuration: YAML-based (
config.yaml) with sensible defaults - Caching: File-based AMI caching (
.aws_cache/) - UI: Rich library for beautiful terminal tables and live progress
- uvx-first: Distributed via uvx for instant execution without containers
- Node Identity: Deterministic sensor identity generation for Bacalhau integration
CRITICAL: This project uses immutable infrastructure. ALWAYS destroy and recreate instances when testing changes. Never patch running instances.
# 1. Make changes to deployment code
# 2. Destroy ALL existing instances
./spot-dev.sh destroy
# 3. Verify cleanup
./spot-dev.sh list # Should be empty
# 4. Deploy fresh instances
./spot-dev.sh create
# 5. Check deployment status
./spot-dev.sh list# Setup configuration
./spot-dev.sh setup
# Deploy instances (hands-off approach)
./spot-dev.sh create
# Note: After creation, instances configure themselves autonomously
# Check back in ~5 minutes for fully configured instances
# List running instances
./spot-dev.sh list
# Destroy all instances
./spot-dev.sh destroy
# Get help
./spot-dev.sh help# Scan VPCs (dry run)
uv run delete_vpcs.py --dry-run
# Full cleanup
uv run delete_vpcs.pyThis project uses pre-commit hooks to automatically run code quality checks before each commit.
# Setup pre-commit (one-time setup)
./scripts/setup-pre-commit.sh
# Manual run (if you can't install hooks due to global git config)
uv run pre-commit run --all-files# Linting - ALWAYS run before committing
uv run ruff check .
# Auto-fix linting issues where possible
uv run ruff check . --fix
# Format code
uv run ruff format .
# Type checking - CRITICAL: Run same command as CI
uv run mypy src/amauo/ --ignore-missing-imports --check-untyped-defsImportant: Pre-commit hooks will automatically run ruff, mypy, and bandit checks on every commit. The configurations are now synchronized between pre-commit and CI to prevent discrepancies. If you have a global git hooks path configured, you may need to run checks manually with uv run pre-commit run --all-files.
src/amauo/- Main package directoryspot-dev- Local development CLI wrapper using uvdelete_vpcs.py- Advanced VPC cleanup utility
AWSResourceManager- Centralized AWS operations with retry logicSSHManager- SSH operations and file transfers with retriesUIManager- Unified terminal UI managementSimpleConfig- YAML configuration managementSimpleStateManager- JSON-based instance state trackingNodeIdentityGenerator- Deterministic sensor identity creation
├── src/amauo/ # Main package
│ ├── commands/ # CLI commands (create, destroy, list, etc.)
│ ├── core/ # Core classes (config, state, constants)
│ └── utils/ # Utilities (AWS, SSH, display, etc.)
├── instance/
│ ├── scripts/ # Scripts deployed to instances
│ └── config/ # Configuration templates
├── spot-dev # Local development CLI wrapper
├── delete_vpcs.py # VPC cleanup utility
├── config.yaml # Runtime configuration
├── config.yaml.example # Comprehensive example
├── instances.json # Runtime state (auto-created)
├── .aws_cache/ # AMI cache directory
└── deployment-files/ # All files to deploy to instances
aws:
total_instances: 3
username: ubuntu
ssh_key_name: my-key
files_directory: "files"
scripts_directory: "instance/scripts"
regions:
- us-west-2:
machine_type: t3.medium
image: auto # Auto-discovers latest Ubuntu 24.04IMPORTANT: Bacalhau compute nodes require orchestrator connection details. These are provided via credential files:
Create these files in the deployment-files/ directory before deployment:
-
deployment-files/orchestrator_endpoint- Contains the NATS endpoint URLnats://orchestrator.example.com:4222 -
deployment-files/orchestrator_token- Contains the authentication tokenyour-secret-token-here
Security Notes:
- The files are listed in
.gitignoreto prevent accidental commits - If these files are missing, compute nodes will start but won't connect to any orchestrator
- During
amauo create, the credential files are mirrored to their target locations - The
bacalhau.servicerunsgenerate_bacalhau_config.shwhich:- Reads the credential files
- Generates a complete
/bacalhau_node/config.yamlwith orchestrator endpoint and token injected
- Bacalhau service reads the generated config.yaml directly
- No environment variables needed - all configuration is in the YAML file
- AWSResourceManager: All AWS operations go through this manager
- SSHManager: All SSH operations use this for consistent retry logic
- UIManager: All UI operations for consistent terminal output
- Managers handle retries, timeouts, and error handling internally
- NEVER modify running instances
- ALWAYS destroy and recreate for any changes
- Treat instances as disposable cattle, not pets
- Fix issues in code, not on instances
- Upload files and enable services, then disconnect
- No long-running SSH connections during setup
- Cloud-init handles package installation only
- deploy_services.py handles all application setup
- SystemD services start automatically after reboot
- JSON file for instance tracking
- Region-based cleanup
- Automatic state synchronization
- Beautiful tables for instance lists
- Progress bars for file upload only
- Styled success/error messages (✅ ❌ ℹ️
⚠️ ) - Minimal status updates (hands-off approach)
- Direct boto3 calls (no abstraction layers)
- AMI auto-discovery with caching
- VPC/subnet auto-discovery
- Spot instance lifecycle management
- Retry Logic: All network operations retry 3 times with exponential backoff
- Specific Error Codes: Handles AWS error codes like
InsufficientInstanceCapacity - Graceful Degradation: When regions fail, continues with others
- Clear Error Messages: Shows specific error codes and guidance
- Automatic Cleanup: On failure, cleans up partial resources
- Timeout Configuration:
- Connection timeout: 10 seconds
- Read timeout: 60 seconds
- SSH timeout: 300 seconds (configurable)
- Deterministic generation based on EC2 instance ID
- Realistic US city locations with GPS coordinates
- Authentic sensor manufacturer/model data
- Automatic generation during startup
- Output to
/opt/sensor/config/node_identity.json
- Startup time: ~0.15 seconds (93% faster than original)
- File size: 30KB (65% reduction from original)
- Dependencies: 3 packages only (boto3, pyyaml, rich)
- Full type annotations throughout
- Clear docstrings for all functions
- Consistent error handling patterns
- Single-file design for simplicity
- Follow modular package structure
- Update configuration schema if needed
- Test with real AWS resources using
./spot-dev
- IMPORTANT: Never debug by patching instances
- Fix issues in source code
- Destroy all instances:
./spot-dev.sh destroy - Deploy fresh:
./spot-dev.sh create - Check
instances.jsonfor state issues - Use
--dry-runwith VPC cleanup for safety - Verify deployment log at
/opt/deployment.logon instances
The deployment tool includes a custom ConsoleLogger that enhances log output with instance identification and IP addresses. During deployment, all SUCCESS and ERROR messages are automatically prefixed with:
- Instance ID and IP address:
[i-1234567890abcdef0 @ 54.123.45.67] SUCCESS: Created - This helps identify which specific instance is producing each log message
- Makes it easy to SSH into the correct instance for debugging
Example output:
[i-0a1b2c3d4e5f67890 @ 52.34.56.78] SUCCESS: Created
[i-0a1b2c3d4e5f67890 @ 52.34.56.78] SUCCESS: Setup complete - rebooting to start services
[i-9f8e7d6c5b4a32109 @ 54.67.89.12] SUCCESS: Created
[i-9f8e7d6c5b4a32109 @ 54.67.89.12] ERROR: File upload failed
- Always provide sensible defaults
- Update
config.yaml.examplefor new options - Test with minimal configuration
- Identities are deterministic based on instance ID
- Test with:
INSTANCE_ID=i-test python3 instance/scripts/generate_node_identity.py - Check generated identity:
cat /opt/sensor/config/node_identity.json | jq . - Add new cities/manufacturers in
generate_node_identity.py
- This project should only use one table function for everything