Environment Management
Environment management in HORUS allows you to capture, save, and restore the exact set of packages and versions used in your project. Perfect for reproducible builds, team collaboration, and deployment.
Overview
Think of environments like Python's requirements.txt or Node's package-lock.json:
- Freeze your current environment to a file
- Restore environments on different machines
- Share setups with teammates
- Deploy exact versions to production robots
- Track environment history in version control
Understanding HORUS's Hidden Environment
HORUS automatically manages a hidden .horus/ environment in each project. Understanding the global vs local architecture helps you work efficiently across multiple projects.
Global Cache (Shared Storage)
Location: ~/.horus/cache/
All packages are downloaded once and stored here:
~/.horus/cache/
── horus_py@0.1.0/ # HORUS packages
── lib/horus/
── serde@1.0.228/ # External crates (from crates.io)
── src/
── Cargo.toml # Cargo lives here, not your project!
── lib/libserde.rlib # Pre-compiled
── pid-controller@1.2.0/ # More HORUS packages
Benefits:
- Download once - Use in all projects
- Saves disk space - No duplication
- Faster setup - Cached packages install instantly
- Works offline - Already have what you need
Local Workspace (Project-Specific)
Location: .horus/ in your project
Each project gets its own isolated environment:
my_robot_project/
── horus.yaml # Dependencies declared here
── main.py / main.rs # Your code
── .horus/ # Hidden automatic environment
── packages/ # Symlinks to global cache
── horus_py -> ~/.horus/cache/horus_py@0.1.0/
── serde -> ~/.horus/cache/serde@1.0.228/
── bin/ # Project binaries (auto-created)
── lib/ # Project libraries (auto-created)
── Cargo.toml # Generated for Rust projects (auto-managed)
── Cargo.lock # Cargo lock file for Rust (auto-managed)
── target/ # Cargo build artifacts for Rust (auto-managed)
Key Points:
- Workspace marker -
.horus/identifies a HORUS project - Symlinks not copies - Points to global cache (lightweight!)
- Isolated - Each project independent
- Auto-managed - Created by
horus run, not by you
Automatic Workflow
When you run horus run:
- Reads
horus.yamldependencies - Checks global cache - already downloaded?
- Downloads if missing:
- HORUS registry first
- crates.io fallback for external Rust crates
- Compiles external crates (in global cache with cargo)
- Symlinks to
.horus/packages/in your project - For Rust projects: Generates
.horus/Cargo.tomlfromhorus.yamlwith path-based dependencies - Runs your code with correct environment
You never touch .horus/ - It's automatic!
Why This Matters
Portable: horus.yaml works on any machine
# Team member clones your project
git clone your-repo
cd your-repo
horus run # Auto-installs everything, just works!
Lightweight: Projects stay small
# Without HORUS (traditional)
project1/node_modules/ # 500 MB
project2/node_modules/ # 500 MB
project3/node_modules/ # 500 MB
# Total: 1.5 GB duplicated!
# With HORUS (global cache)
~/.horus/cache/ # 500 MB (shared)
project1/.horus/packages/ # Symlinks only (a few KB)
project2/.horus/packages/ # Symlinks only (a few KB)
project3/.horus/packages/ # Symlinks only (a few KB)
# Total: 500 MB globally, ~10 KB per project!
Isolated: Projects don't interfere
# Different versions, no problem
project_a/horus.yaml: serde@1.0.228
project_b/horus.yaml: serde@1.0.150
# Both work perfectly - isolated environments
Solving Dependency Hell
HORUS solves dependency hell with local-first resolution and smart fallback:
Resolution Order (how horus run finds packages):
- Check local first -
.horus/packages/<package>exists? Use it immediately - Check global cache - Only if not found locally
- Install from registry - Only if missing from both
Local Always Wins:
# Scenario: Global cache has broken package
~/.horus/cache/
── serde@1.0.228/ # Corrupted or incompatible
my_project/.horus/packages/
── serde@1.0.150/ # Working local version
# When you run:
horus run
# Uses local serde@1.0.150 (line 1010-1012 in run.rs)
# NEVER checks global cache
# Broken global version ignored!
Automatic Smart Behavior:
When you install a package, HORUS automatically chooses the best strategy:
horus pkg install serde
If package exists in global cache:
- Install to global cache (save disk space)
- Create symlink:
.horus/packages/serde -> ~/.horus/cache/serde@1.0.228/ - All projects share same version efficiently
If package NOT in global cache:
- Install directly to local:
.horus/packages/serde@1.0.228/ - No symlink needed - real directory
- Project is isolated from global cache
Override Broken Global Cache:
If global cache has corrupted or incompatible package:
# Option 1: Remove symlink and reinstall locally
rm .horus/packages/serde # Remove symlink to broken global
horus pkg install serde # Installs locally (global check fails)
# Option 2: Install different version locally
horus pkg install serde -v 1.0.150 # Specific working version
# Option 3: Clear global and reinstall
rm -rf ~/.horus/cache/serde@1.0.228/
horus run # Auto-reinstalls to global
Benefits:
True isolation - Local packages override global No conflicts - Version-specific directories coexist Disk efficient - Uses global cache when possible Escape hatch - Can bypass broken global cache Zero config - Works automatically
Comparison with other tools:
| Feature | Python venv | Node node_modules | HORUS |
|---|---|---|---|
| Isolated envs | Full copies | Full copies | Symlinks + local override |
| Disk efficient | Duplicates everything | Duplicates everything | Global cache shared |
| Local override | Always local | Always local | Local-first, global fallback |
| Escape broken global | Independent | Independent | Local override |
| Multiple versions | One per venv | Nested hell | Version-specific dirs |
Best of both worlds:
- Disk efficiency of global cache (like Cargo, pip global)
- Isolation of virtual environments (like venv, node_modules)
- Smart automatic fallback
Quick Start
Save Your Environment
# Freeze to default file (horus-freeze.yaml)
horus env freeze
# Freeze to custom file
horus env freeze -o production.yaml
# Freeze and publish to registry
horus env freeze --publish
Restore an Environment
# Restore from local file
horus env restore horus-freeze.yaml
# Restore from registry
horus env restore env_abc123
Environment Files
Format
Environment files use YAML format with complete package information:
horus-freeze.yaml:
# HORUS Environment
# Generated: 2025-10-09T14:32:15Z
# System: Linux 6.14.0-33-generic
metadata:
name: "Mobile Robot Production Environment"
description: "Stable release for lab robots"
author: "robotics-team"
created_at: "2025-10-09T14:32:15Z"
horus_version: "0.1.0"
packages:
# Direct dependencies
- name: pid-controller
version: 1.2.0
source: registry
checksum: sha256:a3b2c1...
features: ["anti-windup"]
- name: motion-planner
version: 2.0.1
source: registry
checksum: sha256:d4e5f6...
dependencies:
- pathfinding-utils: 1.2.0
- name: sensor-drivers
version: 1.5.0
source: registry
checksum: sha256:g7h8i9...
# Total: 3 packages (+ 1 transitive dependency)
File Locations
Default locations:
my_project/
── horus-freeze.yaml # Default freeze file
── production.yaml # Custom freeze file
── environments/ # Optional: organize freeze files
── dev.yaml
── staging.yaml
── production.yaml
── .horus/ # Auto-managed, don't store freeze files here
── packages/ # Symlinks to global cache
── bin/ # Compiled binaries
── lib/ # Libraries
── include/ # Headers
Note: Store freeze files in your project root or a custom
environments/folder (not inside.horus/). The.horus/directory is auto-managed and should not contain user files.
Freezing Environments
horus env freeze
Captures the current state of all installed packages.
Usage:
horus env freeze [OPTIONS]
Options:
-o, --output <FILE>- Output file (default:horus-freeze.yaml)--publish- Upload to registry and generate ID
Basic Freeze
horus env freeze
Output:
Analyzing environment...
Found 5 packages (3 direct, 2 transitive)
Verified checksums
Generated metadata
Saved to: horus-freeze.yaml
Packages frozen:
pid-controller@1.2.0
motion-planner@2.0.1
sensor-drivers@1.5.0
pathfinding-utils@1.2.0 (transitive)
control-utils@1.0.0 (transitive)
To restore this environment:
horus env restore horus-freeze.yaml
Custom Output File
# Save to specific file
horus env freeze -o environments/production.yaml
# Timestamp-based filename
horus env freeze -o "backup-$(date +%Y%m%d).yaml"
Publish to Registry
# Freeze and upload to registry
horus env freeze --publish
Output:
Freezing environment...
Captured 5 packages
Generated manifest
Uploading to registry...
Uploaded
Environment published:
ID: env_abc123def456
URL: https://marketplace.horus-registry.dev/environments/env_abc123def456
Share this environment:
horus env restore env_abc123def456
Or save locally:
horus env freeze -o local-copy.yaml
Benefits of publishing:
- No file transfer - Just share the environment ID
- Version tracking - Registry keeps history
- Team access - Anyone authenticated can restore
- Immutable - Can't be changed after publishing
Restoring Environments
horus env restore
Installs the exact packages from a frozen environment.
Usage:
horus env restore <FILE_OR_ID>
Options:
Note: Additional options for restore are planned for future releases.
Restore from File
# Restore from local file
horus env restore horus-freeze.yaml
Output:
Reading environment: horus-freeze.yaml
Name: Mobile Robot Production Environment
Packages: 5 (3 direct, 2 transitive)
Created: 2025-10-09
Restoring environment...
pid-controller@1.2.0
motion-planner@2.0.1
sensor-drivers@1.5.0
pathfinding-utils@1.2.0 (dependency)
control-utils@1.0.0 (dependency)
Environment restored successfully!
Location: .horus/packages/
Total size: 2.3 MB
Restore from Registry
# Restore using environment ID
horus env restore env_abc123def456
Output:
Fetching environment from registry...
Downloaded env_abc123def456
Name: Production v2.1
Description: Stable release for warehouse robots
Author: robotics-team
Packages: 5
Restoring...
All packages installed
Environment ready!
Common Workflows
Development Workflow
Setup for new developer:
# 1. Clone project
git clone https://github.com/team/robot-controller
cd robot-controller
# 2. Restore environment
horus env restore horus-freeze.yaml
# 3. Run project
horus run --release
Update dependencies:
# 1. Install new package
horus pkg install new-feature
# 2. Test
horus run --release
# 3. Freeze updated environment
horus env freeze
# 4. Commit changes
git add horus-freeze.yaml
git commit -m "Add new-feature package"
Production Deployment
Prepare for deployment:
# 1. Test locally
horus run --release
# 2. Freeze environment
horus env freeze -o production.yaml \
--name "Production v2.1" \
--description "Release for warehouse robots"
# 3. Publish to registry
horus env freeze --publish
# Output: env_abc123def456
# 4. Deploy to robot
ssh robot@192.168.1.100
horus env restore env_abc123def456
horus run --release --remote
Team Collaboration
Share exact setup:
# Team lead freezes environment
horus env freeze --publish \
--name "Team Development Environment" \
--description "Standard setup for all team members"
# Output: env_team_dev_001
# Team members restore
horus env restore env_team_dev_001
Multiple Environments
Maintain separate environments:
# Development
horus env freeze -o environments/dev.yaml
# Staging
horus env freeze -o environments/staging.yaml
# Production
horus env freeze -o environments/production.yaml
Switch environments:
# Switch to staging
horus env restore environments/staging.yaml
# Switch to production
horus env restore environments/production.yaml
Rollback
If deployment fails, rollback:
# Restore previous working environment
horus env restore backup-20251008.yaml
# Or restore from registry
horus env restore env_previous_stable
Environment Comparison
Note: Environment comparison commands (
env diff,env status) are planned for future releases. For now, you can manually compare freeze files or use standard diff tools.
Best Practices
Version Control
Always commit environment files:
# Add to git
git add horus-freeze.yaml
git commit -m "Update environment: add sensor-fusion package"
# .gitignore (auto-generated by `horus new`)
.horus/packages/ # Don't commit symlinks/packages
.horus/bin/ # Don't commit compiled binaries
.horus/lib/ # Don't commit libraries
.horus/include/ # Don't commit headers
.horus/cache/ # Don't commit cache
.horus/build/ # Don't commit build artifacts
Environment Naming
Use descriptive names:
# Good
name: "Production v2.1 - Warehouse Robots"
name: "Development - Feature Branch XYZ"
name: "Staging - Pre-release Testing"
# Bad
name: "env1"
name: "test"
name: "final_final_v2"
Documentation
Document environment purpose:
metadata:
name: "Production v2.1"
description: |
Stable production environment for warehouse robots.
Features:
- PID controller with anti-windup
- Motion planner with obstacle avoidance
- Sensor drivers for LIDAR and IMU
Tested on:
- Robot A (192.168.1.100)
- Robot B (192.168.1.101)
- Robot C (192.168.1.102)
Last updated: 2025-10-09
Contact: robotics-team@company.com
Periodic Freezes
Freeze regularly:
# Before major changes
horus env freeze -o backup-before-upgrade.yaml
# After successful testing
horus env freeze -o stable-$(date +%Y%m%d).yaml
# Before deployment
horus env freeze -o production-v$(git describe --tags).yaml
Environment Hygiene
Keep environments clean:
# Remove unused packages
horus pkg list
horus pkg remove unused-package
# Refreeze
horus env freeze
Troubleshooting
Package Not Available
Error:
Error: Package 'legacy-driver@0.5.0' not found in registry
Causes:
- Package was unpublished
- Version no longer available
- Registry connection issue
Solutions:
# Option 1: Update environment file
# Remove or replace unavailable package
# Option 2: Install alternative
horus pkg install modern-driver
horus env freeze # Update freeze file
# Option 3: Use cached version
ls ~/.horus/cache/legacy-driver@0.5.0/
Checksum Mismatch
Error:
Error: Checksum mismatch for 'pid-controller@1.2.0'
Expected: sha256:a3b2c1...
Got: sha256:x9y8z7...
Causes:
- Package was modified on registry
- Corrupted download
- Network issue
Solutions:
# Reinstall the package
horus pkg remove pid-controller
horus pkg install pid-controller -v 1.2.0
Version Conflicts
Error:
Error: Cannot satisfy version constraints
motion-planner requires pathfinding-utils ^1.2
sensor-fusion requires pathfinding-utils ^1.0
Solutions:
# Option 1: Install compatible version
horus pkg install sensor-fusion -v 2.0.0
# Option 2: Edit environment file manually
# Change pathfinding-utils version to compatible one
# Option 3: Remove conflicting package
horus pkg remove sensor-fusion
horus env freeze # Update freeze file
Registry Unavailable
Error:
Error: Failed to fetch environment from registry
Solutions:
# Use local file instead
horus env restore horus-freeze.yaml
Note: Environment registry management commands (
env list,env info,env delete,env export) are planned for future releases. For now, manage published environments through the registry web interface at https://marketplace.horus-registry.dev
Next Steps
- Package Management - Install and manage packages
- Authentication - Login to registry
- Remote Deployment - Deploy to remote robots
- CLI Reference - Complete command documentation