nickel
Nickel configuration language with gradual typing, contracts, and dynamic sufficiency verification. Use for type-safe configs, transformation contracts, and validation pipelines.
When & Why to Use This Skill
This Claude skill integrates the Nickel configuration language, a powerful tool designed for creating type-safe, modular, and programmatically verifiable configurations. By combining gradual typing with functional contracts and dynamic sufficiency verification, it enables developers to build complex configuration pipelines that are both flexible and robust, preventing common runtime errors in infrastructure and application settings.
Use Cases
- Type-Safe Configuration Design: Define complex settings using gradual typing to ensure structural correctness and catch errors before deployment.
- Automated Validation Pipelines: Implement functional contracts to enforce business logic and technical constraints across configuration files.
- Safe Configuration Refactoring: Utilize transformation contracts and dynamic sufficiency checks to refactor large-scale configurations without breaking downstream dependencies.
- Multi-Format Exporting: Manage a single source of truth in Nickel and export validated, error-free configurations to JSON or YAML for various environments.
| name | nickel |
|---|---|
| description | Nickel configuration language with gradual typing, contracts, and dynamic sufficiency verification. Use for type-safe configs, transformation contracts, and validation pipelines. |
| version | 1.0.0 |
Nickel Configuration Language
Gradual typing + contracts for configuration that composes correctly.
Dynamic Sufficiency
A Nickel config is dynamically sufficient when:
- Structural: Contract coverage is complete (all fields typed)
- Computational: Same outputs for all valid inputs
- Semantic: Olog types preserved through transformations
# Sufficiency levels (from dynamic_sufficiency.jl)
let SufficiencyLevel = [|
'NOT_SUFFICIENT, # Different behavior
'WEAKLY_SUFFICIENT, # Same structure, different labels
'COMPUTATIONALLY_SUFFICIENT, # Same outputs
'SEMANTICALLY_SUFFICIENT # Same olog meaning
|]
Core Contracts
Import from workspace:
let contracts = import ".topos/nickel/contracts/transformation-contracts.ncl"
Available contracts:
TransformationPattern- rename/refactor operationsTransformationStrategy- checkpoint + rollback + validationBalancedTernarySelector- GF(3) strategy selection (seed 1069)ValidationResult- gate pass/fail with exit codes
Gradual Typing Pattern
# Untyped (dynamic) - simple configs
{ name = "example", count = 42 }
# Typed block - contract enforcement
let typed_config : { name: String, count: Number } =
{ name = "example", count = 42 }
# Contract annotation - runtime validation
let validated = config | TransformationStrategy
Idempotent Contracts
# Good: applying twice yields same result
let Positive = std.contract.from_predicate (fun x => x > 0)
5 | Positive | Positive # ✓ idempotent
# Key property for dynamic sufficiency:
# ∀c: Contract, ∀x: (x | c) | c ≡ x | c
Workspace Integration
| Path | Purpose |
|---|---|
.topos/nickel/contracts/ |
Reusable contract library |
.topos/nickel/examples/ |
Transformation examples |
environment-specs/environments.ncl |
Flox env specs |
seth-rs/nickel/ |
Pipeline + telemetry modules |
CLI Usage
# Evaluate config
nickel eval config.ncl
# Type-check without eval
nickel typecheck config.ncl
# Export to JSON
nickel export config.ncl --format json
# REPL
nickel repl
GF(3) Integration
Trit: 0 (ERGODIC - synthesis/validation)
Home: Prof
Poly Op: ⊗
Color: #FFFF00
Triadic pairing:
dune-analytics(+1) - expanding/queryingnickel(0) - contract validationsicp(-1) - foundational evaluation
Dynamic Sufficiency Verification
# Verify sufficiency between two configs
let verify_sufficiency = fun cfg1 cfg2 =>
let fields1 = std.record.fields cfg1 in
let fields2 = std.record.fields cfg2 in
if std.array.all (fun f => std.array.elem f fields2) fields1
then 'COMPUTATIONALLY_SUFFICIENT
else 'NOT_SUFFICIENT