v0.5.0 — Release Overview

PLEXAR
NETWORK
AUTOMATION

The nervous system for your network. A unified, async-first Python SDK and CLI for multi-vendor network automation — with AI, security, topology, and intent-based management built in.

16,589Lines of Code
75Source Files
28Test Files
4Vendors
9Intent Types
5Build Phases
01 — Architecture

HOW IT'S BUILT

Plexar is a layered platform SDK. Each layer has a single responsibility and communicates with adjacent layers through clean interfaces. No layer reaches past its neighbor.

Layer 1 — User Interface
Python SDK (from plexar import Network)
CLI (plexar intent apply)
Layer 2 — Intelligence
AI Engine · Parser · RCA · Natural Language Query
Intent Engine · Primitives · Compiler · Plan/Apply/Verify
Layer 3 — State & Topology
State Manager · Snapshots · Drift Monitor
Topology Engine · LLDP/CDP · Graph · Blast Radius
Digital Twin · Change Simulation
Layer 4 — Device Abstraction
Config · Diff · Transaction · Validator
Security · Sanitizer · RBAC · Audit · Secrets · TLS
Parsers · Regex · TTP · TextFSM · JSON · XML
Connection Pool · Retry
Layer 5 — Vendor Drivers & Transport
Arista EOS
Cisco IOS/IOS-XE
Cisco NX-OS
Juniper JunOS
SSH / Scrapli
NETCONF / ncclient
gNMI / grpc
SNMP (reserved)

Directory Structure

plexar/ ├── plexar/ ← Python package │ ├── core/ ← Network, Device, Inventory, Pool, Credentials │ ├── vendors/ ← Vendor driver implementations │ │ ├── arista/ eos.py │ │ ├── cisco/ ios.py nxos.py │ │ └── juniper/ junos.py │ ├── drivers/ ← BaseDriver ABC + DriverRegistry + MockDriver │ ├── models/ ← Pydantic data models (BGP, Interface, Route, Platform) │ ├── intent/ ← Intent engine: primitives, compiler, engine, verifier │ ├── config/ ← Config diff, transaction, validators │ ├── state/ ← Snapshots, drift monitor │ ├── topology/ ← NetworkX graph, LLDP/CDP discovery │ ├── security/ ← Sanitizer, audit, RBAC, secrets, TLS │ ├── ai/ ← AIParser, RCAEngine, NetworkQuery │ ├── twin/ ← DigitalTwin simulator │ ├── telemetry/ ← Event bus, gNMI streaming │ ├── parsers/ ← Regex, TTP, TextFSM, JSON, XML │ ├── plugins/ ← Plugin SDK + PluginRegistry │ ├── reporting/ ← HTML/JSON/text report engine │ ├── integrations/ ← NetBox, Nautobot, OpenTelemetry │ ├── discovery/ ← Reserved: SNMP sweep (puresnmp) │ ├── cli/ ← Click CLI — plexar command │ └── utils/ ← Retry, helpers ├── tests/ ← 28 test files ├── .github/workflows/ ← CI/CD + network pipeline ├── pyproject.toml ← Dependencies, extras, entry points └── inventory.example.yaml

Key Design Decisions

Async-first, always

Every driver, every operation, every I/O call is async/await. Running 100 devices concurrently is as natural as running 1.

🔌

Driver abstraction

All vendors implement BaseDriver. Application code never references a specific vendor — only device.get_bgp_summary().

🔐

Security is automatic

Sanitization, auditing, and RBAC run in the execution path, not as opt-in decorators. You cannot accidentally bypass them.

🧩

Platform-ready seams

OperationRunner, StateStore, AuditSink, EventBus are all ABCs. The tool uses local defaults. The future platform swaps them without touching application code.

📦

Optional extras

Core installs in seconds. AI, gNMI, topology, vault — each is a separate pip install plexar[extra]. Use only what you need.

🔌

Plugin ecosystem

Third parties publish plugins as ordinary Python packages with entry points. Install the package; Plexar auto-discovers it.

02 — How It Works

INSIDE PLEXAR

A request's journey — device.get_bgp_summary()

Tracing a single call from user code to device and back:

