Dirvana – Reach Directory Nirvana

1 month ago 6

dirvana-logo

Warning

🧪 Beta Status - We Need Your Feedback!

Dirvana is currently in beta and actively seeking testers to help validate its functionality across different configurations and use cases. Your feedback will help us:

  • Identify edge cases and limitations
  • Improve compatibility across different shell environments
  • Shape the tool's evolution based on real-world usage

Found a bug? Have a feature request? Please open an issue or share your experience!

Automatically load shell aliases, functions, and environment variables per directory.

Dirvana is a lightweight CLI tool that manages project-specific shell environments. When you enter a directory, Dirvana automatically loads the configuration defined in .dirvana.yml, giving you instant access to project-specific commands, environment variables, and functions.

Dirvana solves a common problem: managing different shell environments for different projects. Instead of cluttering your .bashrc with project-specific aliases or manually sourcing environment files, Dirvana automatically loads the right configuration when you cd into a directory.

The magic: When you leave the directory, everything is automatically unloaded. No pollution of your global shell environment!

graph TD A[👤 User: cd ~/projects/myapp] --> B{🔍 Dirvana Hook} B --> C[📄 Read .dirvana.yml] C --> D{🔒 Authorized?} D -->|No| E[⚠️ Warning: Not authorized] D -->|Yes| F[🌳 Merge configs<br/>global → parent → current] F --> G[💾 Check cache] G -->|Hit| H[⚡ Load from cache] G -->|Miss| I[🔨 Generate shell code] I --> J[💾 Save to cache] H --> K[✅ Environment loaded] J --> K K --> L[✨ Aliases available<br/>🔧 Functions ready<br/>🌍 Env vars set] M[👤 User: cd ..] --> N{🧹 Dirvana Hook} N --> O[🗑️ Unload aliases] O --> P[🗑️ Unload functions] P --> Q[🗑️ Unset env vars] Q --> R[✅ Clean environment] style A fill:#e1f5ff style K fill:#c8e6c9 style L fill:#c8e6c9 style M fill:#fff3e0 style R fill:#c8e6c9 style E fill:#ffcdd2
Loading

Before Dirvana:

$ cd ~/projects/terraform $ export TF_LOG=debug $ alias tf="terraform" $ alias plan="terraform plan" $ alias apply="terraform apply" # ... and don't forget to unset everything when leaving!

With Dirvana:

# .dirvana.yml aliases: tf: command: task terraform -- # a specific wrapper via taskfile exist completion: terraform # Inherits terraform's auto-completion! plan: task terraform -- plan apply: task terraform -- apply functions: greet: | echo "Hello, $1!" env: GIT_REPOSITORY: sh: git remote get-url origin | sed 's/.*github.com:\(.*\)\.git/\1/' PROJECT_NAME: myproject
$ cd ~/projects/terraform # Everything loads automatically! $ tf <TAB> # Auto-completion works! ✨ apply console destroy init plan validate ... $ tf plan # Runs: task terraform -- plan $ tf apply # Runs: task terraform -- apply $ cd .. # Everything unloads automatically! 🧹 # Your shell is clean again
  • 🚀 Fast: <10ms overhead with intelligent caching
  • 🔒 Secure: Authorization system prevents untrusted configs + Explicit user consent for dynamic environment variables
  • 🌳 Hierarchical: Merge configurations from parent directories
  • 📝 Simple: YAML configuration with JSON Schema validation
  • 🐚 Compatible: Works with Bash and Zsh
  • 🔄 Auto-completion: Inherits completion from aliased commands (git, kubectl, etc.)
go install github.com/NikitaCOEUR/dirvana/cmd/dirvana@latest

Download the latest release for your platform:

Linux:

curl -L https://github.com/NikitaCOEUR/dirvana/releases/latest/download/dirvana-linux-amd64 -o /usr/local/bin/dirvana chmod +x /usr/local/bin/dirvana

