- Bump all 18 plugins from 0.110.0 to 0.111.0
- Update rust-toolchain.toml channel to 1.93.1 (nu 0.111.0 requires ≥1.91.1)
Fixes:
- interprocess pin =2.2.x → ^2.3.1 in nu_plugin_mcp, nu_plugin_nats, nu_plugin_typedialog
(required by nu-plugin-core 0.111.0)
- nu_plugin_typedialog: BackendType::Web initializer — add open_browser: false field
- nu_plugin_auth: implement missing user_info_to_value helper referenced in tests
Scripts:
- update_all_plugins.nu: fix [package].version update on minor bumps; add [dev-dependencies]
pass; add nu-plugin-test-support to managed crates
- download_nushell.nu: rustup override unset before rm -rf on nushell dir replace;
fix unclosed ) in string interpolation
nu_plugin_nickel
Nushell plugin for seamless Nickel configuration language integration. Load, evaluate, format, and validate Nickel files directly from Nushell scripts.
Quick Start
# Build and register the plugin
just build-plugin nu_plugin_nickel
just register-plugin nu_plugin_nickel
# Verify installation
plugin list | where name == "nickel-export"
Overview
5 commands for working with Nickel files:
| Command | Purpose |
|---|---|
nickel-export |
Export Nickel to JSON/YAML (with smart type conversion) |
nickel-eval |
Evaluate with automatic caching (for config loading) |
nickel-format |
Format Nickel files (in-place) |
nickel-validate |
Validate all Nickel files in a directory |
nickel-cache-status |
Show cache statistics |
Core Concept: Smart Type Conversion
The plugin converts output intelligently based on whether you specify a format:
nickel-export config.ncl → Nushell object (parsed JSON)
nickel-export config.ncl -f json → Raw JSON string
nickel-export config.ncl -f yaml → Raw YAML string
Why? Default behavior gives you structured data for programming. Explicit -f gives you raw output for external tools.
Complete Usage Guide
1. Load Configuration as Object (Most Common)
Without -f flag → Returns Nushell object
# Load configuration into a variable
let config = nickel-export workspace/config.ncl
# Access nested values with cell paths
$config.database.host # "localhost"
$config.database.port # 5432
$config.database.username # "admin"
# Work with arrays
$config.servers | length # 3
$config.servers | map {|s| $s.name}
# Filter and transform
$config.services
| where enabled == true
| each {|svc| {name: $svc.name, port: $svc.port}}
2. Get Raw Output (For External Tools)
With -f flag → Returns raw string
# Export as raw JSON string
let json = nickel-export config.ncl -f json
$json | save output.json
# Export as raw YAML string
nickel-export config.ncl -f yaml | save config.yaml
# Pipe to external tools
nickel-export config.ncl -f json | jq '.database'
nickel-export config.ncl -f json | curl -X POST -d @- http://api.example.com
3. Primary Config Loader with Caching
nickel-eval is optimized for configuration loading
# Load with automatic caching (80-90% hit rate)
let cfg = nickel-eval workspace/provisioning.ncl
# Works just like nickel-export (same smart conversion)
$cfg.infrastructure.cloud_provider # "aws"
$cfg.infrastructure.region # "us-east-1"
# Caching is transparent
nickel-eval config.ncl # First call: 100-200ms
nickel-eval config.ncl # Subsequent calls: 1-5ms
4. Format Nickel Files
# Format a single file (modifies in place)
nickel-format config.ncl
# Format multiple files
glob "**/*.ncl" | each {|f| nickel-format $f}
5. Validate Nickel Project
# Validate all .ncl files in directory
nickel-validate ./workspace/config
# Validate current directory
nickel-validate
# Output:
# ✅ workspace/config/main.ncl
# ✅ workspace/config/lib.ncl
# ✅ workspace/config/vars.ncl
6. Check Cache Status
nickel-cache-status
# Output:
# ╭──────────────────────────────────────────────────╮
# │ cache_dir: ~/.cache/provisioning/config-cache/ │
# │ entries: 42 │
# │ enabled: true │
# ╰──────────────────────────────────────────────────╯
Real-World Examples
Example 1: Multi-Environment Configuration
# Load environment-specific config
let env = "production"
let config = nickel-eval "config/provisioning-($env).ncl"
# Use in deployment
def deploy [service: string] {
let svc_config = $config.services | where name == $service | first
print $"Deploying ($service) to ($svc_config.region)"
print $" Image: ($svc_config.docker.image)"
print $" Replicas: ($svc_config.replicas)"
print $" Port: ($svc_config.port)"
}
deploy "api-server"
Example 2: Generate Kubernetes Manifests
# Load infrastructure config
let infra = nickel-eval "infrastructure.ncl"
# Generate K8s manifests
$infra.services | each {|svc|
{
apiVersion: "apps/v1"
kind: "Deployment"
metadata: {name: $svc.name}
spec: {
replicas: $svc.replicas
template: {
spec: {
containers: [{
name: $svc.name
image: $svc.docker.image
ports: [{containerPort: $svc.port}]
}]
}
}
}
}
}
| each {|manifest|
$manifest | to json | save "k8s/($manifest.metadata.name).yaml"
}
Example 3: Configuration Validation Script
def validate-config [config-path: path] {
# Validate syntax
nickel-validate $config-path | print
# Load and check required fields
let config = nickel-eval $config-path
let required = ["database", "services", "infrastructure"]
$required | each {|field|
if ($config | has $field) {
print $"✅ ($field): present"
} else {
print $"❌ ($field): MISSING"
}
}
# Check configuration consistency
let db_replicas = $config.database.replicas
let svc_replicas = ($config.services | map {|s| $s.replicas} | math sum)
if $db_replicas >= $svc_replicas {
print "✅ Database replicas sufficient"
} else {
print "❌ WARNING: Services exceed database capacity"
}
}
validate-config "workspace/config.ncl"
Example 4: Generate Configuration from Template
# Load base config template
let template = nickel-eval "templates/base.ncl"
# Customize for specific environment
let prod_config = {
environment: "production"
debug: false
replicas: ($template.replicas * 3)
services: ($template.services | map {|s|
$s | merge {
replicas: 5
resources: {
memory: "2Gi"
cpu: "1000m"
}
}
})
}
# Export as JSON
$prod_config | to json | save "production-config.json"
Example 5: Merge Multiple Configurations
# Load base config
let base = nickel-eval "config/base.ncl"
# Load environment-specific overrides
let env_overrides = nickel-eval "config/($env).ncl"
# Load local customizations
let local = nickel-eval "config/local.ncl"
# Merge with precedence: local > env > base
let final_config = $base
| merge $env_overrides
| merge $local
print $"Final configuration:"
print $final_config
Command Reference
nickel-export
nickel-export <FILE> [-f FORMAT] [-o OUTPUT]
Arguments:
FILE- Path to Nickel file (required)
Flags:
-f, --format- Output format:json(default),yaml(optional)-o, --output- Save to file instead of returning value (optional)
Return Type:
- Without
-f: Nushell object (Record/List) - With
-f json: Raw JSON string - With
-f yaml: Raw YAML string
Examples:
nickel-export config.ncl # → object
nickel-export config.ncl -f json # → JSON string
nickel-export config.ncl -f yaml -o out.yaml
nickel-eval
nickel-eval <FILE> [-f FORMAT] [--cache]
Arguments:
FILE- Path to Nickel file (required)
Flags:
-f, --format- Output format:json(default),yaml(optional)--cache- Use caching (enabled by default, flag for future use)
Return Type:
- Without
-f: Nushell object (with caching) - With
-f json: Raw JSON string (with caching) - With
-f yaml: Raw YAML string (with caching)
Examples:
nickel-eval workspace/config.ncl # → cached object
nickel-eval config.ncl -f json # → cached JSON string
let cfg = nickel-eval config.ncl
$cfg.database.host
nickel-format
nickel-format <FILE>
Arguments:
FILE- Path to Nickel file to format (required)
Examples:
nickel-format config.ncl
glob "**/*.ncl" | each {|f| nickel-format $f}
nickel-validate
nickel-validate [DIR]
Arguments:
DIR- Directory to validate (optional, defaults to current directory)
Examples:
nickel-validate ./workspace/config
nickel-validate
nickel-cache-status
nickel-cache-status
Returns record with cache information:
cache_dir- Cache directory pathentries- Number of cached entriesenabled- Whether caching is enabled
Examples:
nickel-cache-status
let cache = nickel-cache-status
print $"Cache has ($cache.entries) entries at ($cache.cache_dir)"
Type Conversion Details
Without -f Flag (Object Mode)
The plugin converts Nickel output to Nushell types:
JSON Input → Nushell Type
─────────────────────────────────────
{"key": "value"} → {key: "value"}
[1, 2, 3] → [1, 2, 3]
"string" → "string"
123 → 123
true → true
null → null
Enables full Nushell data access:
let config = nickel-export config.ncl
# Cell path access
$config.database.host
# Filtering
$config.services | where enabled == true
# Transformation
$config.services | map {|s| {name: $s.name, port: $s.port}}
# Custom functions
def get-service [name: string] {
$config.services | where name == $name | first
}
With -f Flag (Raw Mode)
Returns unprocessed string:
nickel-export config.ncl -f json
# Returns: "{\"database\":{\"host\":\"localhost\", ...}}"
nickel-export config.ncl -f yaml
# Returns: "database:\n host: localhost\n ..."
Use for:
- Saving to files with specific format
- Piping to external JSON/YAML tools
- API calls requiring raw format
- Integration with non-Nushell tools
Caching
Automatic Caching with nickel-eval
Results are cached using content-addressed storage:
Cache location: ~/.cache/provisioning/config-cache/
Cache key: SHA256(file_content + format)
First call: ~100-200ms
Cached calls: ~1-5ms
Characteristics:
- Non-blocking (errors are silently ignored)
- Transparent (no configuration needed)
- Hit rate: ~80-90% in typical workflows
- Per-format caching (json and yaml cached separately)
Manual cache inspection:
let status = nickel-cache-status
print $"Cache entries: ($status.entries)"
print $"Cache location: ($status.cache_dir)"
# List cache files
ls ($status.cache_dir)
Troubleshooting
Plugin Not Found
Error: Unknown command 'nickel-export'
Solution:
# Register the plugin
just register-plugin nu_plugin_nickel
# Verify registration
plugin list | grep nickel
Nickel Binary Not Found
Error: Nickel execution failed: No such file or directory
Solution:
Ensure nickel CLI is installed and in PATH:
# Check if nickel is available
which nickel
# Install nickel (macOS)
brew install nickel-lang/nickel/nickel
# Or build from source
cargo install nickel
File Not Found
Error: Nickel file not found: config.ncl
Solution: Use absolute path or verify file exists:
# Use absolute path
nickel-export /absolute/path/to/config.ncl
# Verify file exists
ls config.ncl
Cache Issues
# Clear cache if needed
rm -rf ~/.cache/provisioning/config-cache/*
# Check cache status
nickel-cache-status
JSON Parsing Error
If -f json returns parsing error, the Nickel file may not export valid JSON:
# Test with raw Nickel output
nickel-export config.ncl -f json | print
Architecture
Design Pattern: CLI Wrapper
The plugin uses an elegant CLI wrapper pattern:
Nushell Script
↓
nickel-export/eval command
↓
Command::new("nickel")
↓
Nickel official CLI
↓
Module resolution (guaranteed correct)
↓
JSON/YAML output
↓
Smart type conversion
↓
Nushell object or raw string
Benefits:
- ✅ Module resolution guaranteed correct (official CLI)
- ✅ Works with all Nickel versions automatically
- ✅ All Nickel CLI features automatically supported
- ✅ Zero maintenance burden
Trade-offs:
- ⚠️ Requires
nickelbinary in PATH - ⚠️ ~100-200ms per evaluation (mitigated by caching)
Type Conversion Flow
nickel export /file.ncl --format json
↓
Captures stdout (JSON string)
↓
serde_json::from_str (parse)
↓
json_value_to_nu_value (convert recursively)
├── Object → Record
├── Array → List
├── String → String
├── Number → Int or Float
├── Boolean → Bool
└── Null → Nothing
↓
Returns nu_protocol::Value
↓
Nushell receives properly typed data
Integration Examples
With Provisioning System
# Load provisioning config
let prov = nickel-eval "workspace/provisioning.ncl"
# Deploy infrastructure
def deploy [] {
for region in $prov.regions {
print $"Deploying to ($region.name)..."
# Your deployment logic
}
}
# Validate configuration before deploy
def validate [] {
nickel-validate "workspace/provisioning.ncl"
}
In Nushell Configuration
# env.nu or config.nu
# Load environment from Nickel
let env-config = nickel-eval "~/.config/nushell/environment.ncl"
# Set environment variables
$env.MY_VAR = $env-config.my_var
$env.DATABASE_URL = $env-config.database.url
In CI/CD Pipelines
# GitHub Actions / GitLab CI script
# Load config
let config = nickel-eval ".provisioning/ci-config.ncl"
# Check if tests should run
if $config.run_tests {
print "Running tests..."
}
# Set deployment target
export DEPLOY_TARGET = $config.deployment.target
Performance Tips
-
Use
nickel-evalfor repeated access# ❌ Bad: 3 separate evaluations print ($config.database | nickel-eval) print ($config.services | nickel-eval) # ✅ Good: Single evaluation, cached let cfg = nickel-eval config.ncl print $cfg.database print $cfg.services -
Avoid format conversion loops
# ❌ Bad: Converts each time (1..100) | each {|i| nickel-export config.ncl | ...} # ✅ Good: Convert once let cfg = nickel-eval config.ncl (1..100) | each {|i| ... $cfg ...} -
Use raw output for large datasets
# ❌ Bad: Large object in memory let big = nickel-export huge-config.ncl # ✅ Good: Stream raw JSON nickel-export huge-config.ncl -f json | jq '.items[]'
Requirements
- Nushell: 0.110.0 or later
- Nickel CLI: Latest version (install via
breworcargo) - Rust: For building the plugin (if not using pre-built binary)
Building from Source
cd nu_plugin_nickel
cargo build --release
Binary will be at: target/release/nu_plugin_nickel
Testing
# Run unit tests
cargo test
# Verify compilation
cargo check
# Run clippy linting
cargo clippy -- -D warnings
License
MIT