user: await device.get_bgp_summary()
RBAC check
Sanitize hostname
DriverRegistry.get(platform)
SSH connect (if not open)
run "show bgp summary | json"
parse JSON → BGPSummary
Audit log: COMMAND_EXECUTE
return BGPSummary
# What the user writes
async with device:
    bgp = await device.get_bgp_summary()
    print(bgp.peers_established)

# What happens internally — all automatic:
# 1. RBAC: is current context role >= VIEWER?
# 2. Sanitize: is device.hostname safe?
# 3. DriverRegistry: platform="arista_eos" → AristaEOSDriver
# 4. Scrapli: SSH to management_ip:22
# 5. Run: "show bgp summary | json"
# 6. Parse: JSON → BGPSummary(Pydantic model)
# 7. Audit: {event: COMMAND_EXECUTE, hostname: ..., success: true}
# 8. Return typed BGPSummary object

The Intent Engine

Intent-based networking separates what you want from how to configure it. You write vendor-neutral primitives. Plexar compiles them to each vendor's CLI.

BGPIntent(asn=65001)
IntentCompiler
per-vendor config text
device.transaction()
push → verify
commit or rollback
# Arista EOS output:
router bgp 65001
  neighbor 10.0.0.1 remote-as 65000
  neighbor 10.0.0.1 description spine-01

# Cisco IOS output (same primitive):
router bgp 65001
 neighbor 10.0.0.1 remote-as 65000
 neighbor 10.0.0.1 description spine-01

# Juniper JunOS output (same primitive):
set protocols bgp group UNDERLAY neighbor 10.0.0.1 peer-as 65000
set protocols bgp group UNDERLAY description spine-01

The Security Layer

Every operation passes through five security controls automatically:

ControlWhat it doesWhere it runs
SanitizerBlocks command injection, prompt injection, SSTI, path traversal, output overflowBefore every device call and AI call
RBACChecks caller role against required permission levelEntry point of every operation
SecretsFetches credentials from Vault/keyring/env — never from plaintextAt connection time
TLS/SSH PolicyEnforces cipher suites and host key verificationAt transport setup
Audit LoggerAppends every event to immutable JSONL + optional SIEM sinkAfter every operation completes

The AI Engine

Three AI-powered features, each solving a different problem:

AI Parser

LLM parses raw CLI output into typed Pydantic models when the built-in regex/TextFSM parser fails. LRU cached — same output never hits the API twice.

RCA Engine

Root cause analysis. Given a network event, gathers live device context, topology, and drift data, then produces a structured diagnosis with remediation steps.

NL Query

Natural language questions about the fleet. "Which leafs have BGP peers down?" → plan → concurrent device queries → LLM synthesizes an answer.

The Digital Twin

Capture a live snapshot of your network's state, then simulate failures before touching production:

await twin.capture(network=net)

result = twin.simulate_interface_failure("leaf-01", "Ethernet1")
# → risk_score: 72/100
# → affected_devices: ["leaf-01", "server-rack-3"]
# → warnings: ["leaf-01 has no redundant uplink on this segment"]

result = twin.validate_intent(intent)
# → passed: True  (safe to apply)
# OR
# → conflicts: ["BGP ASN 65001 already configured on spine-01"]

The Plugin System

Third parties extend Plexar by declaring an entry point. No code changes to Plexar required:

# In third-party pyproject.toml:
[project.entry-points."plexar.plugins"]
aruba_cx = "plexar_aruba.plugin:ArubaOSCXPlugin"

# After pip install plexar-aruba:
# DriverRegistry automatically has "aruba_cx" → ArubaOSCXDriver
# inventory.yaml platform: aruba_cx  just works
03 — Deployment

HOW TO DEPLOY

Plexar v1 is a tool — it runs wherever Python runs. There is no server to operate, no database to manage, no daemon to keep alive. Pick the scenario that matches your environment.

Prerequisites

RequirementMinimumRecommended
Python3.103.11 or 3.12
OSLinux, macOS, Windows (WSL2)Ubuntu 22.04 LTS
RAM256 MB1 GB (4 GB if using local AI)
Disk100 MB5 GB (if using local AI model)
NetworkSSH access to devicesDedicated management network
Python accesspipuv (10× faster installs)

Scenario A — Developer Laptop

The fastest path. Run Plexar from your laptop against a lab or staging network.

1

Install Python 3.11+

# macOS
brew install python@3.11

# Ubuntu / Debian
sudo apt update && sudo apt install python3.11 python3.11-venv python3-pip