macOS:

curl -L https://github.com/NikitaCOEUR/dirvana/releases/latest/download/dirvana-darwin-amd64 -o /usr/local/bin/dirvana chmod +x /usr/local/bin/dirvana

See all releases at GitHub Releases.

Install the shell hook (required for automatic loading):

This adds a hook to your ~/.bashrc or ~/.zshrc that automatically runs when you change directories.

Reload your shell:

source ~/.bashrc # or ~/.zshrc
  1. Initialize a project (creates .dirvana.yml with JSON Schema validation):
cd your-project dirvana init or dirvana edit
  1. Authorize the project:
  1. Reload your configuration:
eval "$(dirvana export)" # or cd .. && cd -

Your aliases, functions, and environment variables are now loaded!

Dirvana supports two types of configuration files:

  1. Global config: ~/.config/dirvana/global.yml - Applied to all projects
  2. Local configs: .dirvana.yml in project directories - Project-specific settings

Configuration files are merged in this order: global → root → parent → current directory (child configs override parent values).

All configuration files generated by dirvana init or dirvana edit automatically include JSON Schema validation for IDE support (auto-completion, validation, documentation).

# yaml-language-server: $schema=https://raw.githubusercontent.com/NikitaCOEUR/dirvana/main/schema/dirvana.schema.json # Simple aliases aliases: ll: ls -lah gs: git status build: go build -o bin/app ./cmd # Aliases with auto-completion support # The 'completion' field makes the alias inherit completion from the target command aliases: tf: terraform # Now 'tf <TAB>' works like 'terraform <TAB>'! k: command: kubecolor completion: kubectl # Kubernetes resource completion! With colors! g: git # Git branch/file completion! # Functions - reusable command sequences functions: mkcd: | mkdir -p "$1" && cd "$1" deploy: | echo "Deploying to $1..." task deploy -- "$1" # Environment variables env: # Static values PROJECT_NAME: myproject LOG_LEVEL: debug TF_LOG: info # Dynamic values from shell commands (like Taskfile) GIT_BRANCH: sh: git rev-parse --abbrev-ref HEAD PROJECT_ROOT: sh: pwd CURRENT_USER: sh: whoami # Prevent merging with parent configs (only use this directory's config) local_only: false # Ignore global config (start fresh from this directory) ignore_global: false

Dynamic Environment Variables

