The nervous system for your network — a unified, async-first Python SDK for network automation.
Project description
██████╗ ██╗ ███████╗██╗ ██╗ █████╗ ██████╗ ██╔══██╗██║ ██╔════╝╚██╗██╔╝██╔══██╗██╔══██╗ ██████╔╝██║ █████╗ ╚███╔╝ ███████║██████╔╝ ██╔═══╝ ██║ ██╔══╝ ██╔██╗ ██╔══██║██╔══██╗ ██║ ███████╗███████╗██╔╝ ██╗██║ ██║██║ ██║ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝
The nervous system for your network.
A unified, async-first Python SDK for network automation — transport, parsing, intent, telemetry, topology, and AI in one platform.
Why Plexar?
The Python network automation ecosystem is fragmented across a dozen libraries — each solving one layer well, none solving the whole problem.
| You need to... | Current reality |
|---|---|
| Connect to devices | Netmiko or Scrapli or Paramiko |
| Parse CLI output | TextFSM or TTP or Genie (Cisco-only) |
| Abstract vendors | NAPALM (limited drivers, no async) |
| Orchestrate at scale | Nornir + plugins |
| Detect config drift | Build it yourself |
| Push with rollback | Only if using NETCONF |
| Stream telemetry | pyGNMI (raw, unnormalized) |
| Model topology | Doesn't exist |
| Test network state | pyATS (Cisco-only) |
| Get AI-assisted RCA | Doesn't exist |
Plexar collapses all of this into a single, layered, async-native SDK.
Quickstart
pip install plexar
from plexar import Network
net = Network()
net.inventory.load("netbox", url="https://netbox.corp.com", token_env="NB_TOKEN")
# Connect to all leaf switches and get BGP state — concurrently
async with net.pool(max_concurrent=50) as pool:
results = await pool.map(lambda d: d.get_bgp_summary(), net.devices(role="leaf"))
for device, bgp in results:
for peer in bgp.peers:
if peer.state != "established":
print(f"⚠️ {device.hostname} → {peer.neighbor_ip} is {peer.state}")
Core Features
🔌 Async Transport Layer
Connect over SSH, NETCONF, RESTCONF, gNMI, or SNMP — async throughout, with automatic fallback, connection pooling, and per-device rate limiting.
device = Device(
hostname="spine-01",
platform="arista_eos",
transport=Transport.SSH, # or NETCONF, GNMI, RESTCONF
credentials=Credentials(password_env="DEVICE_PASS")
)
await device.connect()
🏭 Vendor-Neutral Data Models
Every get_* call returns a normalized Pydantic model — not raw text — regardless of vendor.
# Same API across Cisco, Arista, Juniper, Palo Alto
interfaces = await device.get_interfaces()
bgp = await device.get_bgp_summary()
routes = await device.get_routing_table()
# Fully typed, validated, serializable
print(bgp.peers[0].state) # "established"
print(interfaces[0].speed_mbps) # 10000
🎯 Intent Engine
Declare what you want. Plexar figures out how to get there, per vendor.
from plexar.intent import Intent
from plexar.intent.primitives import BGPIntent, InterfaceIntent
intent = Intent(devices=net.devices(role="leaf"))
intent.ensure(BGPIntent(asn=65001, neighbors=["10.0.0.1"], address_family="evpn"))
intent.ensure(InterfaceIntent(name="Ethernet1", mtu=9214, admin_state="up"))
plan = await intent.compile()
print(plan.diff()) # see exactly what will change, per device
result = await intent.apply()
report = await intent.verify()
print(report.compliant) # True
🔄 Transactional Config Push
Every push is a transaction. Automatic rollback on verification failure.
async with device.transaction() as txn:
await txn.push(new_config)
ok = await txn.verify([
("bgp_peers_up", lambda r: r.peers_established >= 4),
])
if not ok:
await txn.rollback() # guaranteed, across all transports
📡 Drift Detection
Continuously compare running state against desired state. Get alerted. Auto-remediate.
monitor = DriftMonitor(inventory=net.inventory, interval_seconds=300)
@monitor.on_drift
async def handle_drift(event):
await alert_slack(f"Drift on {event.device}: {event.summary}")
await event.remediate() # optional: auto-fix
await monitor.start()
🌐 Topology Engine
Understand your network as a graph. Discover via LLDP/CDP. Compute blast radius.
topo = TopologyEngine(net.inventory)
await topo.discover()
path = topo.shortest_path("leaf-01", "spine-02")
blast = topo.blast_radius("core-sw-01") # what breaks if this dies?
topo.export_d3("topology.html") # interactive browser visualization
🤖 AI Engine
Natural language RCA. Autonomous remediation. LLM-assisted parsing for unknown output.
ai = NetworkAI(net)
# Ask in plain English
rca = await ai.ask("Why is traffic slow between dc1 and dc2?")
print(rca.root_cause) # "BGP prefix limit reached on leaf-03"
print(rca.affected_devices) # ["leaf-03", "spine-01"]
# Parse unknown CLI output — no template required
raw = await device.run("show platform qos queue-stats")
parsed = await ai.parse(raw, hint="QoS queue statistics")
🧪 Network Testing Framework
pytest-native. Mock driver for CI/CD. No real devices needed in your pipeline.
@pytest.mark.asyncio
async def test_all_bgp_peers_established(net):
async for device in net.devices(role="leaf"):
bgp = await device.get_bgp_summary()
assert all(p.state == "established" for p in bgp.peers)
async def test_no_config_drift(net):
report = await net.drift_report()
assert report.is_clean, report.summary()
Architecture
┌─────────────────────────────────────────────────────┐
│ USER API │
├─────────────────────────────────────────────────────┤
│ AI ENGINE · INTENT ENGINE │
├─────────────────────────────────────────────────────┤
│ STATE MANAGER · TOPOLOGY ENGINE │
├─────────────────────────────────────────────────────┤
│ DEVICE ABSTRACTION LAYER │
├─────────────────────────────────────────────────────┤
│ SSH · NETCONF · RESTCONF · gNMI · SNMP │
├─────────────────────────────────────────────────────┤
│ Cisco · Juniper · Arista · Palo Alto · … │
└─────────────────────────────────────────────────────┘
Supported Platforms
| Vendor | SSH | NETCONF | RESTCONF | gNMI |
|---|---|---|---|---|
| Cisco IOS / IOS-XE | ✅ | ✅ | ✅ | ⚡ |
| Cisco NX-OS | ✅ | ✅ | ✅ | ⚡ |
| Cisco IOS-XR | ✅ | ✅ | ✅ | ✅ |
| Arista EOS | ✅ | ✅ | ✅ | ✅ |
| Juniper JunOS | ✅ | ✅ | ⚡ | ⚡ |
| Palo Alto PAN-OS | ✅ | ✅ | ✅ | — |
| Fortinet FortiOS | ✅ | ⚡ | ✅ | — |
| Nokia SR-OS | ⚡ | ✅ | ⚡ | ✅ |
✅ Stable · ⚡ In Progress · — Roadmap
Compared to the Ecosystem
| Capability | Netmiko | NAPALM | Nornir | pyATS | Plexar |
|---|---|---|---|---|---|
| Async-native | ❌ | ❌ | ❌ | ❌ | ✅ |
| Vendor-neutral models | ❌ | ⚠️ | ❌ | ⚠️ | ✅ |
| Intent engine | ❌ | ❌ | ❌ | ❌ | ✅ |
| Drift detection | ❌ | ❌ | ❌ | ❌ | ✅ |
| Transactional push | ❌ | ❌ | ❌ | ❌ | ✅ |
| Streaming telemetry | ❌ | ❌ | ❌ | ❌ | ✅ |
| Topology graph | ❌ | ❌ | ❌ | ❌ | ✅ |
| AI-assisted RCA | ❌ | ❌ | ❌ | ❌ | ✅ |
| Mock driver / CI-CD | ❌ | ❌ | ⚠️ | ✅ | ✅ |
| Multi-vendor testing | ❌ | ❌ | ❌ | ❌ | ✅ |
Installation
# Core
pip install plexar
# With AI engine
pip install plexar[ai]
# With gNMI telemetry
pip install plexar[gnmi]
# Everything
pip install plexar[all]
Requires Python 3.11+
Documentation
Full documentation, tutorials, and API reference at plexar.dev
Contributing
We welcome contributions — especially new vendor drivers.
git clone https://github.com/plexar/plexar
cd plexar
pip install -e ".[dev]"
pytest
See CONTRIBUTING.md and the Driver Authoring Guide.
Roadmap
- Core device model + async SSH
- Cisco IOS/NX-OS/XR drivers
- Arista EOS driver
- Juniper JunOS driver
- Intent engine v1
- Drift monitor
- Topology engine
- gNMI telemetry
- AI parser + RCA
- Digital twin / simulation
- Web UI (enterprise)
License
Apache 2.0 — see LICENSE
Built with obsession by the Plexar team and contributors.
plexar.dev · Discord · Twitter
The nervous system for your network.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file plexar-0.5.0.tar.gz.
File metadata
- Download URL: plexar-0.5.0.tar.gz
- Upload date:
- Size: 215.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d484760f31e38622f9b5605ef1bee0110c09ba86e3251d8de085d8441b9c14f
|
|
| MD5 |
130071e9ace9e76bb9450d803c2a73b4
|
|
| BLAKE2b-256 |
d4fe08619f3048bc9103870577217b3c766a79033577c4dfd2e5fbec3aca3f24
|
File details
Details for the file plexar-0.5.0-py3-none-any.whl.
File metadata
- Download URL: plexar-0.5.0-py3-none-any.whl
- Upload date:
- Size: 249.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8233c097078c942ad5cb344b9bc6e438bbb8ea8946185d639437dabd27287b68
|
|
| MD5 |
ef59a377ecbd7d94cd5ce060697d8ac4
|
|
| BLAKE2b-256 |
e477cd1b11e942652091fb70372539c9d93a88bc5f3a01b5f859075a861b947c
|