# Verify
python3 --version
2

Create a virtual environment and install Plexar

# Create and activate
python3.11 -m venv ~/.venvs/plexar
source ~/.venvs/plexar/bin/activate    # Linux/macOS
# ~/.venvs/plexar/Scripts/activate    # Windows WSL2

# Install core + CLI + topology
pip install "plexar[cli,topology]"

# Install everything
pip install "plexar[all]"

# Verify
plexar --version
3

Create your inventory file

# inventory.yaml
devices:
  - hostname: spine-01
    management_ip: 192.168.1.1
    platform: arista_eos
    credentials:
      username: admin
      password_env: NET_PASSWORD
    metadata:
      role: spine
      site: dc1

  - hostname: leaf-01
    management_ip: 192.168.1.10
    platform: arista_eos
    credentials:
      username: admin
      password_env: NET_PASSWORD
    metadata:
      role: leaf
      site: dc1
4

Set credentials and run

export NET_PASSWORD="your-device-password"

plexar --inventory inventory.yaml devices list
plexar --inventory inventory.yaml bgp show spine-01
plexar --inventory inventory.yaml bgp fleet

Scenario B — Shared Jump Host (Team Use)

Install Plexar on a shared Linux server that has SSH access to all devices. Multiple engineers use it. Recommended for teams of 2–20.

1

Provision a jump host

A small VM is fine. 2 vCPU, 2 GB RAM, Ubuntu 22.04. It must have SSH access to your device management network.

# On the jump host
sudo apt update
sudo apt install python3.11 python3.11-venv python3-pip git -y

# Create a dedicated service user
sudo useradd -m -s /bin/bash plexar
sudo su - plexar
2

Install Plexar system-wide for the plexar user

python3.11 -m venv ~/venv
source ~/venv/bin/activate
pip install "plexar[all]"

# Create config directory
mkdir -p ~/.plexar/state ~/.plexar/snapshots
mkdir -p ~/network/intent
3

Set up secrets securely

# Option A: Environment file (simple)
cat > ~/.plexar/.env << 'EOF'
NET_PASSWORD=your-device-password
NET_SSH_KEY_PATH=/home/plexar/.ssh/network_key
OPENAI_API_KEY=sk-...  # optional
EOF
chmod 600 ~/.plexar/.env

# Add to ~/.bashrc
echo 'set -a; source ~/.plexar/.env; set +a' >> ~/.bashrc
source ~/.bashrc

# Option B: OS keyring (more secure)
pip install "plexar[keyring]"
python3 -c "
from plexar.security.secrets import SecretsManager, KeyringBackend
import asyncio
secrets = SecretsManager(backend=KeyringBackend())
asyncio.run(secrets.set('net_password', 'your-device-password'))
"
4

Put inventory and intent files under git

cd ~/network
git init
git remote add origin https://github.com/yourorg/network-config

# Recommended structure
mkdir -p intent snapshots reports

# .gitignore
cat > .gitignore << 'EOF'
snapshots/
reports/
*.env
*.key
EOF
5

Create a systemd service for the drift monitor (optional)

# /etc/systemd/system/plexar-drift.service
[Unit]
Description=Plexar Drift Monitor
After=network.target

[Service]
Type=simple
User=plexar
WorkingDirectory=/home/plexar/network
EnvironmentFile=/home/plexar/.plexar/.env
ExecStart=/home/plexar/venv/bin/python3 -c "
import asyncio
from plexar import Network
from plexar.state.drift import DriftMonitor

async def main():
    net = Network()
    net.inventory.load('yaml', path='inventory.yaml')
    monitor = DriftMonitor(interval=300)
    await monitor.start(devices=net.inventory.all())

asyncio.run(main())
"
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable plexar-drift
sudo systemctl start plexar-drift
sudo systemctl status plexar-drift
6

Give team members SSH access

# Each engineer SSHes to the jump host and uses plexar
ssh engineer@jump-host.corp.com

# They activate the shared venv
source /home/plexar/venv/bin/activate

# And run commands against the shared inventory
plexar --inventory ~/network/inventory.yaml bgp fleet

Scenario C — CI/CD Pipeline (Automated)

Run Plexar as part of a GitOps workflow. Engineers commit intent YAML files; the pipeline applies them.

1

Copy the GitHub Actions workflow

