Network design repository
The network design as text in a repository, reviewed like code, compared with what the devices really say, and tested: intents the design must keep, what-if failures, and a merge gate.
Search for a command to run…
The network design as text in a repository, reviewed like code, compared with what the devices really say, and tested: intents the design must keep, what-if failures, and a merge gate.
A network design repository is the network's source of truth, what it is supposed to be: its sites, the devices in them, their ports, the links between them, the circuits a provider sells you and the ducts those circuits run through. It is plain text (.zevtopo files), versioned like code: every change is a commit with an author and a reason, reviewed in a pull request before it's accepted.
Zaryn adds what a drawing or a spreadsheet can't: the design is checked against reality. Linked to a site, it is compared with what the site's devices report about themselves (their neighbors, addresses and ports), so the documentation can't quietly drift away from the network.
Every network has a design somewhere: a Visio file, a wiki page, a spreadsheet of cables. Within months it is wrong. A device was added in a hurry, a link moved to another port, a "temporary" connection became permanent. Nobody notices until an outage, when the diagram everyone trusts sends the engineer to the wrong rack.
The other half of the problem is hidden risk. Two links can look redundant on a diagram and still fail together because they share a fiber duct, a conduit under one bridge, or one provider's backbone. A diagram doesn't know that; a design that names it can.
Zaryn treats the three views of a network as one loop:
| What it is | Where | |
|---|---|---|
| Design | what the network should be | this repository |
| Reality | what the devices say it is | Sites |
| Prediction | what a change would do | the digital twin |
You don't have to write a design from nothing. If the network is already a site on Zaryn, import it:
zev clone <you>/network-design && cd network-designzev topo import <owner>/<site>zev add topology && zev commit -m "Design from the live network" && zev pushzev topo import writes topology/<site>.zevtopo with every device of the site (name, vendor, model, management address) and every link the devices see (with the ports on both ends). On the site's Map tab, Download the site as .zevtopo gives the same file.
Then make it a design: give devices their roles, name the circuits, mark what links share.
.zevtopo is TOML-like: blocks that start with [[kind]], then key = value lines. # starts a comment.
[[site]]name = "thr-dc1"address = "Frankfurt, data center 1"lat = 35.70lon = 51.40[[device]]name = "core1"vendor = "cisco"role = "core"site = "thr-dc1"model = "C9500-48Y4C"mgmt = "10.0.0.1"owner = "sara"[[interface]]device = "core1"name = "Te1/0/1"lag = "Po1"ip = "10.1.12.1/30"description = "to core2"[[link]]a = "core1"b = "core2"a_if = "Te1/0/1"b_if = "Te1/0/1"kind = "fiber"capacity = 10weight = 10provider = "TIC"circuit = "TIC-4411"srlg = ["duct-north", "valiasr-bridge"][[vlan]]id = 10name = "users"subnet = "10.10.0.0/24"[[static_route]]device = "core1"network = "0.0.0.0/0"next_hop = "10.255.0.1"| Block | Keys |
|---|---|
[[site]] | name, address, lat, lon |
[[device]] | name, vendor, role (core, distribution, access, edge…), site, model, mgmt (the management address), owner, lat, lon, mtbf and mttr (hours, see Availability) |
[[interface]] | device, name, ip, description, lag (the port channel it belongs to), vlan |
[[link]] | a, b, a_if, b_if (the ports), kind (fiber, copper, wireless, vpn, virtual), capacity, weight, provider, circuit, srlg (shared risk groups: a list), mtbf, mttr |
[[srlg]] | name, mtbf, mttr: a shared risk group's own failures (a duct cut, a building losing power) |
[[vlan]] | id, name, subnet, description |
[[static_route]] | device, network, next_hop, distance |
Every key except a device's name and a link's a and b is optional. Files written before these keys existed read exactly as before.
Every .zevtopo file at the root of the repository or anywhere under topology/ is part of the design, read in name order as one. Split it the way your team works: one file per site (topology/thr-dc1.zevtopo, topology/mhd-pop.zevtopo), or one for devices and one for circuits. A link may join devices from two files.
The repository's Design editor tab shows the design twice, side by side: the .zevtopo files in a code editor and the network drawn on a canvas. Both are the same design, live:
On the canvas:
| Do | How |
|---|---|
| Add a device | + Device, or n |
| Link two devices | select one, then shift-click the other; or l, then click the other end |
| Edit details | the inspector under the canvas: vendor, role, site, model, management address for a device; ports, weight, capacity, kind, provider, circuit and shared risk groups for a link |
| Rename a device | its name in the inspector; every link, interface and static route naming it is renamed with it, in every file |
| Remove | Delete; a device goes with the links, interfaces and static routes that name it |
| Arrange | drag devices (only the picture moves; positions aren't saved in the design) |
Single points of failure and critical links are worked out again on every change, so a link you add shows at once whether it removed one. Under the editor, mistakes are listed with their line: a line that isn't key = value, a text value without its closing quote, a device declared twice, a link to a device with no [[device]] block, a weight that isn't a number. Click one to jump to it.
Saving. Save (or Ctrl S) commits the changed files from the browser, signed with your browser key like any web commit. The default is to propose it as a pull request: a new branch, then the pull request page, where the network checks and intents run before anything reaches the branch. Commit straight to the branch is there for repositories that don't need review. If someone saved to the branch after you opened it, nothing is overwritten: your work stays as a draft, you reload and restore it. Unsaved work is kept as a draft in this browser, and offered back when you open the editor again.
+ above the editor adds a file under topology/ (see One design, many files); new devices and links go to the file that's open.
.zevtopo linesThe repository's Network overview draws the design four ways:
Click a device to see its model, site, management address, ports and the circuits on its links.
On a site, Collector and settings → Design repository links the design (you need to be an admin of the site and of the repository). From then on Zaryn compares them, both on the repository's Network overview (Design and reality) and on the site's Map tab:
Devices are matched by name (ignoring case and domain: CORE1.lab is core1) or by management address; links by the two devices, then by ports. Reality comes from what the devices said last (CDP, LLDP, MikroTik neighbors, OSPF and BGP peers, shared subnets), so a link both sides keep quiet about can't be seen.
Seeing a comparison needs both: reading the repository and seeing the site. A teammate who only sees the site sees that a design is linked, not what's in it.
A diagram can look redundant and not be. An intent is a promise about the design written as one line of text, like "HQ stays connected to the data center if any single duct is cut". Zaryn checks every intent on the design, shows the failures that break it, and refuses to merge a pull request that breaks one that held.
Intents live in .zevintent files next to the design: at the root of the repository or under topology/, read in name order as one.
# topology/wan.zevintentlinks = survive site:hq site:dc linkducts = survive site:hq site:dc srlghq-to-dc = max-hops hq1 dc2 3no-spof| Line | Holds when |
|---|---|
reach A B | A and B are connected |
survive A B [link|srlg|device|any] | A and B are still connected after any single failure of that kind (any by default) |
max-hops A B N | the shortest path between them is at most N links |
no-spof | no single device failing splits the network |
no-bridge | no single link failing splits the network |
no-shared-risk | no single shared risk group (a duct, a building, a provider) failing splits the network |
availability A B P | A reaches B at least P percent of the time (Premium, below) |
capacity A B N [link|srlg|device|any|none] | A can send B at least N, also after any single failure of that kind (Premium) |
disjoint A B [link|device] | there are two paths that share no link, or no device in between (Premium) |
A and B are a device name, or site:NAME for any device of that site. A name before = is optional; without one the line is its own name. # starts a comment.
Not "failed", but the failure that does it:
ducts: 1 single failure(s) cut site:hq off from site:dc shared risk group duct-north (2 links) → site:hq and site:dc are cut apartTwo circuits that look redundant, both labeled with the same srlg, are one cut away from both going down. A link failure alone would not have shown it, which is why survive … srlg exists. In the API every sentence also comes as a template with {0}, {1}… and its values (parts on a result, effect_t and effect_a on a failure), so a client can say it in another language; this page does so in Persian.
Two circuits, two ports, two providers' labels. The drawing says redundant.
On the repository's Topology analysis page, the Intents tab (key 4) lists every intent and has a What if these fail? box: pick shared risk groups, links and devices, and the graph shows what is left. It lists the pieces the network falls into, the devices cut off, and the intents that stop holding. Each failure under a failing intent has a try it button. The same answers are at GET /v1/repos/<owner>/<repo>/topology-failure?down=srlg:duct-north,device:core2,link:hq1~hq2 (a link by its two ends, or by its number from the response).
Every pull request that changes the design is checked against the intents:
The pull request also draws the change: under Network topology impact, the design before and after as one graph, with devices and links that were added in green, removed in dashed red, and changed in amber. Click one to see what changed (for example circuit: TCI-4411 → TCI-9000, or role: distribution → core).
survive, no-spof, no-bridge, no-shared-risk and capacity try one failure at a time; availability tries one and two. The playground takes any combination, and shows whether capacity (with what is still up) and disjoint still hold.srlg names is invisible to the check, so list the circuits of one duct with the same group."Redundant" says two paths exist. It doesn't say how often the service is down, whether the backup can carry the traffic, or which two paths to build. Three Premium intents answer those, on the same design, in the same pull request check:
# topology/campus.zevintentup = availability edge dc 99.95uplinks = capacity edge dc 10000 linktwo-ways = disjoint edge dc deviceavailability A B 99.95 holds when A reaches B at least 99.95% of the time. Each device and link has a mean time between failures and a mean time to repair in hours (mtbf, mttr), so it is down mttr / (mtbf + mttr) of the time. A shared risk group with its own [[srlg]] block fails on its own too, taking all its links at once:
Between 99.9% and 99.99% is the difference between a working day lost and a lunch break. Availability is the share of the time A can reach B.
[[device]]name = "core1"mtbf = 200000 # about 23 yearsmttr = 4 # spare on site[[link]]a = "edge"b = "core1"srlg = ["riser"]mtbf = 50000mttr = 8[[srlg]]name = "riser"mtbf = 50000 # a riser cut every ~6 yearsmttr = 48 # two days to re-pull fiberZaryn finds every single failure and every pair of failures that cuts A from B, adds up how often each happens, and reports the availability, the expected minutes down a year, and the cuts that cost the most, with try it for each. A device or link without figures gets 150,000 h / 4 h (device) or 50,000 h / 8 h (link), and the result says how many used them.
How it's worked out: failures are independent and cuts are added up (the rare-event approximation). Three failures at once are left out; overlapping cuts are counted twice, so the figure errs on the low side. On designs too big to try every pair, only single failures count and the result says so.
capacity A B 10000 link holds when A can send B at least 10000 (in the units of the links' capacity) with nothing failed, and still after any single link fails. The kind is link, srlg, device, any (the default) or none (only with everything up). It is a max flow over the links' capacities in both directions; a link without a capacity counts as unlimited, and the result says how many there are. The answer names the worst single failure and what it leaves: the worst (link edge core1) leaves 10000.
20000 gets through: 10000 on each uplink, with room to spare beyond the cores.
disjoint A B link holds when there are two paths from A to B that share no link; device also keeps them apart at every device in between. The answer is the proof: the two paths, the pair with the least total weight (Suurballe's algorithm, which finds the pair when the shortest path alone would block the second). show on the graph draws them in two colors. If both paths cross the same shared risk group, it says so: two link-disjoint paths in one duct are one cut away from both going down, which survive A B srlg catches.
The shortest path, s-x-y-t, costs 3. Take it, and every other way from s to t shares a link with it: no second path is left.
On a repository whose owner isn't on Premium, these three intents are listed as waiting for Premium. They are not failures and never block a merge; the rest of the intents are checked as usual.
The network overview scores the design: resilience is the share of single failures, one device or one link at a time, that cut nobody off. For each failure that does, it says who is cut off, worst first (core1 fails: cuts off 3 devices: dist1, acc1, acc2). Show the heat colours every device by how much its own failure would cut off, from amber to red.
Then it looks for the fix. It tries every link the design doesn't have yet, and ranks them the way an engineer would choose: what each one removes first (single points of failure and critical links), a short run before a long one (same site before a new circuit between sites), and never two leaf devices wired to each other. The best few are shown with what they remove. Add it in the editor opens the editor with that link already added, ready to review, save on a branch and open as a pull request, where the intents and the twin check it.
Point at a device. Today core1's failure cuts off dist1, acc1 and acc2: they all hang on it.
The design over time compares today's design with any of its last commits. Move the slider back and the graph shows what changed since then: devices and links added in green, removed in dashed red, changed in amber, with the commit, who pushed it and when. Play walks from the oldest of them to now. It's the quickest way to answer "what did we change since the outage?"
Copy for an AI agent (Markdown) puts the design on the clipboard as a few lines of Markdown: the devices and links as tables, the resilience score, the single failures that cut devices off and the suggested links. Paste it into Claude Code, Codex or a ticket: a fraction of the tokens of the .zevtopo files, with the analysis already done. Agents connected through zev mcp can also read a design's intents and failures themselves.
A design that has never run is a hypothesis. The Network overview's Download .clab.yml turns the design into a Containerlab topology (or, with Download .gns3, a GNS3 project), so you can deploy it in containers or VMs, ping across it, pull a link, and see what your intents and failure playground predicted actually happen.
.zevtopo files in the repositorycontainerlab deploy -t my-network.clab.ymlAlso at GET /v1/repos/<owner>/<repo>/topology-export?format=containerlab|gns3[&ref=<branch>], as {file, text, warnings, nodes, links}. It is free, like the rest of the design repository.
How the design maps:
| Design | Lab |
|---|---|
a [[device]] | a node; vendor picks the kind and image: frr runs the FRRouting container, arista is ceos, cisco is cisco_iol, juniper is juniper_crpd, mikrotik is mikrotik_ros, vyos is vyosnetworks_vyos; any other vendor is a plain Linux container |
site, role, model | the node's labels |
a [[link]] | two endpoints, one per device |
ports (a_if, b_if) | kept only where they are already ethN; every other name (Gi0/1, Te1/0/1) is written in a comment next to the link, and the endpoint gets the next free ethN |
| a device only named by a link | a node too |
What it can't do for you, and says so in a list of notes: vendor images (ceos, cisco_iol, crpd, vrnetlab/*) are not freely downloadable, so the file names placeholders you import or build yourself; names Containerlab doesn't accept (spaces, slashes) are cleaned and listed; a link from a device to itself is left out; vendors without a Containerlab kind run as Linux containers. The lab has the design's shape, not its configuration: load the real configs from your site or config repository, or write them with the twin in mind.
If your team builds labs in GNS3 rather than Containerlab, Download .gns3 gives the same design as a GNS3 project. In GNS3, choose File → Open project and pick the file: the devices are already placed (edge at the top, then core, distribution, access, hosts at the bottom, each row by site) and wired.
| Design | GNS3 |
|---|---|
frr, arista, juniper | Docker nodes: the FRRouting container, ceos:latest (with the environment and start command cEOS needs), crpd:latest |
cisco, mikrotik, vyos | QEMU VMs: IOSv (vios-adventerprisek9-m.spa.159-3.m8.qcow2), MikroTik CHR (chr-7.16.img), VyOS (vyos-1.4.qcow2), with RAM and adapters set |
no vendor, a switch role (access, leaf, switch) | GNS3's built-in Ethernet switch: runs with no image at all |
| no vendor, a host role with one link | a VPCS host: no image either |
| any other vendor | a Linux container (network-multitool) |
| ports | a port the design names in the node's own scheme (eth2, ether3, Gi0/1) is that adapter; any other name gets the next free adapter and is shown as that port's name on the canvas, so Te1/0/1 still reads Te1/0/1 |
vendor, role, site, model | the node's notes |
The same design always gives the same file (node and link IDs come from the names), so a .gns3 kept next to the design only changes where the design did. The images are named, not shipped, and GNS3 won't open a project while one of them is missing, so the first note lists them: add the Docker images to the GNS3 server (or GNS3 VM) and the QEMU disks under its images folder first. Checked against GNS3 2.2. API: ?format=gns3, file <repo>.gns3.
An auditor, a customer or your own incident review asks: who changed the network design, what was checked, and who agreed? A pull request page answers that today; a change certificate answers it in a form that can't be quietly edited later and can be checked without trusting Zaryn's database.
With Premium, every merged pull request that changes a design's .zevtopo or .zevintent files gets one. It records:
prev: the previous certificate of the same repositoryIt is a dag-cbor document signed by Zaryn's Ed25519 key, the same key that signs the transparency log, and it is a leaf of that log. Because each certificate names the one before, a repository's certificates form a chain: the design's history, step by step, with nothing left out unnoticed (the Network overview lists the chain and marks a gap).
Each certificate names the one before it (prev), so a missing or altered one shows. The newest is signed over the chain's earlier link.
Check one. On the merged pull request, Verify in this browser checks five things with nothing but the bytes: the content address (CID) matches the signed document, the signed bytes say what the page shows, the Ed25519 signature, that the key is the one the transparency log is signed with, and that the certified files are the repository's files at that commit. Download saves the certificate as JSON to check elsewhere. The API:
GET /v1/repos/<owner>/<repo>/pulls/<n>/certificate payload (base64), payload_cid, signature, public_key, log_index, certificate (JSON)GET /v1/repos/<owner>/<repo>/design-certificates the chain, newest firstGET /v1/transparency/proof?leaf_index=<log_index> the certificate's place in the logTo check by hand: base64-decode payload; its CID is CIDv1, dag-cbor, BLAKE3-256 of those bytes (b3sum); the signature is Ed25519 over the same bytes with public_key (openssl pkeyutl -verify -rawin).
A certificate covers the design checks Zaryn ran on the merge. Twin results for linked sites and eval results are on the pull request, not in the certificate. On the Free plan merges work the same, without certificates.
The design is the start of the loop: the twin predicts what a config change does, and rollouts make it and check it on the devices. Designs and configs live in separate repositories: the design says what the network is, the config repository says how each device is set up.