Extending The Device Types Library
cani loads device types from three sources, in priority order:
- Built-in — embedded types shipped with the binary.
- Local directories — YAML files on disk (
types_dirs). - Remote git repos — cloned repositories (
types_repos).
Types registered first win. If a slug already exists from a higher-priority source, the duplicate is skipped.
Configuration
All type sources are configured in ~/.cani/cani.yml:
# Local directories containing device type YAML files.
# Each directory should have subdirectories like device-types/, rack-types/, etc.
types_dirs: []
# Git repositories to clone for additional device types.
# The default is the netbox-community device-type library.
types_repos:
- https://github.com/netbox-community/devicetype-library.git
# Whether to git pull on each run (false = clone once, never update).
types_repo_pull: false
Adding A Local Directory
Create a directory with the standard layout and add it to types_dirs:
my-types/
├── device-types/
│ └── my-custom-blade.yaml
├── rack-types/
│ └── my-custom-rack.yaml
├── module-types/
│ └── my-custom-gpu.yaml
└── cable-types/
└── my-custom-cable.yaml
types_dirs:
- /home/user/my-types
Types from local directories take priority over remote repos, so you can override community types with local definitions.
Adding A Git Repository
Add a repository URL to types_repos:
types_repos:
- https://github.com/netbox-community/devicetype-library.git
- https://github.com/my-org/custom-device-types.git
Repos are cloned into ~/.cani/types/<sanitized-repo-name>/ on first use. Set types_repo_pull: true to pull updates on each run.
Listing Loaded Types
After configuring sources, use the -L flag to verify which types are available:
# List all loaded device types
cani alpha add device -L
# List all loaded rack types
cani alpha add rack -L
# List all loaded module types
cani alpha add module -L
# List all loaded cable types
cani alpha add cable -L
The output includes slugs from all sources (built-in, local, and remote):
rack (2):
NAME SLUG PART NUMBER SOURCE
----------------------------------- --------------------------------------------- ---------------- ----------
HPE 42U 800mmx1200mm G2 Enterprise… hpe-42u-800mmx1200mm-g2-enterprise-shock-rack P9K46A builtin
HPE 48U 800mmx1200mm G2 Enterprise… hpe-48u-800mmx1200mm-g2-enterprise-shock-rack P9K58A builtin
Cabinet (7):
NAME SLUG PART NUMBER SOURCE
----------------------------------- --------------------------------------------- ---------------- ----------
EX2000 hpe-eia-cabinet builtin
EX2000 hpe-ex2000 builtin
EX2500 1 Liquid Cooled Chassis hpe-ex2500-1-liquid-cooled-chassis builtin
EX2500 2 Liquid Cooled Chassis hpe-ex2500-2-liquid-cooled-chassis builtin
EX2500 3 Liquid Cooled Chassis hpe-ex2500-3-liquid-cooled-chassis builtin
EX3000 hpe-ex3000 builtin
EX4000 hpe-ex4000 builtin
Use a slug from this list with any add command:
cani alpha add rack hpe-48u-800mmx1200mm-g2-enterprise-shock-rack --auto --accept
Priority Order Example
If the slug my-blade exists in both a local directory and a git repo:
- Built-in types load first — no match.
- Local
types_dirsloadsmy-blade— registered. - Git
types_reposfindsmy-blade— skipped (already registered).
This lets you fork and customize community types without modifying the upstream repository.
Subdirectory Layout
Each source directory is scanned for these subdirectories:
| Subdirectory | Type Loaded |
|---|---|
device-types/ |
CaniDeviceType |
module-types/ |
CaniModuleType |
cable-types/ |
CaniCableType |
rack-types/ |
CaniRackType |
inventory-types/ |
CaniFruType |
Any .yaml or .yml file in these subdirectories is parsed and registered by slug.
Slugs For Nautobot-Format Libraries
Nautobot-format libraries (for example ones converted from the netbox-community library) may omit slug because Nautobot generates it on import. When a device or module type has no slug, cani derives one from manufacturer and model using the same rule as the Nautobot importer: lowercase "<manufacturer> <model>" and replace each run of non-word characters with -.
| manufacturer | model | derived slug |
|---|---|---|
HPE |
Aruba 10000-48Y6C Back-to-Front |
hpe-aruba-10000-48y6c-back-to-front |
Juniper |
EX4100-24T |
juniper-ex4100-24t |
An explicit slug always takes precedence. A file with no slug and without both manufacturer and model is skipped with a warning.
Module types may also name their ports with Nautobot's {module} placeholder, for example HSN {module}/0. When the module is installed in a module bay, cani replaces {module} with the bay's position from the parent device type (or the bay name when it has no position), as Nautobot does. A NIC in bay PCIe1 with position 1 gets port HSN 1/0; moving it to another bay with cani alpha update module --bay renames its ports.
Resolved inventory interface specs retain the original token-bearing names and
labels in optional nameTemplate and labelTemplate JSON fields
(name_template and label_template in YAML). These portable internal fields
survive save/load cycles, including for customized port layouts; only the
resolved names and labels are exported. Explicit interface-label edits replace
the label template too, so a later module move does not undo the edit or restore
a label that was cleared.
Moving a module also updates matching cable endpoint port names and the interface index while preserving interface UUIDs and endpoint ownership. Contradictory or unresolved cable references are not guessed or repaired.
Older inventories without template fields can recover them from a matching
library layout. A customized port whose template was already lost remains a
literal name rather than guessing which characters were once a placeholder.
To restore rebaying for such a port, supply its original template, for example
"nameTemplate": "custom-{module}/0", in the inventory interface spec.