mkdir -p .github/workflows
cp plexar/.github/workflows/network-ci.yml .github/workflows/
2

Add GitHub Secrets

In your repository: Settings → Secrets → Actions

SecretValue
PLEXAR_SSH_KEYContents of your SSH private key
SLACK_WEBHOOKSlack webhook URL (optional)
OPENAI_API_KEYFor AI features (optional)
3

Create the production environment gate

Settings → Environments → New: production. Add required reviewers. Production deploys will wait for approval before executing.

4

Push a change and watch it run

git checkout -b change/update-leaf-bgp
vim intent/leaf-bgp.yaml

git add intent/leaf-bgp.yaml
git commit -m "feat: add leaf-03 BGP neighbors"
git push origin change/update-leaf-bgp
# Open a PR → CI runs validate + plan + simulate + posts PR comment
# Merge to main → approval gate → apply + verify + compliance report

Scenario D — Air-Gapped / No Internet

For environments with no outbound internet access.

1

Pre-download on a connected machine

# On a connected machine, download everything
pip download "plexar[all]" -d ./plexar-packages/

# Bundle the wheel files
tar czf plexar-packages.tar.gz plexar-packages/

# Transfer to air-gapped machine
scp plexar-packages.tar.gz user@airgapped-host:
2

Install from local packages on the air-gapped machine

tar xzf plexar-packages.tar.gz
python3.11 -m venv ~/venv
source ~/venv/bin/activate
pip install --no-index --find-links ./plexar-packages "plexar[all]"

plexar --version  # works with zero internet
3

Set up local AI (no OpenAI required)

# Download Ollama on connected machine, transfer binary
# Download model weights on connected machine:
ollama pull qwen2.5-coder:7b
# Copy ~/.ollama/models/ to air-gapped machine

# Configure Plexar to use local AI
export PLEXAR_AI_BACKEND=local
export PLEXAR_AI_MODEL=qwen2.5-coder:7b

# AI features now work with zero outbound traffic
plexar ask "which leafs have BGP peers down?"

Install Options Summary

CommandInstallsUse case
pip install plexarCore SDK + CLIBasic use, scripts
pip install plexar[cli]+ Click, RichTerminal use
pip install plexar[ai]+ litellm, openaiAI features (API-backed)
pip install plexar[topology]+ networkxTopology analysis
pip install plexar[gnmi]+ grpcio, pygnmiStreaming telemetry
pip install plexar[netconf]+ ncclientNETCONF transport
pip install plexar[netbox]+ pynetboxNetBox inventory
pip install plexar[nautobot]+ requestsNautobot inventory
pip install plexar[vault]+ hvacHashiCorp Vault secrets
pip install plexar[telemetry]+ opentelemetryOTLP metrics export
pip install plexar[discovery]+ puresnmpSNMP sweep (coming soon)
pip install plexar[all]EverythingFull installation
04 — Usage

USING PLEXAR

The Inventory File

Everything starts with inventory.yaml. This tells Plexar about your devices.

devices:
  - hostname: spine-01
    management_ip: 192.168.1.1
    platform: arista_eos            # arista_eos | cisco_ios | cisco_nxos | juniper_junos
    transport: ssh                  # ssh | netconf | gnmi
    port: 22
    credentials:
      username: admin
      password_env: NET_PASSWORD    # env var name — never the actual password
      # OR: ssh_key_env: SSH_KEY_ENV
      # OR: ssh_key: /path/to/key
    metadata:
      role: spine
      site: dc1
      rack: A1
      tags: [production, bgp-core]

CLI Quick Reference

# ── Devices ──────────────────────────────────────────
plexar devices list                          # all devices
plexar devices list --role leaf --site dc1   # filtered
plexar devices connect spine-01              # test SSH
plexar devices show spine-01                 # platform + BGP + interfaces

# ── BGP ──────────────────────────────────────────────
plexar bgp show spine-01                     # single device
plexar bgp fleet                             # all devices
plexar bgp fleet --role leaf                 # filtered

# ── Interfaces ───────────────────────────────────────
plexar interfaces show leaf-01
plexar interfaces show leaf-01 --down-only

# ── Intent ───────────────────────────────────────────
plexar intent plan   ./intent/bgp.yaml       # preview, no changes
plexar intent apply  ./intent/bgp.yaml       # apply (prompts)
plexar intent apply  ./intent/bgp.yaml --yes # apply (no prompt)
plexar intent verify ./intent/bgp.yaml       # verify running state

