This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
NetDriver is a network device automation framework built on AsyncSSH that provides HTTP RESTful APIs for CLI command execution on network devices. It's organized as a monorepo with a Polylith architecture, consisting of:
- netdriver-agent: FastAPI-based REST API service for device connectivity testing and command execution
- netdriver-simunet: SSH server simulation for testing network device terminals
The project uses a Polylith-inspired structure with bases/ (applications) and components/ (shared libraries):
bases/netdriver/
├── agent/ # REST API application
└── simunet/ # Simulation network application
components/netdriver/
├── client/ # SSH client with async session management
├── exception/ # Centralized error handling and error codes
├── log/ # Logging utilities (Loguru-based)
├── plugin/ # Plugin system core and engine
├── plugins/ # Device-specific plugins (Cisco, Huawei, Juniper, etc.)
├── server/ # SSH server for simulated devices
├── textfsm/ # Enhanced TextFSM for output parsing
└── utils/ # Utility functions
The SessionPool (in components/netdriver/client/pool.py) is a singleton that:
- Maintains persistent SSH sessions with devices (identified by
protocol:username@ip:port) - Automatically monitors session health and removes closed/expired/idle sessions
- Implements a command queue per session to prevent concurrent configuration conflicts
- Uses asyncio locks to ensure thread-safe session operations
The plugin engine (components/netdriver/plugin/engine.py) dynamically loads device plugins at startup:
- Plugins are organized by vendor directory under
components/netdriver/plugins/ - Each plugin inherits from
Base(incomponents/netdriver/plugins/base.py) and implements device-specific behavior - Plugins define mode patterns (LOGIN, ENABLE, CONFIG), error patterns, and command handling
- Plugin resolution:
vendor/model/version→vendor/model/base→vendor/base/base
Sessions track device state including:
- Mode: LOGIN, ENABLE, or CONFIG (defined in
client/mode.py) - Vsys: Virtual system context (for multi-context devices like firewalls)
- Mode switching is handled automatically by the base plugin via
switch_mode()
# Install dependencies
uv sync# Start agent service (REST API on http://localhost:8000)
uv run agent
# Start simulation network service (SSH servers on configured ports)
uv run simunet# Run all tests
uv run pytest
# Run unit tests only
uv run pytest -m unit
# Run integration tests only
uv run pytest -m integration
# Run specific test file
uv run pytest tests/bases/netdriver/agent/test_cisco_nexus.pyConfiguration files in config/:
config/agent/agent.yml- Agent service settings (logging, session timeouts, SSH parameters, profiles)- Logs are written to
logs/netdriver_agent.log
- Logs are written to
config/simunet/simunet.yml- Simulated device definitions and logging settings- Logs are written to
logs/netdriver_simunet.log
- Logs are written to
- Create vendor directory under
components/netdriver/plugins/if it doesn't exist - Create plugin file named
{vendor}_{model}.py(e.g.,cisco_nexus.py) - Inherit from vendor base class or
Baseplugin - Define
PluginInfowith vendor, model, version, and description - Implement required abstract methods:
get_mode_prompt_patterns()- Regex patterns for each mode's promptget_more_pattern()- Pattern for pagination promptsget_union_pattern()- Combined pattern for all promptsget_error_patterns()- Patterns that indicate command errorsget_ignore_error_patterns()- Error patterns to ignore
Example:
from netdriver_agent.plugin.plugin_info import PluginInfo
from netdriver_agent.plugins.cisco import CiscoBase
class CiscoNexus(CiscoBase):
info = PluginInfo(
vendor="cisco",
model="nexus",
version="base",
description="Cisco Nexus Plugin"
)Integration tests are in tests/bases/netdriver/agent/ and typically:
- Start the simunet service with test fixtures in
conftest.py - Use httpx client to make API calls to the agent
- Verify command execution and error handling
All custom exceptions are in components/netdriver/exception/errors.py and inherit from BaseError:
- Include HTTP status code and error code
- For command execution errors, include output
- Examples:
LoginFailed,PluginNotFound,ExecCmdTimeout,EnableFailed
The agent uses dependency-injector (see bases/netdriver/agent/containers.py) to wire:
- Configuration providers
- Request handlers
- The container is wired to API modules in
main.py
Uses Loguru configured via netdriver_core.log.logman:
- Correlation ID middleware tracks requests (agent only)
- Log levels configurable in respective config files
- Log files are separated by service:
- Agent:
logs/agent.log(excludesnetdriver_simunet.servermodules in test environment) - Simunet:
logs/simunet.log(onlynetdriver_simunet.servermodules)
- Agent:
- Intercepts uvicorn logs for unified output
- Log rotation: 1 day, retention: 60 days
- Module filtering: Uses
logger.patch()innetdriver_simunet.server.deviceto ensure correct module identification - In test environment: Both handlers are configured to prevent log duplication
- Python 3.12+ required
- Uses uv for dependency management
- All SSH operations are async (AsyncSSH-based)
- Session keys format:
{protocol}:{username}@{ip}:{port} - The agent runs with auto-reload enabled by default (suitable for development)
- Simulated devices use the plugin system to emulate vendor-specific behavior
- Configuration profiles support device-specific settings by vendor/model/version or IP address