Dirvana supports dynamic environment variables that are evaluated at load time using shell commands (similar to Taskfile's sh syntax):

env: # Static value PROJECT_NAME: myproject # Dynamic value - executes shell command GIT_BRANCH: sh: git rev-parse --abbrev-ref HEAD CURRENT_USER: sh: whoami BUILD_TIME: sh: date +%s

The shell commands are executed when the configuration is loaded, and the output becomes the environment variable value.

Create a global config at ~/.config/dirvana/global.yml (or $XDG_CONFIG_HOME/dirvana/global.yml) to apply settings across all projects:

# Global aliases available everywhere aliases: ll: ls -lah g: git d: docker # Global environment variables env: EDITOR: vim PAGER: less # Global functions functions: mkcd: | mkdir -p "$1" && cd "$1"

Local configurations can:

  • Add to or override global settings
  • Ignore global config entirely with ignore_global: true
  • Use local_only: true to prevent merging with parent directories (but still merge with global)

See the examples/ directory for more configuration examples.

IDE Integration with JSON Schema

For auto-completion and validation in your editor, add the schema reference to your config files:

YAML:

# yaml-language-server: $schema=https://raw.githubusercontent.com/NikitaCOEUR/dirvana/main/schema/dirvana.schema.json aliases: ll: ls -lah

VS Code settings.json (workspace or user):

{ "yaml.schemas": { "https://raw.githubusercontent.com/NikitaCOEUR/dirvana/main/schema/dirvana.schema.json": [ ".dirvana.yml", ".dirvana.yaml" ] } }

Generate schema locally:

dirvana schema -o .vscode/dirvana.schema.json

This enables:

  • ✨ Auto-completion for configuration keys
  • 🔍 Inline documentation for all options
  • ⚠️ Real-time validation errors
  • 💡 IntelliSense suggestions

All command parameters can be set via environment variables with the DIRVANA_ prefix:

# Set log level (debug, info, warn, error) DIRVANA_LOG_LEVEL=debug cd ~/project # Set shell type for hook/setup commands DIRVANA_SHELL=zsh dirvana hook # Set previous directory (used internally by the hook) DIRVANA_PREV=/old/path dirvana export

Export shell code for the current folder. This is automatically called by the shell hook.

Flags:

  • --prev : Previous directory for context cleanup (also via DIRVANA_PREV)
  • --log-level : Log level - debug, info, warn, error (also via DIRVANA_LOG_LEVEL, default: warn)

Authorize a project for automatic execution. Without path, authorizes current directory.

dirvana allow dirvana allow /path/to/project

Revoke authorization for a project.

dirvana revoke dirvana revoke /path/to/project

List all authorized projects.

Show current Dirvana configuration status including:

  • Authorization status
  • Configuration hierarchy (from global to local)
  • Active aliases, functions, and environment variables
  • Cache status
  • Configuration flags

Create a sample configuration file in the current directory.

dirvana validate [config-file]

Validate a Dirvana configuration file using JSON Schema and custom validation rules. If no file is specified, looks for a config file in the current directory.

dirvana validate dirvana validate /path/to/.dirvana.yml

Validation checks:

  • JSON Schema validation (draft-07) for structure and types
  • YAML/TOML/JSON syntax errors
  • Name conflicts between aliases and functions
  • Empty values in aliases, functions, and shell commands
  • Invalid environment variable configurations
  • Validates alias/function/env var naming conventions

Open or create a Dirvana configuration file in your editor ($EDITOR or $VISUAL). If no config exists, creates a new .dirvana.yml with helpful comments and automatic JSON Schema validation support.

Note: Generated files automatically include the JSON Schema reference for IDE validation and auto-completion.

dirvana schema [output-file]

Display or export the JSON Schema (draft-07) for Dirvana configuration files. Useful for IDE integration and validation.

dirvana schema # Print to stdout dirvana schema -o schema.json # Save to file dirvana schema myschema.json # Alternative syntax

The schema can be used with:

  • VS Code: Add "$schema" field to your .dirvana.yml
  • IntelliJ/WebStorm: Automatic detection via JSON Schema Store
  • vim/neovim: Use with yaml-language-server

Example configuration with schema:

# yaml-language-server: $schema=https://raw.githubusercontent.com/NikitaCOEUR/dirvana/main/schema/dirvana.schema.json aliases: test: echo "test"

Print shell hook code for manual installation. The hook includes a safety check to ensure the dirvana command exists before executing, preventing "command not found" errors.

dirvana hook --shell bash dirvana hook --shell zsh

Flags:

  • --shell : Shell type - bash, zsh, or auto (also via DIRVANA_SHELL, default: auto)

Automatically install shell hook and completion to the appropriate configuration file. If the hook is already installed but outdated, it will be automatically updated.

dirvana setup --shell bash # Installs to ~/.bashrc dirvana setup --shell zsh # Installs to ~/.zshrc

The setup command uses markers (# Dirvana shell hook - START/END) to:

  • Detect if the hook is already installed
  • Compare the installed version with the current version
  • Automatically update the hook if it has changed
  • Preserve other content in your shell configuration file
  • Automatically install shell completion

Flags:

  • --shell : Shell type - bash, zsh, or auto (also via DIRVANA_SHELL, default: auto)

Show version information.

Dirvana supports auto-completion for bash and zsh.

Bash:

# One-time use (current shell only) source <(dirvana completion bash) # Permanent (add to ~/.bashrc) dirvana completion bash > ~/.bash_completion.d/dirvana # Or for system-wide sudo dirvana completion bash > /etc/bash_completion.d/dirvana

Zsh:

# One-time use (current shell only) source <(dirvana completion zsh) # Permanent (add to ~/.zshrc) dirvana completion zsh > "${fpath[1]}/_dirvana" # Then reload: compinit
  • Go 1.21 or later
  • Task (managed via aqua.yaml, or install via go install github.com/go-task/task/v3/cmd/task@latest)
  • Optional: aqua for dependency management
# Run unit tests task test # Run tests with coverage task test-coverage # Run tests with verbose output task test-verbose # Run integration tests (Docker required) task test-integration # Run specific shell integration test task test-integration-bash task test-integration-zsh task test-integration-fish # Run all tests (unit + integration) task test-all

Integration tests validate that Dirvana works correctly in real shell environments using Docker containers:

  • Bash - Tests aliases, functions, and environment variables in Bash
  • Zsh - Tests hooks and features in Zsh

Each test:

  1. Builds a Docker image with the specific shell
  2. Installs Dirvana and sets up hooks
  3. Creates a test configuration
  4. Validates that all features work correctly

Run task or task --list to see all available tasks.

dirvana/ ├── cmd/ │ └── dirvana/ # CLI entry point ├── internal/ │ ├── auth/ # Authorization system │ ├── cache/ # Cache management │ ├── cli/ # CLI commands implementation │ ├── completion/ # Auto-completion engines (Cobra, Flag, Env, Script) │ ├── config/ # Configuration loading & validation │ ├── context/ # Directory context management │ ├── logger/ # Logging │ ├── shell/ # Shell code generation │ └── timing/ # Performance timing ├── pkg/ │ └── version/ # Version information ├── hooks/ # Shell hook scripts ├── schema/ # JSON Schema for config validation ├── examples/ # Example configurations ├── tests/ # Integration and completion tests └── Taskfile.yml # Build and test automation

Cache is stored in $XDG_CACHE_HOME/dirvana/cache.json and includes:

  • Folder path
  • Config file hash
  • Generated shell code
  • Timestamp
  • Dirvana version
  • local_only flag

Cache is automatically invalidated when:

  • Configuration files change
  • Dirvana version changes

Authorized projects are stored in $XDG_DATA_HOME/dirvana/authorized.json.

Only authorized projects can execute automatically. This prevents malicious code execution from untrusted directories.

This project uses GoReleaser for automated releases with semantic versioning based on conventional commits.

All commits must follow the Conventional Commits specification:

  • feat: - New features (minor version bump)
  • fix: - Bug fixes (patch version bump)
  • perf: - Performance improvements (patch version bump)
  • refactor: - Code refactoring (patch version bump)
  • docs: - Documentation changes (no version bump)
  • test: - Test changes (no version bump)
  • chore: - Maintenance tasks (no version bump)
  • ci: - CI/CD changes (no version bump)

Breaking changes: Add BREAKING CHANGE: in the commit footer or ! after the type (e.g., feat!:) for major version bumps.

  1. Ensure all commits follow conventional commit format
  2. Create and push a new tag:
    git tag -a v1.0.0 -m "Release v1.0.0" git push origin v1.0.0
  3. GitHub Actions will automatically:
    • Run tests
    • Build binaries for multiple platforms
    • Create GitHub release with changelog

Each release includes:

  • Pre-built binaries for Linux, macOS, Windows (amd64, arm64)
  • Checksums and signatures

Contributions are welcome! Please ensure:

  • All commits follow Conventional Commits format
  • All tests pass: task test
  • Code is formatted: task fmt
  • Linter passes: task lint
  • Coverage remains at 90%+

MIT License - See LICENSE file for details

Nikita C (https://github.com/NikitaCOEUR)

Read Entire Article