# ── Topology ─────────────────────────────────────────
plexar topology discover                     # LLDP walk
plexar topology path leaf-01 firewall-01     # shortest path
plexar topology blast spine-01               # blast radius

# ── Snapshots ────────────────────────────────────────
plexar snapshot capture                      # save all device state
plexar snapshot capture --role spine         # filtered

# ── Config ───────────────────────────────────────────
plexar config push spine-01 ./configs/spine-01.txt

# ── AI ───────────────────────────────────────────────
plexar ask "which leafs have BGP peers down?"
plexar ask "what is the total prefix count across all spines?"
plexar rca leaf-01                           # root cause analysis

# ── Output formats ───────────────────────────────────
plexar --output json bgp fleet               # JSON output
plexar --output yaml devices list            # YAML output
plexar --no-color bgp fleet                  # no ANSI color

Python SDK Quick Reference

import asyncio
from plexar import Network

async def main():
    net = Network()
    net.inventory.load("yaml", path="inventory.yaml")

    # ── Single device ─────────────────────────────────
    device = net.inventory.get("spine-01")
    async with device:
        bgp        = await device.get_bgp_summary()
        interfaces = await device.get_interfaces()
        info       = await device.get_platform_info()
        routes     = await device.get_routing_table()

    # ── Fleet concurrently ────────────────────────────
    leafs = net.devices(role="leaf")
    async with net.pool(max_connections=20) as pool:
        results = await pool.gather(lambda d: d.get_bgp_summary())

    # ── Intent ────────────────────────────────────────
    from plexar.intent import Intent, BGPIntent, BGPNeighbor
    intent = Intent(devices=leafs)
    intent.ensure(BGPIntent(asn=65001, neighbors=[
        BGPNeighbor(ip="10.0.0.1", remote_as=65000)
    ]))
    plan   = await intent.plan()     # preview
    result = await intent.apply()    # apply
    report = await intent.verify()   # verify

    # ── Digital Twin ──────────────────────────────────
    from plexar.twin import DigitalTwin
    twin = DigitalTwin()
    await twin.capture(network=net)
    result = twin.simulate_device_failure("spine-01")
    print(f"Risk: {result.risk_score}/100")

    # ── AI Query ──────────────────────────────────────
    from plexar.ai import NetworkQuery
    nq = NetworkQuery(network=net)
    r  = await nq.ask("which leafs have BGP peers down?")
    print(r.answer)

asyncio.run(main())

Intent YAML Format

# intent/leaf-baseline.yaml
devices:
  role: leaf        # target devices by role
  site: dc1         # and/or site

ensure:
  - type: bgp
    asn: 65001
    neighbors:
      - ip: 10.0.0.1
        remote_as: 65000
        description: spine-01

  - type: ntp
    servers: [10.0.0.100, 10.0.0.101]

  - type: banner
    motd: "AUTHORIZED ACCESS ONLY"

  - type: interface
    name: Ethernet1
    description: uplink-to-spine-01
    admin_state: up
    mtu: 9214
💡
Supported intent types bgp · interface · vlan · route · ospf · prefix-list · ntp · snmp · banner

Supported Platform Strings

platform: valueVendorProtocolOutput
arista_eosArista EOSSSH/ScrapliJSON (| json)
cisco_iosCisco IOS / IOS-XESSH/ScrapliRegex/TextFSM
cisco_nxosCisco NX-OSSSH/NX-APIJSON (| json)
juniper_junosJuniper JunOSSSH/ScrapliXML (display xml)
05 — Configuration

ENVIRONMENT VARIABLES

VariableDefaultDescription
PLEXAR_INVENTORYinventory.yamlDefault inventory path for CLI
PLEXAR_AI_MODELgpt-4o-miniAI model for parser/RCA/query
PLEXAR_AI_BACKENDautoauto | local | openai | anthropic
OPENAI_API_KEYRequired for OpenAI-backed AI features
ANTHROPIC_API_KEYAlternative to OpenAI
VAULT_ADDRHashiCorp Vault server URL
VAULT_TOKENVault authentication token
NETBOX_TOKENNetBox API token
NAUTOBOT_TOKENNautobot API token
PLEXAR_LOG_LEVELINFODEBUG | INFO | WARNING | ERROR
PLEXAR_PLATFORM_URLPlatform server URL (v2, reserved)
PLEXAR_PLATFORM_TOKENPlatform auth token (v2, reserved)
⚠️
Never hardcode credentials Always use password_env: VAR_NAME in inventory.yaml — never password: literal_value. The sanitizer redacts credentials in logs, but they should never be in files committed to version control.
06 — Roadmap

