This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
hier_config is a Python library that compares network device configurations (running vs intended) and generates minimal remediation commands. It parses config text into hierarchical trees and computes diffs respecting vendor-specific syntax rules.
All commands use poetry (not pip):
# Full lint + test suite (what CI runs)
poetry run ./scripts/build.py lint-and-test
# Lint only (ruff, mypy, pyright, pylint, yamllint, flynt — run in parallel)
poetry run ./scripts/build.py lint
# Tests only (95% coverage required)
poetry run ./scripts/build.py pytest --coverage
# Run a single test
poetry run pytest tests/test_driver_cisco_xr.py::test_multiple_groups_no_duplicate_child_error -v
# Run a single test file
poetry run pytest tests/test_driver_cisco_xr.py -v
# Auto-fix formatting
poetry run ruff format hier_config tests scriptsPerformance benchmarks are in tests/test_benchmarks.py and are skipped by default via the benchmark pytest marker. They generate ~10,000-line configs and measure parsing, remediation, and iteration performance.
# Run all benchmarks with timing output
poetry run pytest -m benchmark -v -s
# Run a specific benchmark
poetry run pytest -m benchmark -k test_parse_large_ios_config -v -sUse -s to see printed timing results. Each benchmark reports the best time over 3 iterations and asserts an upper bound (e.g., < 5s for parsing, < 10s for remediation). If a benchmark fails its time threshold, investigate the relevant code path for performance regressions.
After running benchmarks, always display the results to the user in a table format summarizing each benchmark's config size and elapsed time.
Three-layer design: Tree (parse/represent config), Driver (platform-specific rules), Workflow (compute diffs/remediations).
HConfig(root.py) — root node, owns the driver reference. Key methods:config_to_get_to(),future(),difference(),dump_simple().HConfigChild(child.py) — tree node withtext,parent,children,tags,comments. Providesis_lineage_match()for rule evaluation andnegate()for negation logic.HConfigBase(base.py) — abstract base shared by both. Providesadd_child(),get_children_deep(),_config_to_get_to()(left pass = negate missing, right pass = add new).HConfigChildren(children.py) — ordered collection with O(1) dict lookup by text.
Each platform driver subclasses HConfigDriverBase (driver_base.py) and overrides _instantiate_rules() to return HConfigDriverRules — a Pydantic model holding lists of typed rule objects:
- Rule models are frozen Pydantic BaseModels defined in
models.py. Each usesmatch_rules: tuple[MatchRule, ...]for lineage-based matching. - MatchRule supports:
equals,startswith,endswith,contains,re_search. Multiple fields = AND logic. is_lineage_match()onHConfigChildcompares the full ancestry path against a tuple of MatchRules.
Key rule types: SectionalExitingRule, IdempotentCommandsRule, PerLineSubRule, NegationDefaultWithRule, OrderingRule, ParentAllowsDuplicateChildRule, IndentAdjustRule.
Platform drivers: CISCO_IOS, CISCO_XR, CISCO_NXOS, ARISTA_EOS, FORTINET_FORTIOS, HP_PROCURVE, HP_COMWARE5, JUNIPER_JUNOS, VYOS, GENERIC.
WorkflowRemediation(workflows.py) — primary API:remediation_configandrollback_configproperties.- Constructor functions in
constructors.py:get_hconfig(),get_hconfig_fast_load(),get_hconfig_driver().
Pattern: add frozen Pydantic model in models.py → add default factory + field in HConfigDriverRules (driver_base.py) → consume in child.py or root.py → populate in platform driver's _instantiate_rules().
This project follows Test-Driven Development (TDD):
- Write a failing test first that validates the expected behavior.
- Run the test to confirm it fails for the right reason.
- Implement the minimal code to make the test pass.
- Run the full test suite to ensure no regressions.
- Refactor if needed, keeping tests green.
All new features and bug fixes must have corresponding tests. Write tests before or alongside implementation, not after.
When creating a PR, always update CHANGELOG.md with a summary of the changes under the ## [Unreleased] section. Use the Keep a Changelog format with categories: Added, Changed, Fixed, Removed. Reference the GitHub issue number when applicable (e.g., (#209)). When a version is released, move unreleased entries under a new version heading with the release date.
- Strict type checking: pyright strict mode + mypy strict + pylint with pydantic plugin.
- Ruff handles formatting (line length 88) and most lint rules.
- Docstrings use raw strings (
r"""...""") when containing backslashes. - Test coverage minimum: 95%.
- Python 3.10+ required.