V2 PLATFORM

Plexar v1 is the tool. v2 adds the platform — an always-on server that wraps the same SDK. The tool works standalone forever; the platform adds persistence, HA, multi-user, and a web UI.

Architecture

User interfaces
plexar CLI (laptop)
Web UI (React)
CI/CD API calls
↓ REST + WebSocket
Platform API Server (FastAPI)
Job Queue (Redis + arq)
Leader Election (singleton tasks)
Plexar Workers (plexar-core SDK)
PostgreSQL (state)
Redis (queue/cache)
S3 (snapshots/reports)

What the Platform Adds

Always-on monitoring

Drift detection, telemetry, gNMI subscriptions run continuously — not just when you run a command.

Multi-user RBAC

Login via SSO/OIDC. Full per-user audit trail. Four-eyes approval for high-risk operations.

HA & job persistence

Operations survive server restarts. Mid-flight intent applies resume from checkpoint. Active-passive failover.

Web dashboard

Fleet health at a glance. Operation history. Compliance scores. Audit log search.

Multi-tenancy

Teams are isolated at the data layer. Team A cannot see Team B's devices, operations, or audit logs.

Webhook receivers

Real-time inventory sync from NetBox/Nautobot change events — no polling required.

Migration is Just a Config Change

When you deploy the platform, upgrading the tool to use it requires changing three lines in ~/.plexar/config.yaml:

# Before: tool runs standalone
tool:
  inventory: ./inventory.yaml

# After: tool routes through platform
tool:
  inventory: ./inventory.yaml
platform:
  url: https://plexar.corp.com
  token_env: PLEXAR_PLATFORM_TOKEN

All CLI commands, all Python SDK calls, all intent YAML files remain unchanged. The execution moves to the platform. The interface stays the same.

Package Split

PackageInstallContains
plexar-corepip install plexar-coreSDK, drivers, security — no CLI
plexarpip install plexarplexar-core + CLI (today's package)
plexar-platformpip install plexar-platformAPI server, workers, web UI
ℹ️
All three share the same plexar namespace from plexar import Network works whether you have plexar or plexar-core installed. The tool and platform always ship the same version number. plexar-core 0.6.0 + plexar 0.6.0 + plexar-platform 0.6.0.
07 — Troubleshooting

COMMON ISSUES

ErrorCauseFix
ModuleNotFoundError: clickCLI extra not installedpip install plexar[cli]
ConnectionError: Authentication failedWrong credentialsCheck password_env var is exported
DriverNotFound: unknown platform 'X'Platform string typo or missing pluginCheck spelling: arista_eos, cisco_ios, cisco_nxos, juniper_junos
ValueError: Input failed sanitizationHostname/command has shell metacharactersRemove semicolons, pipes, backticks from input
PermissionError: Role VIEWER cannot push_configRBAC context too lowSet PLEXAR_ROLE=ENGINEER in environment
AIParser: No API key configuredMissing LLM credentialsSet OPENAI_API_KEY or use --backend local
NetworkX not foundTopology extra missingpip install plexar[topology]
Timeout on large fleetDefault pool too smallIncrease: net.pool(max_connections=50)

Debug Mode

# Enable debug logging
export PLEXAR_LOG_LEVEL=DEBUG
plexar bgp show spine-01

# Or in Python
import logging
logging.basicConfig(level=logging.DEBUG)

Test Connectivity Without Running Plexar

# Test SSH manually
ssh -v admin@192.168.1.1

# Test from Python
python3 -c "
import asyncio, asyncssh
async def test():
    async with asyncssh.connect('192.168.1.1', username='admin',
                                 password='yourpassword',
                                 known_hosts=None) as conn:
        result = await conn.run('show version')
        print(result.stdout[:200])
asyncio.run(test())
"

⚡ PLEXAR v0.5.0
The nervous system for your network.
Apache 2.0 · Python 3.10+ · 16,589 lines · 75 source files