# Rust packages (crates) Source: https://zaryn.xyz/docs/en/packages-rust Publish a Rust crate to Zaryn with cargo, use it from another project, keep it private, and fix the usual errors. Every step explained. Rust's package manager, **cargo**, can download crates from more than one registry. You tell it about Zaryn once, and from then on `cargo publish`, `cargo add` and `cargo build` work with Zaryn the same way they work with crates.io. > Only want crates.io to download faster? You don't need any of this page: see [the crates.io mirror](/docs/en/package-mirrors#rust-crates). Can't install Rust itself because static.rust-lang.org is out of reach? See [rustup through Zaryn](/docs/en/package-mirrors#rust-itself-rustup). ## Tell cargo about Zaryn (once per computer) Open (or create) the file `~/.cargo/config.toml`, the settings file cargo reads every time it runs, and add: ```toml [registries.zaryn] index = "sparse+https://api.zaryn.xyz/v1/packages/cargo/index/" ``` - `[registries.zaryn]` gives the registry a short name, `zaryn`, that you'll use in commands. - `index` is where cargo looks up which crates and versions exist. `sparse+` means it asks for one small file per crate instead of downloading a list of everything. ## Get a token and log in On [Packages](/packages), press **Create a publish token** and copy it. Then: ```bash cargo login --registry zaryn ``` Paste the token when cargo asks. cargo keeps it in `~/.cargo/credentials.toml`, so you only do this once. ## Publish In your crate's `Cargo.toml`, make sure the `[package]` part has a `description` and a `license`, and say where it may be published: ```toml [package] name = "hello-zaryn" version = "0.1.0" edition = "2021" description = "Says hello" license = "MIT" publish = ["zaryn"] # only ever to Zaryn, never by accident to crates.io ``` Then: ```bash cargo publish --registry zaryn ``` cargo builds the crate once to make sure it compiles, packs it into a `.crate` file and uploads it. The crate appears on [Packages](/packages) right away. To publish a fix, raise `version` (for example to `0.1.1`) and run `cargo publish --registry zaryn` again. A version that's already published can't be replaced. ## Use it from another project ```bash cargo add --registry zaryn hello-zaryn ``` That adds this line to `Cargo.toml` (you can also write it by hand): ```toml [dependencies] hello-zaryn = { version = "0.1", registry = "zaryn" } ``` `cargo build` downloads it from Zaryn. Your crate can depend on crates.io crates as usual; cargo fetches each from where it lives. ## Private crates (Premium) A crate becomes private on its page: open it from [Packages](/packages) and press **Make private**. Only you, or the members of the organization that owns it, can see and install it. Reading a private crate needs your token on every request, so it goes through a second registry name: ```toml [registries.zaryn-private] index = "sparse+https://api.zaryn.xyz/v1/packages/cargo/private/index/" credential-provider = "cargo:token" ``` ```bash cargo login --registry zaryn-private cargo add --registry zaryn-private my-secret-crate ``` The private index also lists your public crates, so a team can use just `zaryn-private`. ## Everyday commands | To… | Run | |---|---| | find crates on Zaryn | `cargo search --registry zaryn hello` | | hide a broken version | `cargo yank --registry zaryn --version 0.1.0 hello-zaryn` | | bring it back | `cargo yank --registry zaryn --version 0.1.0 --undo hello-zaryn` | Yanking doesn't delete anything: projects whose `Cargo.lock` already uses that version keep building. New projects just won't choose it. ## When something goes wrong | cargo says | What it means | Fix | |---|---|---| | `401` or "this index needs a token" | cargo has no token for this registry | `cargo login --registry zaryn` (or `zaryn-private`) | | "this token can't publish packages" | the token lacks `package:write` | create a new one on [Packages](/packages) | | "this package name belongs to someone else" | another account published that name first | choose another name | | "crate `foo_bar` already exists…" | `foo-bar` and `foo_bar` count as the same name, as on crates.io | choose another name | | "this version is already published" | versions can't be replaced | raise `version` in `Cargo.toml` | | "package storage on the Free plan is full" | your packages and images use 500 MB | yanked versions still count; [Premium](/billing) has 100 GB | | `no matching package named …` | wrong registry name, or a private crate through `zaryn` | check the `registry =` in `Cargo.toml` | ## How it works Zaryn speaks cargo's own registry protocol: the sparse index (one file per crate listing every version, its dependencies and features), the download address, and the publish, yank and search API. Each `.crate` file is stored by its SHA-256 hash, and that hash is in the index, so cargo checks every download and refuses a file that doesn't match. --- # Path Explain and probes Source: https://zaryn.xyz/docs/en/network-paths Why can't A reach B? Zaryn follows the traffic hop by hop through your devices' routes, ACLs and firewalls, names the device and the rule that stops it, and gives the fix in that device's commands. Probes check what matters every minute. "Why can't the office reach the web server?" Answering that usually means logging in to router after router, reading routing tables and access lists. **Path Explain** does it for you, from what the devices of a [site](/docs/en/network-sites) said last: - **Every hop.** The route each device uses (`172.16.20.0/24 via 10.0.2.2, OSPF`), the interface it leaves by, the ACLs and firewall rules it passes, and the rule that let it through. - **Where it stops, and why.** The device, the interface, and the exact rule that drops it, or the missing route, the routing loop, the interface that's down. - **The way back.** The reply is followed too. A reply that takes another way through a stateful firewall is dropped as invalid, the classic **asymmetric routing** problem, and Path Explain says so. - **The fix**, in the commands of that device's vendor: where to insert the permit rule, which static route to add and through which neighbor. **Probes** run on the site's collector: ping, a TCP port, an HTTP(S) URL, a DNS lookup, every 30 seconds to an hour. When one fails, Path Explain says whether the network is why. Zaryn only suggests. It never changes a device. ## What the collector reads for it The collector (zev 0.8 or later) reads two more things from each device, still with read-only commands: | Vendor | Routing table | Filters | |---|---|---| | Cisco IOS / IOS-XE | `show ip route` | ACLs on interfaces (`ip access-group`), from the config | | Huawei VRP | `display ip routing-table` | `traffic-filter` ACLs on interfaces, from the config | | MikroTik RouterOS | `/ip route print terse` | `/ip firewall filter`, with address lists and interface lists | | FRRouting, VyOS, Linux | `ip -j route` (the kernel's table) | iptables (`iptables-save`) and nftables (`nft -j list ruleset`) | On Linux, reading the firewall needs root. Let the collector's login run only those two commands, read-only: ```text # /etc/sudoers.d/zev-site netops ALL=(root) NOPASSWD: /usr/sbin/iptables-save, /usr/sbin/nft -j list ruleset ``` Without it, Path Explain says it couldn't read that device's firewall, and doesn't pretend it has none. A device's **Routes and filters** tab shows what was read. Search for an address to see the routes that hold it, and which one is used. ## Ask: why can't A reach B? On the site's **Paths** tab: - **From** and **To**: an IPv4 address, a device's name, or `collector` (the collector's own address). - **Protocol** and **port**: TCP or UDP with a port, ICMP (ping), or any IP. - **Enters at** (optional): the device the traffic comes in by, when the source isn't on one of the site's subnets (traffic from the internet, from a VPN) or when a subnet has two gateways. For example, from `192.168.10.20` (a laptop) to `172.16.20.10` (a server), TCP port 80: ```text Blocked by a filter sw1 drops it (outbound on GigabitEthernet0/2): SERVERS-OUT, rule 40 deny ip any any log gw bridge → ether2 route 172.16.0.0/16 via 10.0.1.2 (static) allowed · firewall, passing through · forward (no rule matched) sw1 Gi0/1 → Gi0/2 route 172.16.20.0/24 via 10.0.2.2 (ospf) dropped · outbound on Gi0/2 · SERVERS-OUT #40 deny ip any any log ``` ## Reading the answer | Answer | What it means | |---|---| | Reachable, both ways | It gets there, and the reply comes back. | | Leaves the site | It leaves toward a next hop that isn't one of the site's devices (an ISP, another site). Zaryn can't see past it. | | Gets there, but the reply doesn't come back | The request arrives. The reply is dropped on its way back (often asymmetric routing). | | Blocked by a filter | An ACL or firewall rule drops it. The answer quotes the rule. | | No route | A device has no route to the destination, and no default route. | | Discarded by a route | A route sends it to Null0 or a blackhole. | | Routing loop | Two or more devices send it back and forth. | | An interface on the way is down | The route uses an interface that's down or shut down. | | May be blocked | A rule Zaryn can't fully evaluate comes before the one that decides (an object group, a named set, a time range). The answer names it. | | Can't tell | Something is missing: a device's routes weren't collected, or the source isn't on any subnet of the site. | When there are **equal-cost paths** (ECMP), each one is followed and you can switch between them. **Show it on the map** highlights the devices on the way. **What each answer rests on** is listed under it: a device whose firewall couldn't be read, two gateways on the source's subnet, NAT on the way. ## The fix: the ACL rule, the route, the interface Under a failing answer, Zaryn gives the commands for that device: ```text # Cisco: just before the rule that drops it ip access-list extended SERVERS-OUT 35 permit tcp host 192.168.10.20 host 172.16.20.10 eq 80 # Huawei: a rule id below the one that drops it acl number 3001 rule 2 permit tcp source 192.168.10.20 0 destination 172.16.20.10 0 destination-port eq 3389 # MikroTik: placed before the rule that drops it /ip firewall filter add chain=forward action=accept protocol=tcp src-address=192.168.10.66 dst-address=172.16.20.10 dst-port=443 place-before=[find comment="quarantine"] # iptables / nftables iptables -I FORWARD 2 -s 10.81.1.10 -d 10.81.2.10 -p tcp --dport 8080 -j ACCEPT nft insert rule inet fw forward position 4 ip saddr 10.81.1.10 ip daddr 10.81.2.10 udp dport 53 accept ``` For **no route**, Zaryn looks for a neighbor on the same subnet that knows the way, and gives the static route through it (`ip route`, `ip route-static`, `/ip route add`, VyOS `set protocols static`). For an interface that's **shut down**, the command that brings it up. When there's no room for a rule number (Cisco sequence 20 and 21 with nothing between), the fix renumbers the list first (`ip access-list resequence`, Huawei's `step`). Read the commands before you use them. A permit for one host is the narrowest fix. You may want a wider one. ## When the reply takes another way Stateless ACLs (Cisco, Huawei) need a rule for the reply too, unless one allows `established` traffic. Stateful firewalls (MikroTik, iptables, nftables) let a reply back in when they saw the request. If the reply comes back through a firewall the request never went through, that firewall sees a reply to nothing it knows and drops it as **invalid**. MikroTik's default configuration does exactly that. Path Explain follows the reply through each device with what that device saw, so it finds this case. ## Watched paths After an answer, choose **Watch this path** and give it a name (`users-to-web`). Zaryn checks it again whenever a device on the way reports different routes, filters or interfaces. When the answer changes, **Changes** says so, with the device and the rule ("watched path users-to-web: Reachable → Blocked by a filter, at sw1: deny ip any any"). Someone's ACL change that broke a path shows up minutes later, not when users call. ## What it doesn't follow yet - **NAT.** When a device on the way does NAT, the answer says so and follows the original addresses. - **VRFs and policy routing.** Only the main (global) routing table is read. - **Cisco zone-based firewall** and **Huawei's `match-order auto`**. The answer says when a device has them. - **IPv6.** ## Probes On the site's **Health** tab, add a probe. The collector runs it as often as you choose (30 seconds to an hour): | Kind | Target | What's measured | |---|---|---| | Ping | an address or a name | round trip and loss (4 echoes) | | TCP port | an address or a name, and a port | how long the connection takes. **Refused** (the host answered, nothing listens) is told apart from **no answer** (dropped on the way) | | HTTP(S) | a URL | response time and status. Fine by default: 2xx and 3xx. Set the expected status (`200`, `2xx`, `200,401`) | | DNS lookup | a name, or `name@server` to ask one server | answer time. Optionally, an address the answer must hold | Each probe shows its last day (a bar per half hour), the share of checks that passed, and a chart for 6 hours, a day or a week. Results are kept for a week. A probe becomes **failing** after two failures in a row, and is back to normal after one success. Both show in **Changes**. When it starts failing, Zaryn runs Path Explain from the collector to the target: - If the network path is fine, the problem is at the target itself (the service is down, the port is closed). - If not, it names the device and the rule. **Open in Path Explain** shows the whole answer. Try a probe from the collector's shell, as the service runs it: ```bash zev site probe ping 10.0.0.10 zev site probe tcp 10.0.0.10:443 zev site probe http https://intranet.example/health --expect 200 zev site probe dns intranet.example@10.0.0.53 --expect 10.0.0.10 ``` ## Latency between sites: mesh and the health map With **mesh** on (Health tab), a site's collector pings the collectors of your other sites that have mesh on too. The **Sites** page then shows a **health map**: latency and loss between every pair of sites, with rows where the ping starts. A link between two sites going down shows on both. ## Limits Free: 10 probes and 10 watched paths per site. Premium: 300 probes and 200 watched paths per site. Mesh probes don't count. --- # Digital twin: test a change before you make it Source: https://zaryn.xyz/docs/en/network-twin See what a config change would do to your network before anyone types it. Which traffic stops, starts or takes another way and why, every routing table entry that changes, and the single points of failure it creates. On the site page, from the command line, and on every pull request. A maintenance window goes wrong when a change does something nobody expected: an ACL line that also blocks backups, an OSPF cost that sends everything over the slow link, a "harmless" shutdown that leaves one router holding the whole office. The **digital twin** shows you that before the change reaches a device. You give it the configs as they would be. It answers with: - **Which traffic stops working, starts working, or takes another way.** Every pair of subnets, every loopback, the flows the changed ACL rules name, your [watched paths and probes](/docs/en/network-paths). Each one is checked hop by hop on the network as it is and as it would be. - **Why.** The device and the exact rule or route that makes the difference, with the whole walk for both versions side by side. - **The change in words.** "interface Gi0/1 shut down", "OSPF cost on eth1: default → 100", "EDGE: rule added: deny tcp any host 10.2.0.10 eq 22", "BGP no longer announces 10.2.0.0/24". - **Every routing table entry that changes,** on every device, not only the one you edited. - **Failure drills (Premium).** Every device and every link is failed in turn, before and after the change. You get the new single points of failure it creates and the ones it removes. Nothing is ever sent to the devices. The twin works from what the devices of a [site](/docs/en/network-sites) said last. ## Try a change on the site page Open a site, then **Try a change**. Choose a device: its current config opens in an editor. Edit it, or load a file, and add more devices if the change spans them. Then **See what it would do**. Flows that stop working come first, in red. Open one to see **Now** and **With the change** hop by hop. Below the results you can **explain any path on the twin**: ask about any source and destination, on the network as it would be. ## From the command line or CI: zev site diff ```bash zev site diff acme/hq r1=r1.cfg core-sw=core-sw.cfg ``` ```text ✗ 212 of 214 flows tested behave the same; 1 stop working; 1 take another way. 3 routing table entries change. What changes r1 EDGE: rule added: deny tcp any host 10.2.0.10 eq 22 r1 OSPF cost on GigabitEthernet0/1: default → 100 Stop working ✗ 10.1.0.100 → 10.2.0.10 tcp/22 (r1 EDGE: added deny tcp any host 10.2.0.10 eq 22) before: 10.1.0.100 reaches 10.2.0.10 (tcp/22), and the reply comes back after: r1 drops it out GigabitEthernet0/2: EDGE rule "deny tcp any host 10.2.0.10 eq 22" Take another way ~ 10.1.0.100 → 10.3.0.100 icmp (10.1.0.0/24 → 10.3.0.0/24) r1 → r3 ⇒ r1 → r2 → r3 ``` It exits with 1 when something stops working (or, with `--drills`, when a new single point of failure appears), so a CI job can stop a change. `--json` prints the whole answer. It uses your `zev login`, or `ZEV_SERVER` and `ZEV_TOKEN` in CI. ## Pull requests on a config repository Keep the site's configs in a repository on Zaryn, one file per device, named after it: `configs/r1.cfg`, `configs/core-sw.rsc` (the extension is optional: `.cfg`, `.conf`, `.rsc`, `.txt`, `.boot` and others). Then, in the site's **Collector and settings**, link it under **Config repository**. Only an admin of the repository can link it. From then on, every pull request that changes a device's file gets the twin: - The pull request shows a **network twin** check: behaves the same, behaves differently, or breaks things. People who can see the site get the whole answer. - The "before" is the target branch's files (the device's last collected config where there's no file), and the "after" is the pull request's. - **Merging waits** while traffic would stop working, or while a new single point of failure appears (with Premium's drills). - A **repository admin can merge anyway**. Zaryn keeps who did it, when, and what the twin said, and the site's Changes shows it. The twin is worked out again whenever either branch moves. ## Failure drills (Premium) Redundancy is easy to lose without noticing: a link shut "for a while", a route that only exists on one side. The drills fail every device and every link in turn, with the change and without it, and test the flows that work. - **New single points of failure:** something whose failure would now stop flows that survived it before the change. These hold a pull request back like broken flows do. - **No longer single points of failure:** the change added redundancy. - **Links that were already single points of failure** are listed too, so you know where you stand. ## How it works The twin simulates routing from every device's config, twice: with the configs as they are, and as proposed. Only the **difference** is applied to what the devices said last: their routing tables, interfaces and filters. So: - Routes the simulation can't see, such as a default route learned from your ISP or routes from devices outside the site, stay as they are. - Anything the simulation simplifies is simplified the same way both times, and cancels out. What it simulates from the configs: - **Interfaces:** addresses, shutdown and no shutdown. - **Static routes,** including Null0 and blackhole routes, distances, and next hops resolved through other routes. - **OSPF:** which interfaces take part (network statements, interface areas, MikroTik templates), costs, passive interfaces, equal-cost paths, redistribution of connected and static routes, and announcing a default route. - **BGP** between the site's devices: eBGP and iBGP sessions configured on both sides, network statements, redistribution, next-hop-self, and the best path by AS path length, then eBGP before iBGP. - **ACLs and firewall rules** from the new config: Cisco ACLs and where they're applied, Huawei traffic filters, MikroTik's firewall. Each vendor's own administrative distances are used. Path Explain then walks each flow through both versions, exactly as it does for [Path Explain](/docs/en/network-paths). ## What it doesn't simulate yet Better to know than to trust it blindly: - OSPF areas are treated as one (no summarization between areas, no stub areas), and OSPF external routes are type 2. - BGP policy: route maps, prefix lists, communities, local preference, MED. Sessions to devices outside the site keep what they learned. - VRFs, policy-based routing, NAT, IPv6, IS-IS, EIGRP and RIP. - Firewall changes on Linux-based devices (FRR, VyOS, Linux): iptables and nftables aren't in the config Zaryn reads, so only their routing changes are simulated. The answer lists what it rests on, including devices without a config and the flows it had no time to test. ## Limits - Up to 400 flows per run. Flows named by changed rules, watched paths and probes go first. - Drills: up to 60 failures over up to 150 flows. - The behavior diff is free on every plan; failure drills come with Premium. --- # Zig packages Source: https://zaryn.xyz/docs/en/packages-zig Publish a Zig package and get the exact hash zig fetch will compute, check a package before publishing, use any Zaryn repository as a dependency, and fix build.zig.zon errors. Every step explained. Zig doesn't have a central package registry. A dependency is simply **a web address of an archive plus its hash**, written in your project's `build.zig.zon`. `zig build` downloads the archive, computes its hash, and stops if it doesn't match. That design is safe, but it leaves you to host the archive somewhere and work out the hash. Zaryn does both: - **A registry for Zig.** Upload your package once; Zaryn gives you its address and the hash, worked out exactly the way `zig fetch` does it, so you can paste them straight into `build.zig.zon`. - **A check before you publish.** Zaryn reads your `build.zig.zon` the way zig does and tells you, in plain words, what zig would refuse (a missing fingerprint, a name that isn't allowed, files left out of the package). - **Any repository is a dependency.** Every commit of a Zaryn repository is downloadable as an archive with a fixed hash. - **Mirrors.** Dependencies from GitHub, Codeberg and others (archives, `.zip` files and `git+https` repositories), and the Zig compiler itself, can come through Zaryn; `zev mirror zig` does it for a whole project: see [Mirrors](/docs/en/package-mirrors#zig-dependencies). ## What a Zig package needs A folder with a `build.zig` (how to build it) and a `build.zig.zon` (what it is). `zig init` creates both. A `build.zig.zon` looks like this: ```zig .{ .name = .greet, // the package name: letters, digits and _ .version = "0.1.0", // raise it for every release .fingerprint = 0x3610a6865d7ac0a2, // made by zig init; never change it .minimum_zig_version = "0.15.1", // oldest Zig that builds it .dependencies = .{}, // other packages it uses .paths = .{ "build.zig", "build.zig.zon", "src" }, // what belongs to the package } ``` - **`.name`** starts with a dot (`.greet`, not `"greet"`) since Zig 0.14. - **`.fingerprint`** is your package's permanent ID. If you copy someone's package to start your own, Zaryn's check tells you the new value to use. - **`.paths`** lists the files and folders that are part of the package. Everything else in the archive (notes, test data, pictures) is left out and doesn't change the hash. ## Pack it From the folder above your package (here the package is in `greet/`): ```bash tar czf greet-0.1.0.tar.gz greet ``` This makes one compressed file of the folder. `.tar.xz`, `.tar.zst` and plain `.tar` work too. ## Check it (optional, recommended) On [Packages](/packages), choose **Zig**, then **Check a package before publishing** and pick the file. Or from a terminal: ```bash curl --data-binary @greet-0.1.0.tar.gz -H "Authorization: Bearer $ZARYN_TOKEN" \ https://api.zaryn.xyz/v1/packages/zig/-/check ``` You get the hash, how many files are in the package, and every problem zig would stop at, for example: ```text invalid fingerprint 0x1234 for the name .greet: if this is a new or forked package, use 0x3610a6865d7ac0a2 ``` Nothing is stored. ## Publish Create a token on [Packages](/packages) (**Create a publish token**), then: ```bash curl -T greet-0.1.0.tar.gz -H "Authorization: Bearer $ZARYN_TOKEN" \ https://api.zaryn.xyz/v1/packages/zig/ ``` - `-T` uploads the file. - The name and version come from `build.zig.zon`, so there's nothing else to type. - To publish for an organization you own or administer, add `?owner=` to the address. Zaryn answers with everything someone needs to use it: ```json { "name": "greet", "version": "0.1.0", "hash": "greet-0.1.0-osB6XSsBAACcv0dHgf4SJ_AaruNKCheoTxH_lgjFjt-i", "url": "https://api.zaryn.xyz/v1/packages/zig/greet/greet-0.1.0.tar.gz", "zon_entry": ".greet = .{ .url = \"…\", .hash = \"…\" }," } ``` A published version can't be replaced: for a fix, raise `.version` and publish again. ## Use it in another project In the other project's folder: ```bash zig fetch --save https://api.zaryn.xyz/v1/packages/zig/greet/greet-0.1.0.tar.gz ``` `zig fetch --save` downloads the package, checks it, and adds it to `build.zig.zon` with its hash. The package's page on Zaryn shows the same entry, ready to copy, if you'd rather paste it yourself. Then use it in `build.zig`: ```zig const greet = b.dependency("greet", .{}); exe.root_module.addImport("greet", greet.module("lib")); ``` `"lib"` is the module name the package's own `build.zig` gives with `b.addModule("lib", …)`; the package's README should say which names it offers. ## Use a Zaryn repository as a dependency Every commit of a repository can be downloaded as a `.tar.gz`: ```text https://api.zaryn.xyz/v1/repos///branches//archive/.tar.gz ``` The same commit always gives the same bytes, so its hash never changes. The simplest way to get the address and hash is to ask Zaryn: ```bash curl https://api.zaryn.xyz/v1/repos///branches/main/zig-package/HEAD ``` The answer pins the newest commit (never "HEAD", which moves) and includes a ready `zig fetch --save …` line and `.dependencies` entry, plus anything in that commit's `build.zig.zon` zig would refuse. On the repository's page, a repository with a `build.zig.zon` also has a **zig** tab next to the clone commands that shows the same. The repository must be public for `zig fetch` to download it, since zig can't send a token. ## Private Zig packages Packages can be made private on their page (Premium). Because `zig fetch` can't send a token, download a private package with curl, unpack it inside your project, and point to the folder: ```bash curl -LO -H "Authorization: Bearer $ZARYN_TOKEN" \ https://api.zaryn.xyz/v1/packages/zig/greet/greet-0.1.0.tar.gz mkdir -p deps && tar xzf greet-0.1.0.tar.gz -C deps ``` ```zig .dependencies = .{ .greet = .{ .path = "deps/greet" }, }, ``` ## When something goes wrong | You see | What it means | Fix | |---|---|---| | "missing top-level 'fingerprint' field; suggested value: 0x…" | `build.zig.zon` has no fingerprint | add `.fingerprint = 0x…` with the suggested value | | "invalid fingerprint … use 0x…" | the fingerprint doesn't belong to this name (often a copied package) | use the value given | | "'name' must be an enum literal" | `.name = "greet"` is the old style | write `.name = .greet` | | "missing top-level 'paths' field" | zig needs to know which files belong to the package | add `.paths = .{ "build.zig", "build.zig.zon", "src" }` | | "there is no build.zig.zon at the top of the archive" | the archive holds a folder of folders, or no manifest | pack the package folder itself | | "this package name belongs to someone else" | another account published that name | rename `.name` (and make a new fingerprint) | | zig says `hash mismatch` | the archive at that address changed since the hash was written | for Zaryn addresses this can't happen; for other sites, see [Mirrors](/docs/en/package-mirrors#zig-dependencies) | ## How the hash works zig doesn't hash the archive file; it hashes **what's inside**. It unpacks the archive, keeps only the files under `.paths`, hashes each file together with its path, and combines those hashes in name order. The result is written as `name-version-` followed by 44 characters that also encode the fingerprint and the package's size. That's why re-packing the same files with a different tool, or adding a notes file outside `.paths`, gives the same hash. Zaryn uses the same rules (checked against `zig fetch` on real packages), so the hash it shows is the hash zig will compute. --- # Mirrors for pypi.org, npm, crates.io, Rust, Zig and their compilers Source: https://zaryn.xyz/docs/en/package-mirrors Make pip, uv, npm, cargo, rustup and zig download through Zaryn when pypi.org, npmjs.com, crates.io, GitHub or ziglang.org are slow or unreachable. Every file is checked against a hash your tools already know, so the mirror can't change anything. A **mirror** is a copy of another site's files kept closer to you. When pypi.org, npmjs.com, crates.io, GitHub or ziglang.org are slow, blocked, or down, pip, uv, npm, cargo, rustup and zig can download through Zaryn instead. ## Why you can trust a mirror Normally a mirror is a risk: whoever runs it could hand you a changed file. These mirrors are built so that can't happen: 1. Before Zaryn keeps a file, it checks it against a hash that comes from the original source: the sha256 in pypi.org's index for Python packages, the integrity in npm's package document for npm packages, the checksum in crates.io's index for crates, the hash written in your `build.zig.zon` for Zig packages. 2. When the file reaches you, cargo or zig checks the same hash again, on your computer. A file that doesn't match is refused. So the worst a mirror could do is fail to answer; it can never give you different code. (Installing Rust itself with rustup works a little differently; [its section](#rust-itself-rustup) says how.) A file Zaryn has fetched once also keeps working when the original site is down. ## All at once: zev mirror If you have the `zev` command ([install it](/docs/en/installation)), one line sets up pip, uv, npm, cargo and rustup: ```bash zev mirror on ``` `zev mirror` shows what is set up, `zev mirror on pip cargo` picks some, and `zev mirror off` takes it all out again. zev only adds a clearly marked block to each tool's own settings file and never changes a setting you made yourself: if, say, your `~/.npmrc` already points at another registry, zev leaves it and tells you. For a Zig project, `zev mirror zig` (in the project's folder) points its `build.zig.zon` at the mirror and fetches what its dependencies need; `zev mirror zig --undo` puts the addresses back. The sections below explain each tool by hand. ## Python: pip and uv Zaryn's Python index holds your own projects on Zaryn and everything on pypi.org: ```bash pip config set global.index-url https://api.zaryn.xyz/v1/packages/pypi/all/simple/ # uv export UV_DEFAULT_INDEX=https://api.zaryn.xyz/v1/packages/pypi/all/simple/ # and Python itself, for uv python install export UV_PYTHON_INSTALL_MIRROR=https://api.zaryn.xyz/v1/packages/python/-/standalone ``` Every file from pypi.org is checked against the sha256 in pypi.org's index; Python builds against their release's SHA256SUMS. A name that exists on Zaryn always comes from Zaryn, so a look-alike published on pypi.org can't slip in. More in [Python packages](/docs/en/packages-pypi). ## JavaScript: npm ```bash npm config set registry https://api.zaryn.xyz/v1/packages/npm-mirror/ ``` pnpm, yarn and bun read the same setting. Every tarball is checked against the sha512 *integrity* npm's package document lists, the same value npm checks after downloading. Packages you publish on Zaryn keep their own scope line in `.npmrc` (see [npm packages](/docs/en/packages-npm)); the mirror is for everything else. ## Rust crates Add this to `~/.cargo/config.toml` (the settings file cargo reads every time it runs; create it if it doesn't exist): ```toml [source.crates-io] replace-with = "zaryn" [source.zaryn] registry = "sparse+https://api.zaryn.xyz/v1/packages/cargo/mirror/index/" ``` - `[source.crates-io] replace-with = "zaryn"` tells cargo: whenever you'd go to crates.io, go to the source called `zaryn` instead. - `[source.zaryn]` says where that is. That's all. `cargo build`, `cargo add`, `cargo update` and `cargo install` now get crates.io crates through Zaryn, and nothing else in your projects changes: `Cargo.toml` and `Cargo.lock` stay the same, and your teammates without the setting still download from crates.io. What happens behind the scenes: - cargo asks Zaryn for a crate's index file (the list of its versions and their checksums). Zaryn answers from its copy if it's less than 5 minutes old, otherwise asks crates.io. If crates.io doesn't answer, you get the copy Zaryn has. - cargo asks for a `.crate` file. Zaryn sends its copy, or downloads it from crates.io, compares its SHA-256 with the checksum in the index, and only then keeps and sends it. To stop using the mirror, delete those lines. ## Rust itself (rustup) rustup, the tool that installs and updates Rust, can download through Zaryn too. Set two variables before running it: ```bash export RUSTUP_DIST_SERVER=https://api.zaryn.xyz/v1/packages/rust/- export RUSTUP_UPDATE_ROOT=https://api.zaryn.xyz/v1/packages/rust/-/rustup ``` - `RUSTUP_DIST_SERVER` is where Rust itself comes from (the compiler, cargo, the standard library). - `RUSTUP_UPDATE_ROOT` is where rustup gets new versions of itself. Put the two lines in `~/.bashrc` (or your shell's start file) so they stay set. Then use rustup as usual: ```bash # first install, with the install script through Zaryn too curl -sSf https://api.zaryn.xyz/v1/packages/rust/-/rustup/rustup-init.sh | sh # later rustup update rustup target add wasm32-unknown-unknown ``` Before Zaryn keeps a file, it checks it against the `.sha256` file static.rust-lang.org publishes next to it, and rustup checks every download against the checksums in the channel file. The channel file itself comes to you from Zaryn, which fetched it from static.rust-lang.org over HTTPS; this is the one place you rely on Zaryn, as with any Rust mirror. When static.rust-lang.org can't be reached, the last channel Zaryn has keeps working. ## Zig dependencies Zig has no mirror setting: each dependency in `build.zig.zon` has its own address. So instead, the addresses are changed to go through Zaryn, while the hashes stay exactly as they are (and zig keeps checking them). **On the web:** open [Packages](/packages), scroll to **Mirrors**, paste your `build.zig.zon` and press **Point at Zaryn**, or **Point at Zaryn and check everything** to have Zaryn download each dependency now and report any problem. Copy or download the result and replace your file. **From a terminal** (`jq` picks the file out of the answer): ```bash curl --data-binary @build.zig.zon \ "https://api.zaryn.xyz/v1/packages/zig/-/mirror-zon?warm=1" | jq -r .zon > build.zig.zon.new mv build.zig.zon.new build.zig.zon ``` A dependency like ```zig .known_folders = .{ .url = "https://github.com/ziglibs/known-folders/archive/207c34a16e4365edc20d92c7892f962b3bed46e8.tar.gz", .hash = "known_folders-0.0.0-Fy-PJsbKAACbDh9bBxR0MMThxZSS6A9RH4apWphNHY70", }, ``` becomes ```zig .known_folders = .{ .url = "https://api.zaryn.xyz/v1/packages/zig/-/mirror/known_folders-0.0.0-Fy-PJsbKAACbDh9bBxR0MMThxZSS6A9RH4apWphNHY70/github.com/ziglibs/known-folders/archive/207c34a16e4365edc20d92c7892f962b3bed46e8.tar.gz", .hash = "known_folders-0.0.0-Fy-PJsbKAACbDh9bBxR0MMThxZSS6A9RH4apWphNHY70", }, ``` The new address holds the hash and the original address, so you can also write it by hand: `https://api.zaryn.xyz/v1/packages/zig/-/mirror//`. Zaryn downloads the original once, checks that its Zig hash is the one in the address, and keeps it. If the file at the original address has changed, Zaryn refuses it, exactly as zig would. To go back to the original addresses, use **Undo** on the web, or `?undo=1` instead of `?warm=1`. ### Dependencies of your dependencies Your dependencies have their own `build.zig.zon` files with their own addresses, which you can't change. zig only downloads a package it doesn't already have, though, so download those through Zaryn once and zig won't need the original site. **Point at Zaryn and check everything** lists them and gives a ready set of commands, one per package: ```bash zig fetch https://api.zaryn.xyz/v1/packages/zig/-/mirror//
``` ### What can be mirrored - Archives over `https://` from GitHub, Codeberg, GitLab, SourceHut, Bitbucket, ziglang.org and a few other well-known code hosts (a server's admin can add more). Other addresses are left as they are. - `.tar.gz`, `.tar.xz`, `.tar.zst`, `.tar` and `.zip` archives. - `git+https://` dependencies with a `#ref` (zig fetch --save writes the commit there). Zaryn checks out that commit the way zig does and serves it as a `.tar.gz`; the hash is the same, because zig hashes the files, not the archive. The mirror address looks like `…/mirror//git/github.com/owner/repo?ref=`. - Dependencies that already have a `.hash`. A new one gets its hash the first time you run `zig build` or `zig fetch --save`; mirror after that. Any package Zaryn already has can also be fetched by its hash alone: `https://api.zaryn.xyz/v1/packages/zig/-/hash/`. ## Zig toolchains The Zig compiler itself, from ziglang.org, by its file name: ```bash curl -LO https://api.zaryn.xyz/v1/packages/zig/-/toolchain/zig-x86_64-linux-0.15.1.tar.xz curl -LO https://api.zaryn.xyz/v1/packages/zig/-/toolchain/zig-x86_64-linux-0.15.1.tar.xz.minisig ``` - Use the exact file names from [ziglang.org/download](https://ziglang.org/download/): releases (`zig---.tar.xz`, `.zip` on Windows) and dev builds (`…-0.16.0-dev.…`). - Dev builds stay available on Zaryn after ziglang.org removes them, so a project pinned to one keeps building. - `https://api.zaryn.xyz/v1/packages/zig/-/toolchain/index.json` is ziglang.org's list of releases. Check the download with the Zig Software Foundation's key, exactly as you would from ziglang.org: ```bash minisign -Vm zig-x86_64-linux-0.15.1.tar.xz -P RWSGOq2NVecA2UPNdBUZykf1CCb147pkmdtYxgb3Ti+JO/wCYvhbAb/U ``` Tools that support Zig's community mirrors can use `https://api.zaryn.xyz/v1/packages/zig/-/toolchain` as one. ## How much the mirrors hold `https://api.zaryn.xyz/v1/packages/-/mirrors` shows what each mirror holds and how many downloads it answered in the last 30 days. When the cache is full, the files nobody has asked for in the longest time make room first; they're downloaded again if someone needs them. --- # npm packages (JavaScript, TypeScript) Source: https://zaryn.xyz/docs/en/packages-npm Publish a JavaScript or TypeScript package to Zaryn with npm, install it with npm, pnpm or yarn, and keep it private. Every step explained. > Only want npm installs to be faster or to work when npmjs.com is out of reach? See [the npm mirror](/docs/en/package-mirrors#javascript-npm). **npm** installs JavaScript packages. It can send one *scope* (the `@name/` part of a package name) to a different registry than the rest, which is how Zaryn fits in: your `@you/...` packages come from Zaryn, everything else still comes from npmjs.com. ## Tell npm about Zaryn (once per project, or once per computer) Create a token on [Packages](/packages) (**Create a publish token**). Then put these two lines in a file called `.npmrc`, either in your project's folder or in your home folder (`~/.npmrc`) for every project: ```ini @your-username:registry=https://api.zaryn.xyz/v1/packages/npm/ //api.zaryn.xyz/v1/packages/npm/:_authToken=YOUR_TOKEN ``` - The first line: packages whose names start with `@your-username/` live on Zaryn. - The second line: the token npm sends to Zaryn. Don't commit a file with a real token into a public repository; npm also reads `${NPM_TOKEN}` from the environment if you write `_authToken=${NPM_TOKEN}`. Use your Zaryn username, or the name of an organization you own or administer, as the scope. ## Publish In `package.json`, give the package a scoped name and a version: ```json { "name": "@your-username/hello", "version": "0.1.0", "main": "index.js" } ``` ```bash npm publish --access public ``` Without `--access public`, npm asks for a **private** package (that's npm's rule for scoped names), which needs Premium. To publish a fix, raise `version` and publish again; a published version can't be replaced. ## Install With the `.npmrc` lines in place, install it like any other package: ```bash npm install @your-username/hello pnpm add @your-username/hello yarn add @your-username/hello ``` ## Install straight from a Zaryn repository Any commit of a repository with a `package.json` installs without publishing: the repository's **install** tab (next to the clone commands) gives the line: ```bash npm install https://zaryn.xyz/api/v1/repos///branches/main/archive/.tar.gz ``` It pins that exact commit, in `package.json` too. ## Private packages (Premium) `npm publish` without `--access public` creates a private package; you can also switch an existing one on its page (**Make private**). Only you, or members of the organization that owns it, can see or install it, using the same `.npmrc` token. ## When something goes wrong | npm says | What it means | Fix | |---|---|---| | `E401` | no token, or a wrong one | check the `_authToken` line in `.npmrc` | | `E403` "you can only publish under your own @username…" | the scope isn't yours | use your username or your organization's name | | `E402` "Private packages are a Premium feature" | a scoped publish without `--access public` | add `--access public`, or upgrade | | `E404` when installing an unscoped package | npm asked Zaryn for a package that lives on npmjs.com | only map your scope to Zaryn, as above | | `E409` "already published" | versions can't be replaced | raise `version` | ## How it works Zaryn speaks npm's registry protocol: the package document npm reads (versions, dist-tags, dependencies) and the `.tgz` files, each with its `sha512` integrity value, which npm checks on every install. --- # Python packages (pip, uv, Poetry) Source: https://zaryn.xyz/docs/en/packages-pypi Install Python packages through Zaryn with pip, uv or Poetry, publish your own, install Python itself, and keep private packages private. One index for your projects and pypi.org, safe from look-alike packages. Every step explained. Python's installers (**pip**, **uv**, **Poetry**) download packages from an *index*. Zaryn gives you one index for everything: - **Your projects** published on Zaryn, public or private. - **Everything on pypi.org**, through Zaryn's mirror: every file is checked against the sha256 pypi.org lists before Zaryn keeps it, and pip checks it again. - **Safe from look-alikes.** A name that exists on Zaryn always comes from Zaryn, so nobody can publish a same-named package on pypi.org and sneak it into your installs (this is called *dependency confusion*). And new names on Zaryn can't be ones pypi.org already has, so nobody can do it the other way round either. The index's address: ```text https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` ## Install packages through Zaryn ### pip Once per computer: ```bash pip config set global.index-url https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` That's all: `pip install requests` now goes through Zaryn. Or for one command only: ```bash pip install --index-url https://api.zaryn.xyz/v1/packages/pypi/all/simple/ requests ``` ### uv For every project on this computer, set it in your shell start file (`~/.bashrc` or similar): ```bash export UV_DEFAULT_INDEX=https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` Or for one project, in its `pyproject.toml`: ```toml [[tool.uv.index]] name = "zaryn" url = "https://api.zaryn.xyz/v1/packages/pypi/all/simple/" default = true ``` `uv add`, `uv sync` and `uv pip install` then use Zaryn. ### Poetry ```bash poetry source add --priority=primary zaryn https://api.zaryn.xyz/v1/packages/pypi/all/simple/ ``` ### All of them at once With the `zev` command installed, `zev mirror on pip uv` writes the pip and uv settings for you, and `zev mirror off pip uv` removes them. See [Mirrors](/docs/en/package-mirrors#all-at-once-zev-mirror). ## Install Python itself (uv) uv can download Python too (`uv python install 3.13`, or automatically when a project needs it). Those downloads come from GitHub; to get them through Zaryn: ```bash export UV_PYTHON_INSTALL_MIRROR=https://api.zaryn.xyz/v1/packages/python/-/standalone uv python install 3.13 ``` Each build is checked against the release's SHA256SUMS before Zaryn keeps it, and uv checks it against the checksum it has built in. ## Publish your own package ### Build it From the folder with your `pyproject.toml`: ```bash python -m pip install build twine python -m build ``` This puts a wheel (`.whl`) and a source archive (`.tar.gz`) into `dist/`. ### Upload it Create a token on [Packages](/packages) (**Create a publish token**). Then, with twine: ```bash twine upload --repository-url https://api.zaryn.xyz/v1/packages/pypi/ \ -u __token__ -p YOUR_TOKEN dist/* ``` - `-u __token__` is literal: it tells Zaryn the password is a token. - To avoid typing it each time, put this in `~/.pypirc` and run `twine upload -r zaryn dist/*`: ```ini [distutils] index-servers = zaryn [zaryn] repository = https://api.zaryn.xyz/v1/packages/pypi/ username = __token__ password = YOUR_TOKEN ``` With uv or Poetry instead: ```bash uv publish --publish-url https://api.zaryn.xyz/v1/packages/pypi/ --username __token__ --password YOUR_TOKEN poetry config repositories.zaryn https://api.zaryn.xyz/v1/packages/pypi/ poetry publish -r zaryn --username __token__ --password YOUR_TOKEN ``` A version that's already uploaded can't be replaced: raise the version in `pyproject.toml` for a fix. ### Choosing a name A **new** name must not exist on pypi.org; Zaryn checks when you first upload. If it's taken there, pick another, for example with your team's prefix (`acme-utils`). This is what keeps the single index safe for everyone. ### Install it With the index set up as above, it's just `pip install your-package` or `uv add your-package`. Its dependencies from pypi.org come through the same index. ## Install straight from a Zaryn repository Any commit of a repository with a `pyproject.toml` (or `setup.py`) can be installed without publishing it first: open the repository, then the **install** tab next to the clone commands, and copy the line. It looks like this: ```bash pip install https://zaryn.xyz/api/v1/repos///branches/main/archive/.tar.gz ``` The address names a commit, so it always installs exactly the same code. In `pyproject.toml` the same works as a dependency: `"mytool @ https://zaryn.xyz/api/v1/repos/…/archive/.tar.gz"`. The repository must be public (or give pip your token in the address). ## Private packages (Premium) Make a package private on its page (**Make private**). Only you, or members of the organization that owns it, can see or install it. Installers then need your token, written into the index address: ```bash pip install --index-url https://__token__:$ZARYN_TOKEN@api.zaryn.xyz/v1/packages/pypi/all/simple/ your-package ``` For uv, set `UV_INDEX_ZARYN_USERNAME=__token__` and `UV_INDEX_ZARYN_PASSWORD=$ZARYN_TOKEN` (with the `zaryn` index from `pyproject.toml` above). ## When something goes wrong | You see | What it means | Fix | |---|---|---| | `403` "… is a project on pypi.org" when uploading | new names can't be ones pypi.org has | choose another name | | `403` "this token can't publish packages" | the token lacks `package:write` | create one on [Packages](/packages) | | `403` "this package name belongs to someone else" | another account uploaded that name first | choose another name | | `409` | that file was already uploaded | raise the version | | `503` "couldn't check that this name is free on pypi.org" | pypi.org didn't answer when you uploaded a new name | try again in a minute | | pip: "No matching distribution" | wrong index address, or a private package without the token | check the address ends in `/all/simple/` | | pip: "not a trusted or secure host" | the address starts with `http://` | use the `https://` address | ## How it works Every index Zaryn serves speaks both formats installers use: the classic HTML page (PEP 503) and JSON (PEP 691), whichever the installer asks for. It also gives each wheel's metadata as a separate small file (PEP 658), so pip and uv work out which versions fit without downloading whole wheels; this makes resolving noticeably faster. Files are stored by their SHA-256, which the index lists, so the installer checks every download. Names are normalized the way PyPI does it: `My_Package` and `my-package` are the same name. The addresses, if you need them separately: `/v1/packages/pypi/simple/` is only your projects on Zaryn, `/v1/packages/pypi/mirror/simple/` is only pypi.org, and `/v1/packages/pypi/all/simple/` is both. --- # Container images Source: https://zaryn.xyz/docs/en/packages-containers Push Docker or OCI images to Zaryn, pull them anywhere including Kubernetes, and store Helm charts and other OCI artifacts. Every step explained. A **container image** packs an app with everything it needs to run. Zaryn is a container registry: `docker push` and `docker pull` (and podman, buildah, nerdctl, Kubernetes) work with it directly. The registry's name is shown on [Packages](/packages) under **Docker**; on zaryn.xyz it is `zaryn.xyz`. Images are named `zaryn.xyz//:`, where `` is your username or an organization you own or administer. ## Log in (once per computer) Create a token on [Packages](/packages) (**Create a publish token**), then: ```bash echo YOUR_TOKEN | docker login zaryn.xyz -u your-username --password-stdin ``` ## Push ```bash docker build -t zaryn.xyz/your-username/app:1.0 . docker push zaryn.xyz/your-username/app:1.0 ``` - `-t` names the image: registry, owner, image name, then a *tag* after the colon (a version, or `latest`). - Layers Zaryn already has aren't uploaded again. ## Pull ```bash docker pull zaryn.xyz/your-username/app:1.0 ``` Public images need no login to pull. ## Kubernetes For a private image, give the cluster a read-only key instead of your token: create a project API key in Zaryn, then ```bash kubectl create secret docker-registry zaryn \ --docker-server=zaryn.xyz --docker-username=zaryn \ --docker-password=YOUR_PROJECT_KEY ``` and add `imagePullSecrets: [{ name: zaryn }]` to your pod spec. The key can only pull, and you can revoke it any time. ## Helm charts and other files Anything in the OCI format can be stored next to images: ```bash helm push chart-0.1.0.tgz oci://zaryn.xyz/your-username/charts oras push zaryn.xyz/your-username/model:v1 model.gguf ``` Signatures and SBOMs (from cosign and similar tools) are attached to the image they describe and shown on its page. ## Private images (Premium) On Premium, new images start private; switch any image on its page. On Free, images are public. | | Free | Premium | |---|---|---| | Largest layer | 500 MB | 10 GB | | Space (packages and images together) | 500 MB | 100 GB | ## When something goes wrong | docker says | What it means | Fix | |---|---|---| | `unauthorized` | not logged in, or the token expired | `docker login zaryn.xyz` again | | `denied` | that owner isn't you or your organization | push under your username | | a layer upload is refused for its size | the layer is over your plan's limit | make the image smaller (multi-stage builds), or upgrade | --- # Any file (release downloads) Source: https://zaryn.xyz/docs/en/packages-files Publish program downloads, archives or datasets as versioned files with a fixed address, and download them with curl. Every step explained. For things that aren't a package of any language (a compiled program for each operating system, a dataset, a firmware image), Zaryn keeps **versioned files** at addresses that never change. ## Upload Create a token on [Packages](/packages) (**Create a publish token**), then: ```bash curl -T mytool-1.0.0-linux.tar.gz -H "Authorization: Bearer $ZARYN_TOKEN" \ https://api.zaryn.xyz/v1/packages/generic/mytool/1.0.0/mytool-1.0.0-linux.tar.gz ``` The address has three parts after `generic/`: the name (`mytool`), the version (`1.0.0`) and the file name. A version can hold several files, for example one per operating system. Names, versions and file names may use letters, digits, `.`, `_`, `+` and `-`. The answer includes the file's SHA-256, so you can publish it next to the download. ## Download ```bash curl -LO https://api.zaryn.xyz/v1/packages/generic/mytool/1.0.0/mytool-1.0.0-linux.tar.gz ``` Once uploaded, a file never changes: the same address always gives the same bytes. To fix something, upload a new version. > Publishing a **Zig** package? Use [Zig packages](/docs/en/packages-zig) instead: Zaryn then reads its `build.zig.zon` and gives you the hash `zig fetch` expects. ## Private files (Premium) Make the name private on its page. Downloads then need the token: ```bash curl -LO -H "Authorization: Bearer $ZARYN_TOKEN" https://api.zaryn.xyz/v1/packages/generic/mytool/1.0.0/mytool-1.0.0-linux.tar.gz ``` ## When something goes wrong | You see | What it means | Fix | |---|---|---| | `409` "this version is already published" | that file name already exists in that version | upload as a new version | | `403` "this package name belongs to someone else" | another account uses that name | choose another name | | `402` | over your plan's file size (50 MB on Free) or space | upgrade, or split the file | --- # What Zaryn can do Source: https://zaryn.xyz/docs/en/what-zaryn-can-do Every Zaryn service in plain words, where to find it on the site, what's free, and the guide that shows you how. Start here if you're new. **Zaryn** ([zaryn.xyz](https://zaryn.xyz)) is a website for keeping your work online, sharing it and working on it with other people. **zev** is the program on your computer that saves versions of your project and sends them to Zaryn. You can do a lot from the website alone; zev is there when you want more. Each section below is one thing Zaryn does: what it's for, where it is on the site, and where to read more. ## Keep a project online, with every version A **repository** is a folder for one project (code, a thesis, a dataset, a website) that remembers every version you save. You can see what changed and go back to any earlier version. - **Where:** [Repos](/repos) in the top menu, then **New repository**. - **From the website:** open the repository and press **Upload** to add a file. Nothing to install. - **From your computer:** install zev and push a whole folder at once. [Quick start](/docs/en/quickstart) walks you through it in about five minutes. - **Free:** unlimited public repositories, 5 private ones, 2 GB in total, files up to 250 MB. > **Public or private?** Anyone can see a public repository. A private one only you and the people you invite can see, and it can also be [encrypted](/docs/en/encrypted-repositories) so not even Zaryn can read it. ## Share a file with a link Upload a file, get a link, send it to anyone. They don't need an account. - **Where:** [Storage](/storage) in the top menu. - **Free:** 500 MB, up to 50 files. - **Guide:** [Storing and sharing files](/docs/en/storing-files). These files are public, so read the warning there before you upload. The same page shows how much space your repositories, files and packages use. ## Work with other people - **Invite someone** to a repository: open it, then **Collaborators**. - **Report a problem or suggest an idea** with an **issue** (the **Issues** tab on a repository). - **Propose a change** and ask for a review with a **pull request**: the owner reads it, comments and merges it when it's ready. - **Work as a team** under one name with an **organization**: [Repos](/repos), then **New organization**. - **Talk privately:** [Messages](/messages). **Guides:** [How do I…?](/docs/en/how-do-i) (the "Share and work together" part) and [Collaboration from the Terminal](/docs/en/cli-collaboration). ## Publish a package If you write a library, Zaryn hosts it for the tools you already use: npm, PyPI, Cargo, Zig, container images, or any file. - **Where:** [Packages](/packages). The page shows the exact command for each tool. - **Free:** 500 MB. - **Zig:** Zaryn reads your `build.zig.zon` and gives you the exact hash `zig fetch` will compute; any repository commit works as a dependency too. - **crates.io or GitHub slow?** cargo and zig can download through Zaryn's [mirrors](/docs/en/package-mirrors), checked against the hashes they already know. **Guides:** [Packages, explained](/docs/en/packages), then the one for your tool. ## Test your project on every push (CI) CI builds and tests your project automatically each time you send new work, so you hear about a broken change right away. ```bash zev ci enable zev ci status ``` - **Free:** 400 minutes a month. - **Guides:** [zev ci](/docs/en/commands#zev-ci); how it skips work it has already done is in [Memoized CI](/docs/en/memoized-ci). ## Know when something you use is unsafe Zaryn tracks security problems (**advisories**) in libraries and tells you when one reaches your project. A repository's **Security scan** tab checks it on demand. - **Where:** [Advisories](/advisories), and the **Security scan** tab on each repository. - **Free:** yes. Only the live graph of who's affected is Premium. - **Guide:** [Advisories and lineage](/docs/en/advisories). ## Reach Zaryn when the internet is filtered `zev proxy` sends zev's traffic through a proxy server you already have (VLESS, VMess, Trojan, Shadowsocks, Hysteria2 and more), and `zev proxy doctor` finds out what's being blocked and how to get around it. - **Free:** on every plan. Zaryn carries none of this traffic. - **Guide:** [Using zev through a proxy](/docs/en/proxy). ## Connect your devices privately (Premium) A **private network** joins your laptop, servers and teammates' machines so they can reach each other directly and encrypted, wherever they are. - **Where:** [Network](/network). - **Guide:** [Private networks](/docs/en/private-networks). ## Let an app, CI or AI agent use Zaryn A **project** holds API keys for a program that calls Zaryn: each key has its own permissions, limits and usage numbers. Hosted AI models are part of Premium. - **Where:** [Projects](/projects). - **Free:** 50,000 API requests a month, up to 60 a minute. - **Guide:** [Scripting and AI Agents](/docs/en/automation-and-agents). ## Plans and paying Everything above has a Free plan; **Premium** raises the limits and adds private networks, hosted AI and more. You top up Zaryn credits with USDC, and credits pay for Premium. - **Where:** [Billing](/billing), which also shows what you've used. - **Guide:** [Billing and Zaryn credits](/docs/en/billing-and-credits). ## Still not sure where to go? - Press `/` on any docs page and type what you want to do, in your own words: "share a file", "undo", "invite someone". - [How do I…?](/docs/en/how-do-i) has short answers to the most common tasks. - [When something goes wrong](/docs/en/troubleshooting) explains error messages. - Still stuck? [Contact us](/contact). --- # Quick start Source: https://zaryn.xyz/docs/en/quickstart From nothing to your first project on Zaryn in about five minutes. Every command is explained as you go. This page takes you from nothing to a project saved on your computer and shared on Zaryn. You don't need to know git or any other version control tool. Each step says what the command does and why. > **What is version control?** It is a tool that remembers every saved version of your project. You can see what changed, go back to an older version, try ideas on the side without breaking anything, and work with other people on the same files. zev is the version control tool, and Zaryn is the website where your projects live online. ## 1. Install zev On **Linux or macOS**, open a terminal and run: ```bash curl -fsSL https://zaryn.xyz/install.sh | sh ``` On **Windows**, open PowerShell and run: ```powershell irm https://zaryn.xyz/install.ps1 | iex ``` Check that it worked: ```bash zev --version ``` You should see something like `zev 0.3.0 (x86_64-linux)`. More options, such as apt, dnf or pacman, are on the [Installation](/docs/en/installation) page. ## 2. Make a project Go to the folder of your project (or make a new one) and turn it into a zev repository: ```bash mkdir my-project cd my-project zev init ``` `zev init` creates a hidden `.zev` folder. That is where zev keeps the history. Your own files stay exactly as they are. Tell zev who you are. Your name goes on every commit you make: ```bash zev config set user.name "Your Name" zev config set user.email "you@example.com" ``` ## 3. Save your first version Create a file, or use the files you already have: ```bash echo "# My project" > README.md ``` Saving a version takes two steps: ```bash zev add . zev commit -m "First version" ``` - `zev add .` picks **what** goes into the next save. The `.` means "everything in this folder". This is called *staging*. - `zev commit -m "..."` **saves** what you staged, with a short message about what you did. Each save is called a *commit*. Why two steps? Because you often change many files but want to save only some of them together. `zev add` lets you choose. ## 4. Change something and see the difference Edit `README.md`, then ask zev what changed: ```bash zev status ``` `zev status` lists the files you changed, the files you staged, and new files zev doesn't track yet. Each section of its output also says which command to run next. To see the exact lines that changed: ```bash zev diff ``` Lines starting with `+` were added and lines starting with `-` were removed. When you're happy, save again: ```bash zev add README.md zev commit -m "Describe the project" ``` See all your saves so far: ```bash zev log --oneline ``` ## 5. Share it on Zaryn Create your account from the terminal. zev emails you a 6-digit code to confirm your address: ```bash zev login zaryn.xyz --register your-username --email you@example.com ``` Type the code when zev asks for it. You sign in once per computer; every project on it uses the same sign-in. Already made an account on the [zaryn.xyz](https://zaryn.xyz) website? Then sign in with your browser instead: ```bash zev login zaryn.xyz --device ``` zev prints a link and a short code. Open the link, check the code matches, and approve. Now create the project on Zaryn and send your commits there: ```bash zev new zev push ``` `zev new` asks for a name, the kind of project, public or private, and a license. It creates the repository on Zaryn and remembers it as `origin`, the default place to push to. `zev push` sends your commits. Open `https://zaryn.xyz/your-username/the-name` to see them. ## The everyday loop Most days, you only need these five commands: ```bash zev status # what changed? zev diff # how exactly? zev add . # choose what to save zev commit -m "what you did" # save it zev push # share it ``` When you work with others, run `zev pull` first to get their latest changes. ## Where to go next - [Your first repository, step by step](/docs/en/first-repository): the same ideas in more depth, including undoing mistakes. - [How do I…?](/docs/en/how-do-i): short answers for common tasks ("undo a change", "delete a file", "work on a branch"). - [All commands](/docs/en/commands): every zev command, with the everyday ones first. - Stuck? See [When something goes wrong](/docs/en/troubleshooting), or press `/` on any docs page to search. --- # Why zev exists Source: https://zaryn.xyz/docs/en/why-zev The problems zev was built to solve, and how it differs from git. zev exists to answer a specific set of questions directly: how large files and models should actually be stored and synced, what a diff should tell you about code that changed structurally, why CI so often re-does work it already did, and how to track a model's full lineage from raw data through every experiment to a published result — all inside one engine, addressed by content hashes throughout. ## Large files change the economics of syncing Treating every file as an opaque blob means a single byte changed in a large file forces a full re-transfer of that file. For source code this is rarely a problem — most edits are small and the files themselves are small. For large text, data, or model files it becomes expensive fast. zev's content-defined chunking addresses this directly. When a file is chunked, an edit near the start of a 1.7 MB file was measured, on real data, to require re-transferring only about 1% of the file's total chunks — the rest were already present on both sides and were skipped entirely, both on push and on pull. This is described in full, with the actual measurements, in [Content-defined chunking](/docs/en/chunking). ## A text diff doesn't tell you what actually changed Line-based diffs show which lines changed. They don't tell you that a function was renamed rather than deleted and a different one added, or that only a function's signature changed while its body stayed identical. A human reading the diff can often infer this, but an automated tool cannot, not reliably. zev's semantic diff parses Zig source with a real AST parser and reports structural changes directly: `signature_changed`, `body_changed`, `likely_rename`, `added`, `removed` — computed from the actual parsed structure of the code, not guessed from text patterns. See [Semantic (AST) diffing](/docs/en/semantic-diff). ## CI time is dominated by unchanged work Most CI runs re-execute steps whose inputs — the exact source content, the container image, the command — are identical to a previous, already-successful run. zev's CI can detect this and skip the step entirely, serving the previous result instead of re-running Docker. In a real, measured test this took step execution from 0.53 seconds (a genuine run) to 0.01 seconds (served from cache) for an unchanged step. See [Memoized CI](/docs/en/memoized-ci). ## A model's history is more than its commits An ML model's real history includes the dataset it was trained on, the shard split it used, every experiment that shaped its architecture, and every checkpoint merge that combined it with another run. zev tracks all of this as first-class, content-addressed data: `zev dataset` and `zev lineage` for provenance, `zev experiment` for hypotheses and outcomes, `zev drift` and `zev threshold` for catching regressions automatically, and `zev merge-weights` for combining checkpoints with real tensor-level strategies (averaging, weighted interpolation, SLERP, TIES-merging) — not just merging text files that happen to contain numbers. ## Built to grow into more than version control zev's object model, content addressing, and IPLD-based provenance graph were designed as a general-purpose foundation, not a fixed feature set. `zev context` already tracks which changes came from a human and which came from an AI model, with what prompt; `zev notarize` anchors results on-chain; `zev fedmerge` merges work peer-to-peer with no central server. Each of these was added on top of the same engine that stores your first commit — the intent is for that pattern to continue, as an engine for code, data, and AI-driven work generally, not a version control system with extras attached. --- # Installation Source: https://zaryn.xyz/docs/en/installation Install zev on Linux, macOS or Windows with one command, or from your package manager. Then keep it updated. zev is a single program with nothing else to install. It runs on Linux, macOS and Windows, on both Intel/AMD (x86-64) and ARM (Apple silicon, Graviton, Snapdragon) machines. ## Quick install **Linux and macOS** ```bash curl -fsSL https://zaryn.xyz/install.sh | sh ``` On Debian, Ubuntu, Fedora, RHEL, openSUSE and Arch, this adds Zaryn's signed package repository and installs the `zev` package, so your system's normal updates keep zev current. On macOS and other Linux systems, it installs the signed `zev` binary in `/usr/local/bin`. **Windows** (PowerShell) ```powershell irm https://zaryn.xyz/install.ps1 | iex ``` This installs `zev.exe` for your user in `%LOCALAPPDATA%\Programs\zev` and adds it to your `PATH`. No administrator rights are needed. It also places `wintun.dll`, WireGuard's signed network driver, beside `zev.exe` for private networks. Then check it: ```bash zev --version ``` ## With your package manager If you'd rather set it up yourself, these are the same steps the installer takes. **Debian, Ubuntu** (apt) ```bash sudo curl -fsSLo /usr/share/keyrings/zaryn.gpg https://zaryn.xyz/dl/zaryn.gpg echo "deb [signed-by=/usr/share/keyrings/zaryn.gpg] https://zaryn.xyz/dl/apt stable main" | sudo tee /etc/apt/sources.list.d/zaryn.list sudo apt update && sudo apt install zev ``` **Fedora, RHEL, Rocky, Alma** (dnf) ```bash sudo rpm --import https://zaryn.xyz/dl/zaryn.asc sudo curl -fsSLo /etc/yum.repos.d/zaryn.repo https://zaryn.xyz/dl/rpm/zaryn.repo sudo dnf install zev ``` **openSUSE** (zypper) ```bash sudo rpm --import https://zaryn.xyz/dl/zaryn.asc sudo zypper addrepo https://zaryn.xyz/dl/rpm/zaryn.repo sudo zypper install zev ``` **Arch Linux** (pacman) ```bash curl -fsSL https://zaryn.xyz/dl/zaryn.gpg | sudo pacman-key --add - sudo pacman-key --lsign-key 7C2B21CBA73569E5C83C6A945F2C0C446C4997EB printf '\n[zaryn]\nServer = https://zaryn.xyz/dl/arch/$arch\n' | sudo tee -a /etc/pacman.conf sudo pacman -Sy zev ``` **Windows** (Scoop) ```powershell scoop install https://zaryn.xyz/dl/scoop/zev.json ``` **Any system, by hand.** Every release is at `https://zaryn.xyz/dl/zev//`. It holds the binaries (`zev-x86_64-linux`, `zev-aarch64-macos`, `zev-x86_64-windows.exe`, and so on), archives, packages, and a `SHA256SUMS` file. The Linux binaries are fully static, so they run on any distribution, including Alpine. ## Updating - **Installed from a package repository:** zev updates with the rest of your system (`apt upgrade`, `dnf upgrade`, `zypper update`, `pacman -Syu`, `scoop update`). - **Installed as a binary:** run `zev self update`, or `zev self update --check` to only look. `zev self update` installs a release only if all of these hold: - it's signed with zev's release key, which is built into zev; - the signature names that exact file and version; - it's newer than what you have, unless you ask for a version with `--to`; - the new binary starts. If zev came from a package manager, `zev self update` doesn't touch it; it tells you which command to use instead. ## Verifying downloads Releases are signed with [minisign](https://jedisct1.github.io/minisign/), the same scheme Zig uses for its releases. zev's release key is: ``` RWQgi1EYwzJgSHlVF5QFI0E4ZaDNfUqL2u9im7SP34VVRCaR60jIUISL ``` To check a file yourself: ```bash minisign -Vm zev-x86_64-linux -P RWQgi1EYwzJgSHlVF5QFI0E4ZaDNfUqL2u9im7SP34VVRCaR60jIUISL ``` The package repositories are signed with the OpenPGP key `7C2B 21CB A735 69E5 C83C 6A94 5F2C 0C44 6C49 97EB` ("Zaryn Packages"). Your package manager checks every package against it, and `install.sh` checks the key itself before trusting it. ## Uninstalling ```bash zev self uninstall ``` If zev came from a package manager, `zev self uninstall` names the command to use instead, for example `sudo apt remove zev`. Your repositories and settings in `~/.zev` stay. To leave a private network first, run `zev net down --forget`. ## Source code and building from source zev's source lives on Zaryn, in the public repository [zaryn/zev](https://zaryn.xyz/zaryn/zev): browse it there, or fetch it with zev itself. Building needs only the Zig compiler (the 0.17 development series); zstd is included in the source. ```bash curl -fsSL https://zaryn.xyz/install.sh | sh # zev, to fetch its own source zev clone zaryn/zev cd zev zig build -Doptimize=ReleaseSafe ``` The binary is at `zig-out/bin/zev`. `zig build check-ports` compiles zev for every platform it ships for, from any machine. ### The server (optional, for self-hosting) ```bash cd zev-api zig build ``` `zev-api` reads its configuration from environment variables, including the database connection and a server identity keypair. The keypair is generated on first run if none exists. You only need your own server if you aren't using a hosted one. --- # Your first repository, step by step Source: https://zaryn.xyz/docs/en/first-repository Create a repository, save versions, look at history, and undo mistakes, with every idea explained. This guide builds a small project from scratch. Along the way you'll learn the four ideas everything else in zev is built on: the **working folder**, the **staging area**, **commits**, and **history**. If you haven't installed zev yet, start with [Installation](/docs/en/installation). ## Create the repository ```bash mkdir notes cd notes zev init ``` ```text Initialized empty Zev repository in ./.zev/ ``` A *repository* (or *repo*) is a folder whose history zev keeps. All of that history lives in the hidden `.zev` folder. Don't edit it by hand; if you delete it, the folder becomes a normal folder again and the history is gone. Set your name and email once per project. They go on every commit you make: ```bash zev config set user.name "Sara Ahmadi" zev config set user.email "sara@example.com" ``` ## The three places your work lives It helps to picture three places: | Place | What it is | How things get there | |---|---|---| | **Working folder** | Your files, as you see them in your editor | You edit them | | **Staging area** | The changes you've picked for the next commit | `zev add` | | **History** | Every commit you've made, saved for good | `zev commit` | Nothing reaches history by accident. You choose what to stage, and then you commit it. ## Make your first commit Create two files: ```bash echo "Buy milk" > todo.txt echo "Ideas for the project" > ideas.txt ``` Ask zev what it sees: ```bash zev status ``` ```text On branch main Untracked files: (zev add to start tracking; list in .zevignore to hide) ideas.txt todo.txt ``` *Untracked* means zev sees the files but isn't keeping their history yet. Stage both and commit: ```bash zev add . zev commit -m "Start my notes" ``` ```text added ideas.txt added todo.txt Staged 2 change(s). Next: zev commit -m "what you changed" Created commit: 5f7f5e226bb19014179575681efba0f8be95eb6a8e64c1fc7dbc6f4d68224d01 Committed 2 file(s) ``` That long string is the commit's **ID**. It is a fingerprint (a hash) of everything in the commit, so it can never be confused with another commit. You only ever need to type its first few characters, for example `5f7f5e22`. **Good commit messages** say what changed and why, in a few words: "Fix login when the password has spaces" is much more useful later than "fix". ## Look at what changed Change one file and add a new one: ```bash echo "Buy bread" >> todo.txt echo "Call Ali" > calls.txt zev status ``` ```text On branch main Changes not staged for commit: (zev add to include them; zev restore to throw them away) modified: todo.txt Untracked files: (zev add to start tracking; list in .zevignore to hide) calls.txt ``` See the changed lines: ```bash zev diff ``` ```text modified: todo.txt @@ -1,1 +1,2 @@ Buy milk +Buy bread ``` `+` is a line that was added and `-` a line that was removed. The `@@ -1,1 +1,2 @@` line tells you where in the file the change is: old file from line 1 (1 line), new file from line 1 (2 lines). You can ignore it at first. Now commit only `todo.txt`, and leave `calls.txt` for later: ```bash zev add todo.txt zev diff --staged zev commit -m "Add bread to the list" ``` `zev diff --staged` shows exactly what the next commit will contain. It's a good habit to check it before committing. ## Read the history ```bash zev log ``` ```text commit 8a41c2d0… Author: Sara Ahmadi Date: 2026-10-04 09:25 UTC Add bread to the list commit 5f7f5e22… Author: Sara Ahmadi Date: 2026-10-04 09:20 UTC Start my notes ``` The newest commit is on top. A shorter view, one line per commit: ```bash zev log --oneline ``` To see one commit and exactly what it changed: ```bash zev show 5f7f5e22 # by the start of its ID zev show HEAD # the newest commit zev show HEAD~1 # the one before it ``` `HEAD` means "the commit you're on now". `HEAD~1` is one before it, `HEAD~2` two before, and so on. ## Undo things Everyone makes mistakes. Here's how to get out of the common ones. **Throw away changes you haven't staged** (go back to the last commit's version of a file): ```bash zev restore todo.txt ``` Be careful: the changes you throw away are gone for good, because they were never committed. **Unstage a file** (keep your edits, but take the file out of the next commit): ```bash zev restore --staged todo.txt ``` **Put changes aside for a moment** (for example, to look at something else with a clean folder): ```bash zev stash zev stash pop # bring them back ``` **Bring back a file you deleted by mistake** (if it was committed before): ```bash zev restore calls.txt ``` More situations, such as deleting and renaming files, are in [How do I…?](/docs/en/how-do-i). ## Delete or rename a file To delete a file and record that in the next commit: ```bash zev rm ideas.txt zev commit -m "Remove ideas" ``` Deleting the file any other way works too. Then `zev add ideas.txt` (or `zev add .`) stages the deletion. To rename, rename the file normally and stage both names: ```bash mv calls.txt phone.txt zev add calls.txt phone.txt zev commit -m "Rename calls to phone" ``` ## Keep some files out Build output, logs and secrets don't belong in history. List them in a file called `.zevignore` in the top folder of the project: ```text # .zevignore node_modules/ build/ *.log .env ``` Ignored files don't show up in `zev status`, and `zev add .` skips them. Commit `.zevignore` itself so everyone working on the project ignores the same files. ## What's next - [Branches and merging](/docs/en/branches): try ideas without touching your main work. - [Share your work on Zaryn](/docs/en/pushing-and-pulling): push, pull and clone. - [All commands](/docs/en/commands): the full reference. --- # Share your work on Zaryn Source: https://zaryn.xyz/docs/en/pushing-and-pulling Sign in, put a project on Zaryn, clone someone else's, and keep everyone in sync with push and pull. Your commits live on your computer until you **push** them. Pushing sends them to Zaryn, where others can see them, clone the project, and send their own work back. **Pull** brings their new commits to you. ## Sign in (once per computer) **New to Zaryn?** Create an account from inside any zev project folder: ```bash zev login zaryn.xyz --register your-username --email you@example.com ``` zev emails you a 6-digit code. Type it when asked. If you closed the terminal before the code arrived, finish later with: ```bash zev login zaryn.xyz --register your-username --code 123456 ``` **Already have an account** (made on the website)? Sign in through your browser: ```bash zev login zaryn.xyz --device ``` zev prints a link and a code. Open the link, check that the code matches, choose what this computer may do, and approve. Check who you are signed in as, or sign out: ```bash zev whoami zev logout ``` Your sign-in is saved in `~/.config/zev/credentials`, readable only by you. Every zev command uses it, so you never paste tokens. ## Put a project on Zaryn From your project folder: ```bash zev new ``` ```text Repository name: notes What kind of repository is this? 1) code 2) model 3) dataset 4) agent 5) topology Visibility? 1) public 2) private License? 1) MIT 2) Apache-2.0 3) GPL-3.0 4) BSD-3-Clause 5) Unlicense 6) None ``` `zev new` creates the repository on Zaryn and saves its address as a **remote** called `origin`. Then send your commits: ```bash zev push ``` With nothing after it, `zev push` sends the branch you're on to `origin`. Your project is now at `https://zaryn.xyz/your-username/notes`. ## Get a copy of a project (clone) ```bash zev clone someone/their-project cd their-project ``` `zev clone` makes a folder named after the project, downloads its full history, puts the files in place, and sets `origin` to where it came from. Add a folder name to put it somewhere else, or `--branch` to start on another branch: ```bash zev clone someone/their-project my-copy --branch dev ``` Every repository page on Zaryn shows its clone command, ready to copy. Clones and pulls download in batches: a few requests carry the whole history (four at a time for large repositories), and every file is checked against its hash before it's kept. Large files come in chunks, and a later pull downloads only the chunks that changed. Private repositories need you to be signed in with access to them. ## Stay up to date (pull) ```bash zev pull ``` `zev pull` downloads new commits on your branch from `origin` and updates your files to match. zev never overwrites work you haven't committed. If a file you've changed would be replaced, `zev pull` changes no files and tells you which file is in the way. The new commits are still saved, so nothing is lost. Commit or stash your changes, then run `zev checkout ` to bring your files up to date. ## The team routine When several people work on one project, this order avoids most trouble: ```bash zev pull # 1. get everyone's latest work # ...edit files... zev add . zev commit -m "What you did" # 2. save your work zev pull # 3. get anything new since step 1 zev push # 4. share ``` If someone else pushed while you were working, pull before you push (step 3): `zev pull` brings their commits in and updates your files, and then your push goes on top of them. For bigger changes, work on a [branch](/docs/en/branches) and open a pull request with `zev pr`, so teammates can review before it goes into `main`. ## Remotes A *remote* is a named address of another copy of the repository. `zev new` and `zev clone` set up `origin` for you. To see or change remotes: ```bash zev remote # list them zev remote add upstream team/project zev remote show upstream zev remote remove upstream ``` Push or pull a particular remote and branch by naming them: ```bash zev push upstream feature-x zev pull upstream main ``` ### Addresses | Address | Means | |---|---| | `owner/repo` | a repository on Zaryn | | `owner/repo@dev` | ... on its `dev` branch | | `https://zaryn.xyz/owner/repo` | the link from your browser: any page of the repository works, and `?branch=` is kept | | `example.com/owner/repo` | a repository on another zev server, by its website | | `localhost:8090/owner/repo` | a zev server of your own (a port means plain HTTP) | | `file:///home/me/backup` | another folder on this computer | | `ipfs://` | a published snapshot on IPFS | `zev push`, `zev pull` and `zev clone` work with all of them. (SSH addresses are not supported yet.) ## Servers, CI and AI agents Machines without a person at the keyboard can't type an email code. Use the device flow, which you approve in your browser, and give the token only the permissions it needs: ```bash zev login zaryn.xyz --device --client "build server" ``` Or put a token in the `ZEV_TOKEN` environment variable (and the server in `ZEV_SERVER`). Settings → AI agents and tokens on Zaryn lists every token and lets you revoke one at any time. See [Scripting and AI agents](/docs/en/automation-and-agents). --- # Words you'll see Source: https://zaryn.xyz/docs/en/glossary Plain explanations of the words used in zev, Zaryn and these docs, from A to Z. ### Branch A named line of commits. Repositories start with `main`. You make branches to work on something separately and [merge](#merge) it back later. See [Branches and merging](/docs/en/branches). ### CI Continuous integration: a server that builds and tests your project automatically whenever you push. Turn it on with `zev ci enable`. ### CID Content identifier: an ID computed from an object's content (its [hash](#hash)), in the format IPFS uses. The same content always has the same CID. ### Clone A full copy of a repository, history included, on your computer. Made with `zev clone`. ### Commit A saved version of your project: the staged changes, plus your name, the time and a message. Each commit points to the one before it, which is what makes the [history](#history). Made with `zev commit`. ### Conflict When two branches changed the same lines of a file, so zev can't combine them by itself. You decide what the lines should be. See [When both changed the same lines](/docs/en/branches#when-both-changed-the-same-lines). ### Diff The difference between two versions of a file: lines added (`+`) and removed (`-`). Shown by `zev diff`. ### Fork Your own copy of someone else's repository on Zaryn. You change it freely, and can send changes back with a [pull request](#pull-request). Made with `zev fork-repo`. ### Hash A short fingerprint computed from data. Change one byte and the hash changes completely. zev identifies every file, folder and commit by its hash (BLAKE3), which is why commit IDs look like `5f7f5e22…`. ### HEAD The commit you're on now: the newest commit of your current branch. `HEAD~1` is the one before it, `HEAD~2` the one before that. ### History All the commits of a branch, newest to oldest. See it with `zev log`. ### Ignore Telling zev not to track some files (build output, logs, secrets) by listing them in a `.zevignore` file. ### Issue A bug report, idea or task, attached to a repository on Zaryn. `zev issue` opens one. ### Merge Bringing the commits of one branch into another. `zev merge `. ### Origin The usual name of the remote your project came from or was published to. `zev new` and `zev clone` set it up, and `zev push`/`zev pull` use it when you don't name another. ### Pull Getting new commits from a remote and updating your files. `zev pull`. ### Pull request A request to merge one branch into another, usually with a review first. Opened with `zev pr` or on Zaryn's website. ### Push Sending your commits to a remote, such as Zaryn. `zev push`. ### Remote A named address of another copy of the repository, such as `origin` on Zaryn. `zev remote` lists them. ### Repository A project whose history zev keeps: your files plus the `.zev` folder. Often shortened to *repo*. ### Restore Putting a file back the way it was in the last commit (throwing away your edits), or taking it out of the staging area with `--staged`. `zev restore`. ### Stage, staging area Picking changes for the next commit. The staging area is the list of changes you've picked. `zev add` stages, `zev restore --staged` unstages. ### Stash A place to put uncommitted changes aside for a moment, leaving a clean folder. `zev stash`, then `zev stash pop` to bring them back. ### Tag A fixed name for one commit, usually a release such as `v1.0`. `zev tag`. ### Token A long secret that lets a program act on your Zaryn account, like a password just for it. `zev login` makes and saves one for you. You can see and revoke tokens in Settings → AI agents and tokens. ### Tracked file A file zev keeps the history of: it's in a commit or staged. New files are *untracked* until you `zev add` them. ### Working folder Your project's files as they are on disk right now, including changes you haven't staged or committed. ### Zaryn The website at [zaryn.xyz](https://zaryn.xyz) where repositories live online, with issues, pull requests, CI and more. zev is the tool on your computer; Zaryn is the place you share to. ### zev The command-line tool: version control for code, data and models. ### .zevignore The file that lists what zev should ignore. See [Ignore files](/docs/en/how-do-i#ignore-files-build-output-logs-secrets). --- # How do I…? Source: https://zaryn.xyz/docs/en/how-do-i Short answers to the things people most often need to do. Find yours in the list on the right, or press / to search. ## Start ### Start version control in a folder I already have ```bash cd my-folder zev init zev add . zev commit -m "First version" ``` ### Get a project from Zaryn onto my computer ```bash zev clone owner/project ``` The repository page on Zaryn shows this command with the right address. ### Put my project on Zaryn ```bash zev login zaryn.xyz --register your-name --email you@example.com # once per computer zev new zev push ``` ## Save and look ### See what I changed ```bash zev status # which files zev diff # which lines ``` ### Save only some of my changes Stage just those files, then commit: ```bash zev add src/login.js src/login.css zev commit -m "Fix the login form" ``` Everything else stays changed but uncommitted. ### Check what I'm about to commit ```bash zev diff --staged ``` ### See the history of the project ```bash zev log --oneline ``` ### See what one commit changed ```bash zev show 47bec4f5 ``` ### Find who changed a line, and when ```bash zev blame path/to/file ``` Each line shows the commit and author that last changed it. Then `zev show ` shows the whole change. ## Undo ### Throw away my changes to a file ```bash zev restore path/to/file ``` The file goes back to how it was in the last commit. Those edits are gone for good, so stash them first if you're not sure. ### Throw away all my uncommitted changes ```bash zev restore . ``` New files that were never added stay; delete them yourself if you don't want them. ### Unstage a file (I added it by mistake) ```bash zev restore --staged path/to/file ``` Your edits stay in the file; it just won't be in the next commit. ### Put my changes aside for a moment ```bash zev stash save "what I was doing" # ...do something else, switch branches, pull... zev stash pop ``` ### Bring back a file I deleted If it was in the last commit: ```bash zev restore path/to/file ``` ### Look at an old version of the project zev can't switch your folder to an old commit yet, but you can look at any commit without changing your files: ```bash zev show # what that commit changed zev diff HEAD -- file # how a file differs between then and now ``` ### Undo a commit I already made zev doesn't rewrite commits you've made. Make a new commit that undoes it: restore the files as you want them, then commit. `zev diff ~1 ` shows exactly what that commit changed, so you know what to undo. ## Files ### Delete a file ```bash zev rm path/to/file zev commit -m "Remove the old file" ``` Or delete it however you like, then `zev add path/to/file` (or `zev add .`) to stage the deletion. ### Rename or move a file Rename it normally, then stage both the old and the new name: ```bash mv old-name.txt new-name.txt zev add old-name.txt new-name.txt zev commit -m "Rename old-name to new-name" ``` `zev add .` stages both at once too. ### Stop tracking a file but keep it For example, a settings file with passwords that you committed by mistake: ```bash zev rm --cached .env echo ".env" >> .zevignore zev add .zevignore zev commit -m "Stop tracking .env" ``` If it held real secrets and you already pushed, change those secrets: they are still in the history. ### Ignore files (build output, logs, secrets) Create a `.zevignore` file in the top folder of the project, one pattern per line: ```text node_modules/ dist/ *.log .env ``` `zev status` and `zev add .` skip ignored files. Commit `.zevignore` so your teammates ignore the same files. `zev new` writes a sensible one for the main language you pick. ## Branches ### Work on something without touching main ```bash zev checkout -b my-feature ``` Commit as usual; `main` doesn't change until you merge. ### Switch branches when I have unfinished changes ```bash zev stash zev checkout other-branch # ...later... zev checkout my-feature zev stash pop ``` ### Bring my branch into main ```bash zev checkout main zev merge my-feature ``` ### Fix a merge conflict ```bash zev merge my-feature --resolve # edit the files it lists: keep what you want between <<<<<<< and >>>>>>>, delete the markers zev add . zev merge --continue ``` Full walk-through: [When both changed the same lines](/docs/en/branches#when-both-changed-the-same-lines). ### Mark a release ```bash zev tag v1.0 ``` ## Share and work together ### Get my teammates' latest changes ```bash zev pull ``` ### Send my commits ```bash zev push ``` ### Ask for a review before merging ```bash zev checkout -b fix-header zev commit -m "Fix the header on phones" zev push zev pr ``` ### Contribute to a project I can't push to ```bash zev fork-repo owner/project --clone cd project # ...commit your change... zev push zev pr ``` ### Report a bug or suggest an idea ```bash zev issue --title "Search ignores accents" --desc "Searching café doesn't find cafe" ``` Or open an issue on the repository's page on Zaryn. ### Send someone a file with a link Open **Storage** in the top menu, drop the file on **Upload a file**, then press **Copy link**. Anyone with the link can open it, so only share files that aren't private. More in [Storing and sharing files](/docs/en/storing-files). ### Delete a repository Open the repository and press **⚙ Settings** (for a topology repository, on its network overview). At the bottom, under **Danger zone**, type the repository's name and press **Delete this repository**. Its history, branches, pull requests, issues and every file stored for it are removed, and it can't be undone. Its owner can do this, and so can an owner or admin of its organization. ### See how much space I have left The bars at the top of **Storage** show repositories, files and packages against your plan. ## zev itself ### Update zev ```bash zev self update ``` If you installed it with apt, dnf, zypper or pacman, your system's normal update does it (`zev self update` tells you the command). ### Find a command I've forgotten ```bash zev help zev help stash ``` Or see [All commands](/docs/en/commands). ### Use zev on a server, in CI, or from an AI agent See [Scripting and AI agents](/docs/en/automation-and-agents). --- # Branches and merging Source: https://zaryn.xyz/docs/en/branches Work on new ideas without touching your main code, then bring them back in. Includes fixing merge conflicts, step by step. ## What a branch is A branch is a line of commits with a name. Every repository starts with one branch, `main`. When you make a new branch, it starts at the commit you're on, and from then on its commits are separate from `main`'s. That makes branches the safe way to try things: - work on a new feature without breaking `main` - fix a bug while a half-done feature waits on another branch - let a teammate review your work in a pull request before it goes into `main` ```text main: A ── B ── C \ new-search: D ── E ``` Here `new-search` started at `C` and has two commits of its own. `main` doesn't have `D` or `E` until you merge. ## Make a branch and switch to it ```bash zev checkout -b new-search ``` This makes the branch `new-search` at the current commit and switches to it. Any uncommitted changes come with you. Now commit as usual; the commits go on `new-search`: ```bash zev add . zev commit -m "Search box, first version" ``` See all branches; the one marked `*` is where you are: ```bash zev branch ``` ```text main * new-search ``` ## Switch between branches ```bash zev checkout main ``` zev changes your files to match the branch: files that only exist on the other branch disappear, and come back when you switch back. Nothing is lost; it's all in the history. If you have uncommitted changes that switching would overwrite, zev stops and tells you which file. You have three choices: ```bash zev commit -m "Work in progress" # 1. commit them on this branch zev stash # 2. put them aside (zev stash pop later) zev checkout --force main # 3. throw them away ``` ## Bring a branch into main (merge) When the work on `new-search` is ready, go to `main` and merge: ```bash zev checkout main zev merge new-search ``` If `main` hasn't changed since the branch started, zev simply moves `main` forward to include the branch's commits (a *fast-forward*). If both have new commits, zev combines them, file by file and line by line. When the two changed different lines, this just works. On a team, the usual way is a pull request instead: push the branch and run `zev pr`, so others can review it first. See [Collaboration from the terminal](/docs/en/cli-collaboration). ## When both changed the same lines If `main` and your branch changed the same lines of a file, zev can't know which version you want. It stops before changing anything: ```text Can't bring 'new-search' in automatically: your commit "Tweak header" and 'new-search' changed the same lines of: index.html Nothing was changed. To combine them by hand, run: zev merge new-search --resolve ``` Here's how to combine them by hand. This is called *resolving a conflict*. **1. Start the resolve:** ```bash zev merge new-search --resolve ``` **2. Open each file it lists.** zev marked the places where both changed: ```text

<<<<<<< main Welcome to my site ======= Welcome! Search below >>>>>>> new-search

``` The part between `<<<<<<<` and `=======` is one version, and the part between `=======` and `>>>>>>>` is the other. **3. Edit it to what it should be.** Keep one side, the other, or a mix, and delete the three marker lines: ```text

Welcome! Search below

``` **4. Stage the files and finish:** ```bash zev add index.html zev merge --continue ``` Changed your mind halfway? `zev merge --abort` puts everything back the way it was before step 1. > **Tip:** conflicts are smaller and rarer when you merge often. Run `zev pull` and merge `main` into your branch regularly, rather than once at the end. ## Delete a branch you're done with ```bash zev branch -d new-search ``` This deletes only the name. Commits that were merged into another branch stay in its history. ## Branches on Zaryn Push a branch like any other: ```bash zev push origin new-search ``` When you're on the branch, plain `zev push` does the same. Others get it with `zev pull origin new-search`, or by cloning with `--branch new-search`. --- # When something goes wrong Source: https://zaryn.xyz/docs/en/troubleshooting zev's messages, what they mean, and what to do. Search for the words of the message you got. Find the message you got below (press `/` and type a few of its words), or the situation you're in. ## Messages from zev ### "Not a zev repository" You ran a command outside a project. `cd` into the project folder (the one with the hidden `.zev` folder), or run `zev init` to make the current folder a project. ### "Nothing to commit (staging area is empty)" You haven't staged anything. Stage your changes first: ```bash zev add . zev commit -m "message" ``` ### "Nothing new to add: no changes since the last commit" The files you named are exactly as they were in the last commit, so there's nothing to stage. Check `zev status` to see what really changed. ### "'file' doesn't exist, and zev doesn't track it" The path is wrong (check spelling and the folder you're in), or the file was never committed, so there's nothing to stage. ### "'file' is ignored (it matches a pattern in .zevignore)" A line in `.zevignore` matches this file. Remove or change that line if the file should be tracked. ### "Not switching to 'branch': you have local changes" Switching would overwrite changes you haven't committed, and zev never does that silently. Pick one: ```bash zev commit -m "work in progress" # keep them, on this branch zev stash # keep them, aside (zev stash pop later) zev checkout --force branch # throw them away ``` ### "Working files NOT updated" `zev pull` got the new commits, but didn't change your files, because one you changed would have been overwritten. Nothing is lost. Commit or stash your changes, then: ```bash zev checkout ``` ### "Can't bring 'branch' in automatically: … changed the same lines" A merge conflict: both branches changed the same lines. Run `zev merge --resolve` and follow [When both changed the same lines](/docs/en/branches#when-both-changed-the-same-lines). ### "has changes that aren't committed. Nothing was removed." `zev rm` refuses to delete a file with uncommitted changes. Commit them first, use `zev rm --cached` to stop tracking but keep the file, or `zev rm --force` to delete it anyway. ### "Not applying stash: 'file' has changes of its own" You changed a file after stashing, and the stash would overwrite it. Commit or stash those newer changes, then `zev stash pop` again. ### "No remote named 'origin'" The project isn't connected to Zaryn yet. Either create it there: ```bash zev new ``` or connect it to an existing repository: ```bash zev remote add origin owner/project ``` ### "Challenge request failed" when signing in This project's identity has no account on the server yet. Create one with `--register` and `--email`, or, if you made your account on the website, sign in with `zev login zaryn.xyz --device`. ### "Could not reach …" zev couldn't connect to the server. Check the address (for Zaryn, `zaryn.xyz` is enough), your internet connection, and any proxy or firewall. ### HTTP 401 or "unauthorized" You aren't signed in, or your token was revoked or expired. Run `zev whoami` to check, and `zev login` again. ### HTTP 403 or "forbidden" You're signed in, but your account can't do this here: for example, pushing to someone else's repository. Ask the owner to add you, or [fork it](/docs/en/how-do-i#contribute-to-a-project-i-cant-push-to). ### HTTP 402 The action needs Premium or more credits (private networks, some advanced tools). See [Billing and credits](/docs/en/billing-and-credits). ### HTTP 413, or "quota" The push is bigger than your plan allows (repository size or file size). Remove big generated files from the commit, ignore them, or upgrade. ### "Unknown command" A typo, or a git command zev names differently. zev suggests the closest command. Some common ones: | git | zev | |---|---| | `git reset ` | `zev restore --staged ` | | `git checkout -- ` | `zev restore ` | | `git switch -c ` | `zev switch -c ` (or `zev checkout -b`) | | `git fetch` + `git merge` | `zev pull` | | `git mv a b` | rename the file, then `zev add a b` | ## Situations ### I committed something I shouldn't have If you haven't pushed: fix the files and make another commit (zev doesn't rewrite commits). If it was a secret, such as a password or key, treat it as leaked once it's in history: change the secret, then stop tracking the file: ```bash zev rm --cached .env echo ".env" >> .zevignore zev add .zevignore zev commit -m "Stop tracking .env" ``` ### My push contains a huge file by mistake Stop tracking it, ignore it, and commit: ```bash zev rm --cached data/big.csv echo "data/big.csv" >> .zevignore zev add .zevignore zev commit -m "Don't track the big CSV" ``` For data and model files you do want to keep, zev handles large files well: only the changed parts of a file are sent on each push. ### zev printed a long list of lines with "error:" and file names That's a crash report. Please tell us: open an issue on Zaryn with the command you ran and the first lines of the output, or write to us from the Contact page. ### zev is old, or a command is missing ```bash zev --version zev self update ``` ### Cloning or pulling is slow zev 0.4 and later download in batches: a few requests instead of one per file. Older versions fetch every file on its own, which is slow on a long or filtered connection. Check with `zev --version` and update with `zev self update`. If it's still slow, the connection may be throttled: see [the proxy](/docs/en/proxy). ### I still can't figure it out - `zev help ` explains any command. - [How do I…?](/docs/en/how-do-i) covers the common tasks. - Ask on Zaryn: the Contact page reaches the team. --- # Proxy and VPN (zev proxy, zev vpn) Source: https://zaryn.xyz/docs/en/proxy When Zaryn or other sites are blocked, use your own VLESS, VMess, Trojan, Shadowsocks, Hysteria2 or WireGuard servers for zev, every app, or the whole computer (a VPN). Some networks block or slow down the way to Zaryn, GitHub and much else. If you have a proxy server that works on that network (VLESS, VMess, Trojan, Shadowsocks, Hysteria2, WireGuard, SOCKS5 or HTTP), zev uses it at the level you choose: | | What goes through the proxy | How | |---|---|---| | **zev only** (the default) | zev's own connections: sign-in, clone, push, pull, `zev self update`, private networks | `zev proxy use ` | | **Every app you point at it** | anything that can use a SOCKS5 or HTTP proxy: browsers, git, SSH, pip, npm, cargo, apt… | `zev proxy share on` (port 10808), then `zev proxy system on`, `zev proxy ssh` | | **The whole computer** | every program, its DNS and IPv6, without any settings in them | `sudo zev vpn on` (Linux) | zev never uses a proxy you didn't choose, and never falls back to going out directly when the proxy fails. With these it replaces apps like v2rayN, NekoRay or Hiddify: [moving from v2rayN](#moving-from-v2rayn-nekoray-hiddify) takes a minute. ## One command on, one off ```bash zev proxy start # asks for your server's link the first time zev proxy stop ``` `zev proxy start` does everything: saves the server, installs the engine if needed, opens the shared port 127.0.0.1:10808 for every app, sets your desktop's proxy, and then shows where you appear from. It stays on across restarts. `zev proxy stop` turns all of it off again. ```bash zev proxy start 'vless://…' # with a new server (keep the quotes) zev proxy start --tun # the whole computer: a VPN (asks for your sudo password) zev proxy start --tun --kill-switch # ... and nothing gets out directly if it stops zev proxy # is it on? through which server? ``` The rest of this page explains each part, for when you want more control. `zev proxy` is **free** on every plan: you bring your own proxy, and Zaryn carries none of its traffic. Private networks are part of [Premium](/docs/en/billing-and-credits), so using them through your proxy is too. Below: [the links zev understands](#links-zev-understands), then how to add yours. ## Links zev understands zev understands the share links VPN apps (v2rayN, v2rayNG, Hiddify, Nekoray, Shadowrocket) use, and the subscriptions providers hand out: | Link | What it is | Needs | |---|---|---| | `vless://…` | VLESS: TLS or REALITY, XTLS Vision, VLESS Encryption (such as `mlkem768x25519plus`), the `tcp`, `ws`, `grpc`, `xhttp` and `httpupgrade` transports | the Xray engine | | `vmess://…` | VMess (the v2rayN format), with the same TLS and transports | the Xray engine | | `trojan://…` | Trojan, over TLS or REALITY, same transports | the Xray engine | | `ss://…` | Shadowsocks: the 2022 ciphers (`2022-blake3-…`) and `aes-128-gcm`, `aes-256-gcm`, `chacha20-poly1305` | the Xray engine | | `hysteria2://…` or `hy2://…` | Hysteria2 over QUIC, with Salamander obfuscation (`obfs=salamander`) | the Xray engine | | `wireguard://…` or `wg://…` | WireGuard, including Cloudflare WARP (`reserved=`); no root needed | the Xray engine | | `socks5://user:pass@host:port` | a SOCKS5 proxy | nothing | | `http://…` or `https://…` | an HTTP proxy | nothing | | a subscription URL | a list of any of the above, from your provider: see [Subscriptions](#subscriptions) | | zev refuses what isn't safe or won't work rather than failing later: old Shadowsocks stream ciphers (`aes-256-cfb`, `rc4-md5`), Shadowsocks plugins, and the transports Xray dropped (`h2`, `kcp`, `quic`). A link's `insecure=1` or `allowInsecure` never turns certificate checks off; if your server uses its own certificate, pin it with `pcs=` (or `pinSHA256=` for Hysteria2), as your provider's app does. ## Add your proxy Save it under a name you choose. To keep the link (it holds your credentials) out of your shell history, leave it off and paste it when asked: ```bash zev proxy add work --use Paste the link, then press Enter: vless://… ✓ Saved work: vless proxy.example.com:443 tcp+tls xtls-rprx-vision mlkem768x25519plus fp=firefox sni=… pinned ``` `--use` also makes it the proxy zev uses from now on. Saved links live in `~/.config/zev/proxies`, readable by you alone. `zev proxy ls` lists them without their secrets. ## Subscriptions If your provider gives you a subscription URL (one link that lists many servers, updated when they change), add it once: ```bash zev proxy sub add myvpn https://provider.example/sub/abc123 ✓ myvpn: 24 servers (12 vless, 6 trojan, 4 shadowsocks, 2 hysteria2), named myvpn-1 … myvpn-24 Pick one: zev proxy use myvpn-1 (zev proxy test myvpn-1 tries it first) ``` zev downloads it through the proxy you use now (subscription hosts are often blocked too), or directly if that fails. Servers it can't use are listed with the reason, and the rest are saved. | Command | What it does | |---|---| | `zev proxy sub update []` | download it again: its servers are replaced by the new list. If the one you use is gone, zev says so and connects directly | | `zev proxy sub ls` | subscriptions and how many servers each has | | `zev proxy sub rm ` | forget it and its servers | The usual base64 format and plain lists of links both work. Clash (`proxies:`) and sing-box (JSON) files aren't share links: ask your provider for the v2ray / share-link format of the same subscription. ## Install the engine Everything except SOCKS5 and HTTP is spoken by [Xray-core](https://github.com/XTLS/Xray-core), which zev runs for you on this computer. Install it once: ```bash zev proxy engine install ``` zev downloads the Xray release it was tested with and checks its SHA-256 before unpacking it. If GitHub is blocked, download the zip for your system another way and run `zev proxy engine install --from Xray-linux-64.zip` (the same check applies). An Xray you already have also works: zev looks on your `PATH`, or set `ZEV_XRAY=/path/to/xray`. ## Check it ```bash zev proxy test work: vless proxy.example.com:443 tcp+tls xtls-rprx-vision … engine ✓ Xray on 127.0.0.1:41377 (48 ms) Zaryn ✓ 200 in 310 ms internet ✓ 204 in 290 ms ``` `zev proxy test ` tries a saved proxy without switching to it. When a check fails, the last lines of Xray's log are shown below it. To see exactly what zev makes of a link, `zev proxy config ` prints the Xray config it runs (it contains the proxy's secrets, so don't share it). ## When it doesn't work: zev proxy doctor `zev proxy doctor` finds what stands between you and Zaryn, fixes what zev can fix itself, and proves each fix with a real request before keeping it: ```bash zev proxy doctor ``` ```text Checking the way to Zaryn through work: vless proxy.example.com:443 tcp+tls fp=chrome … Network: wlan0 via 192.168.1.1; fixes in force: none work vless proxy.example.com:443 … ✗ DNS lies: this network answers 10.10.34.36 for proxy.example.com, DNS over HTTPS 203.0.113.9 (only that one accepts connections) fix: look names up with DNS over HTTPS (https://1.1.1.1/dns-query) ✓ TCP: 203.0.113.9:443 connects in 84 ms ✗ SNI filtering: TLS naming proxy.example.com is reset, naming www.example.com goes through · the reset comes from 3 routers away, near you: in your provider's network (the server is 14 away) Finding a way through 8 ways at once · as it is: no way through · firefox fingerprint: no way through · ClientHello in pieces (split: 10-20 byte pieces): 231 ms · ClientHello in pieces (large: 100-200 byte pieces, 10-20 ms apart): 400 ms … ✓ kept: ClientHello in pieces (split: 10-20 byte pieces) (the cheapest that works, and proven again) Clock ✓ within 2 s of api.zaryn.xyz's clock Throughput ✓ a download through the proxy: 2.0 MB in 1.4 s (1.43 MB/s) Result ✓ api.zaryn.xyz answers through the proxy (200 in 310 ms) · fixes for this network: DNS over HTTPS (https://1.1.1.1/dns-query), ClientHello in pieces (split) ✓ saved for wlan0 via 192.168.1.1: every zev command here uses them, and zev picks them up again when you're back on this network ``` What it looks for, and what it does about it: | Problem | How zev tells | What zev does | |---|---|---| | **DNS that lies** | the network's answer for the proxy's name against DNS over HTTPS (asked straight by IP address); a different answer that accepts no connections, or the filter's own address (`10.10.34.x`), is a lie | looks names up with DNS over HTTPS from then on, zev and Xray both | | **SNI filtering** | TCP connects, but a TLS handshake naming the server is cut while one naming another site goes through | races the ways around it (below) | | **Where the filter is** | the handshake is sent again with a TTL of 1, 2, 3 …: it expires that many routers away, so the first distance that gets a reset is where the filter sits | tells you whether it's in your provider's network or nearer the server | | **Broken IPv6** | the name's IPv6 address times out while IPv4 connects (every connection waits for IPv6 first) | IPv4 only | | **A blocked port** | the proxy's port doesn't answer while other ports of the same address do | says which ports answer: ask whoever runs the server for a link on one | | **A blocked address** | no port of the address answers | says so: another server, or a CDN-fronted link | | **The freeze** | small requests work but a download stops after 15-20 KB and never resumes (filters starve connections they can't classify) | says so: a REALITY or XHTTP link, or another server, usually avoids it | | **Throttling** | downloads crawl | says so, with the speed | | **The clock** | Zaryn's `Date` header against yours: VMess refuses connections more than 2 minutes off, and certificates look expired when the clock is days off | tells you how to set it (that needs an administrator) | | **TLS interception** | Zaryn's certificate isn't trusted on the direct path: something answers in its place (or a Wi-Fi sign-in page) | never turns certificate checks off; a link with a pinned certificate gets around it | ### Finding a way through When the way doesn't work, the doctor doesn't make you guess settings. It tries them all at once, in one Xray, each as its own way to the server: - **the ClientHello in pieces**, in three sizes (`split` 10-20 bytes, `large` 100-200 bytes, `tiny` 1-5 bytes), so a filter reading the server's name never sees it whole in one packet; - **other TLS fingerprints** (Chrome, Firefox, Safari, randomized), for filters that block a handshake by its shape; - both together. Each way's time is measured; the cheapest that works wins (a little extra time counts against the tiny pieces, which slow every connection). The winner must then work again in the engine zev really runs, with a real request; one that only got through once is skipped for the next. Nothing is saved until that passes. ### Per network The fixes are saved **for the network you're on**, which zev tells apart by its router (a hash of the router's address and hardware address; on Linux). Home, the office and a phone's hotspot each keep their own, and zev picks them up again by itself when you come back. Elsewhere, the fixes you set by hand apply. ```bash zev proxy set # this network, its fixes, and the networks zev remembers zev proxy set forget # forget what the doctor found here zev proxy set fragment split # set fixes by hand, for every network (dns , ipv4 on, fp … , or off) zev proxy doctor --no-fix # only look, change nothing zev proxy doctor home # check another saved proxy ``` ### For support and AI agents `zev proxy doctor --json` prints the whole report as JSON: every finding with its hint, the fixes, whether they were saved, and how far away the filter is. It never contains a link or its secrets, so it's safe to paste into a support request or hand to an assistant. ## Everyday use Once a proxy is chosen there's nothing more to do: every zev command goes through it. The engine starts with the first command that connects and keeps running for the ones after it. ```bash zev proxy status # which proxy, and whether the engine runs zev proxy use home # switch to another saved proxy zev proxy off # connect directly again zev proxy stop # everything off (shared port, desktop, VPN) zev proxy rm old # forget a proxy ``` For a single command, or in scripts and CI, `ZEV_PROXY` overrides the choice: a saved name, a link, or `off`. ```bash ZEV_PROXY=off zev pull ZEV_PROXY=home zev push ``` ## Every app on this computer: zev proxy share ```bash zev proxy share on ``` From then on **127.0.0.1:10808** is a proxy port any program can use, SOCKS5 and HTTP on the same port (10808 is the port v2rayN uses, so settings made for it keep working). It runs in the background, starts again when you log in, and: - **follows your choice**: `zev proxy use other` switches it, a pool switches to the fastest working server by itself, and the fixes `zev proxy doctor` found for the network you're on come with you when you move between networks; - **looks after itself**: if its engine stops, it starts it again; with no proxy chosen (`zev proxy off`) the port closes instead of letting traffic go out directly ([it fixes itself](#it-fixes-itself) has more). ```bash zev proxy share status # sharing? through which server, since when zev proxy share on --port 1080 zev proxy share off ``` **Other devices on your network** (a phone, a second laptop): `zev proxy share on --lan` opens the port to the LAN behind a password, which zev prints. Set the device's proxy to this computer's address, port 10808, user `zev` and that password. `zev proxy share on --local` closes it to the LAN again. Addresses on your own network (LAN, `10.0.0.0/8`, `192.168.0.0/16` and the like) are reached directly, not through the proxy. ### Your desktop and browsers: zev proxy system ```bash zev proxy system on # GNOME's or KDE's proxy setting → the shared port; new terminals get http_proxy, all_proxy… zev proxy system off ``` Browsers and most desktop apps follow the system setting. Terminals opened after a new login pick up `http_proxy`, `https_proxy` and `all_proxy` (from `~/.config/environment.d/90-zev-proxy.conf`). ### SSH and git: zev proxy ssh ```bash zev proxy ssh # GitHub, GitLab and Codeberg through the proxy zev proxy ssh github.com myserver # or the hosts you name zev proxy ssh off ``` zev puts a marked block at the top of `~/.ssh/config` with `ProxyCommand zev proxy connect %h %p`; `git push` to GitHub then goes through the proxy, and nothing else in the file changes. `zev proxy connect ` works anywhere a ProxyCommand does, and needs neither `nc` nor the shared port (it uses zev's own engine when sharing is off). ### One command: zev proxy run ```bash zev proxy run git push zev proxy run pip install requests zev proxy run -- curl https://example.com ``` The command gets `http_proxy`, `https_proxy`, `all_proxy` and a `GIT_SSH_COMMAND` that goes through the proxy, so HTTP, SOCKS and git over SSH all use it. Its exit code is zev's. ## The whole computer: zev vpn On Linux, zev can carry **everything**: every program, without any proxy settings in it, plus its DNS lookups and IPv6. ```bash sudo zev vpn on sudo zev vpn on --kill-switch sudo zev vpn on --exclude example.ir,192.0.2.0/24 zev vpn status sudo zev vpn off ``` - It uses the proxy you chose with `zev proxy use` (as yourself: `sudo` only sets up the network), and follows it when you change it. - It runs as a system service: it starts with the computer and comes back if it stops. - **Your LAN stays direct**, and so do Docker's networks and private networks: anything your computer has a more specific route for. - **DNS goes through the tunnel**: names are looked up over HTTPS by the far side, so a poisoned DNS on your network can't send you elsewhere. - **`--exclude`** sends some sites or addresses directly (names, IP addresses, CIDR ranges). `zev proxy route iran` sends Iran's sites direct for every mode. - **`--kill-switch`**: if the VPN stops for any reason, nothing goes out directly; only your LAN keeps working, until the VPN is back or you run `sudo zev vpn off`. How it works: zev creates a network interface (`zev0`) that the Xray engine reads, and routes everything into it except what has a more specific route and the engine's own connections (which carry a firewall mark so they don't loop). `sudo zev vpn off` removes the interface, the routes, the rules and the firewall table; nothing is left behind. On macOS and Windows, use `zev proxy share on` with `zev proxy system on` for now. ## It fixes itself The shared port and the VPN check every 30 seconds that traffic really gets through. When it stops for three checks in a row: 1. You get a notification on the desktop. 2. zev runs [`zev proxy doctor`](#when-it-doesnt-work-zev-proxy-doctor) by itself, at most every 10 minutes. It finds what blocks the way on this network (DNS lies, a blocked port, SNI filtering, a clock that's off) and saves a fix for this network. 3. The engine restarts with the fix, and a notification says what was fixed, for example *Fixed for wlo1 via 192.168.1.1: TLS fragmentation (split)*. With a pool, a dead server is simply skipped in the meantime. With the VPN's kill switch on, zev doesn't pause the VPN to run the doctor; it only restarts the engine. ## Check it: zev proxy check ```text $ zev proxy check Where you appear from through zev 203.0.113.9 (DE) without zev 5.160.12.34 (IR) Leaks ✓ every app goes through the VPN (they appear from the proxy's address) ✓ DNS goes through the tunnel ✓ no IPv6 way out (nothing to leak) ``` It shows the address and country websites see through the proxy and without it, and with the VPN on, whether every app, DNS and IPv6 really go through it. ## Watch it: zev proxy top ```bash zev proxy top ``` Live traffic of the shared port or the VPN: what each part sent and received in total and right now (zev itself, the shared port, the VPN, each server of a pool, what went direct). `--once` prints it once. ## Moving from v2rayN, NekoRay, Hiddify 1. Copy your servers out of the old app: most can export a server as a share link (`vless://…`) or give you the subscription address. 2. Add them to zev: ```bash zev proxy engine install # once: the Xray engine zev proxy add home 'vless://…' --use # a server, or: zev proxy sub add work https://… # a subscription zev proxy use work # all of its servers as a pool: the fastest, with failover ``` 3. Quit the old app (it holds port 10808), then: ```bash zev proxy share on # the same port 10808: your SSH config and apps keep working zev proxy system on # browsers and the desktop ``` 4. Or for everything at once: `sudo zev vpn on`. What you get on top: failover between servers ranked by measured speed, self-healing on networks that filter, per-network fixes that follow you, leak checks, and the same settings for zev's own connections. ## Many servers: the fastest, and failover Servers come and go on filtered networks: one is fast in the morning and blocked by the evening. Give zev several and it uses the best of them, and switches on its own when one stops answering: ```bash zev proxy use myvpn # every server of a subscription zev proxy use auto # every proxy you saved zev proxy use work,home,backup # these ones ``` zev times every server at once (a small request through each), keeps the three best running, and Xray sends each connection through the fastest that answers, checking them again every 30 seconds. When the one in use goes down, the next connection takes another; nothing for you to do. Every 30 minutes the next zev command times the whole list again, so a server that got better comes back. To see the ranking, or rank them now: ```bash zev proxy probe Probing 4 servers at once (https://www.gstatic.com/generate_204)… server now expected answers ● work 92 ms 95+-12 100% vless proxy.example.com:443 … ● home 140 ms 151+-20 100% trojan home.example:443 … ● backup 410 ms 388+-61 83% shadowsocks 203.0.113.9:8388 … old down - 0% vmess old.example:443 … ● in use (the best 3 by expected latency and answers; Xray switches between them) ``` > **Why "expected" and not just "now"?** One request says little: a slow DNS answer or a lost packet can make a good server look bad once. zev keeps a running estimate for each server (a Kalman filter): it smooths the noise, ignores a single spike, follows a server that really got slower, and trusts an old measurement less than a fresh one. A server that often fails to answer is ranked below a steady one, even a slightly slower one. The measurements are kept in `~/.cache/zev/proxy/health.json`, under a hash of each link, never the link itself. `zev proxy probe `, `zev proxy probe auto` or `zev proxy probe a,b,c` rank other servers without switching to them. `zev proxy status` shows which servers the engine runs now. ## Chains: one proxy through another A chain reaches its last server through the ones before it. Use one when the server you want to come out of is blocked from your network but reachable from another server: ```bash zev proxy chain out home work # zev → home → work → Zaryn zev proxy use out ``` `home` sees only that you connect to `work`; Zaryn sees `work`'s address. Each hop is a saved proxy, any of the kinds above. Hysteria2 and WireGuard run over UDP, so in a chain they can only be the first hop. `zev proxy ls` lists chains with their hops, and `zev proxy rm out` forgets one (a proxy that is a hop of a chain can't be removed until the chain is). ## Routes: what goes direct Some places are faster without the proxy, or only work without it: a server in your own country, a company mirror, sites that refuse connections from abroad. Routes send those direct and everything else through the proxy (split routing): ```bash zev proxy route iran # Iran's sites and addresses direct zev proxy route direct git.company.example 10.20.0.0/16 zev proxy route proxy blocked.example.ir # through the proxy, whatever a direct route says zev proxy route # list them zev proxy route rm git.company.example zev proxy route clear ``` | A route | Matches | |---|---| | `example.com` | that name and every name under it (`api.example.com`) | | `.ir` | every name ending in `.ir` | | `full:host.example` | that name only | | `5.160.0.0/16`, `2a01:5ec0::/29`, `203.0.113.7` | addresses | | `geoip:ir` | every address in a country (any two-letter country code) | | `geosite:category-ir` | a list of a country's or a service's sites, kept by the Xray project | | `iran` | `.ir`, `geosite:category-ir` and `geoip:ir` together | Routes apply to every proxy, single servers, pools and chains alike, from the next zev command. `geoip:` and `geosite:` use Xray's routing data, which `zev proxy engine install` puts beside Xray; if you installed the engine before these routes existed, run it once more. With a route on addresses, Xray looks up names on this computer to compare them; names that only resolve through the proxy still go through it. ## Private networks `sudo zev net up` takes the proxy you use and saves it with the network, so the network's background service reaches Zaryn and the relay through it as well. The relay's traffic travels inside the proxy too, which is how a device behind a network that blocks everything else still joins its team. `zev net status` shows `through the proxy …` when this is the case. ```bash sudo zev net up your-name/office # with the proxy you use sudo zev net up your-name/office --proxy home # with another saved proxy (a pool or a chain works too) sudo zev net up your-name/office --no-proxy # directly ``` The service runs its own copy of Xray from `/var/lib/zev/net` (root only), never one from your home folder. Devices behind a proxy talk to their peers through the relay. Their traffic stays end-to-end encrypted; the proxy and the relay only see WireGuard's encrypted packets. ## What never goes through the proxy Addresses on your computer, your local network and private networks: `localhost`, `127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `100.64.0.0/10` (private networks), `fc00::/7` and `*.zaryn.internal`. To change this list, set `ZEV_NO_PROXY` to your own, in curl's `--noproxy` form (names, `.domains`, CIDR ranges). ## Security - **zev doesn't fall back to a direct connection.** If the chosen proxy can't be used (the engine won't start, the link is broken), the command stops and says why. Run `zev proxy off` to connect directly. - **Certificate checks stay on.** A link can pin the server's certificate (`pcs=` / `pinSHA256=`), and zev passes that on. zev ignores `allowInsecure` in links: a link someone hands you can't switch certificate checks off. - **The shared port is for this computer.** `zev proxy share on` listens on `127.0.0.1` only; `--lan` opens it to the network only behind a password. - **The VPN runs its own copy of the engine.** `sudo zev vpn on` copies Xray into `/var/lib/zev/vpn`, owned by root, so a root service never runs a file your user account could replace. - **The engine is yours alone.** zev's own engine listens on `127.0.0.1` only, behind a random password. curl gets that password from a file only you can read, never from its command line, so other users on the computer can't use your proxy or see it. - **Treat a link like a password.** It contains your account's key on that server. If one leaks (into a chat, a screenshot, a public repository), ask whoever runs the server for a new one. --- # All commands Source: https://zaryn.xyz/docs/en/commands Every zev command, with the ones you'll use every day first. Each entry says what it does, how to type it, and shows examples. The commands are grouped by what you're doing, and the groups go from everyday to specialised. Most people only ever need the first three groups. In the terminal, `zev help` lists every command, and `zev help ` shows how to use one. Press `/` on this page to search. **In the usage lines:** `` means you fill something in, `[name]` means it's optional, and `a | b` means one or the other. ## Quick list | I want to… | Command | |---|---| | start a new project | [`zev init`](#zev-init) | | copy a project from Zaryn | [`zev clone`](#zev-clone) | | see what I changed | [`zev status`](#zev-status), [`zev diff`](#zev-diff) | | choose what to save | [`zev add`](#zev-add) | | save a version | [`zev commit`](#zev-commit) | | see the history | [`zev log`](#zev-log), [`zev show`](#zev-show) | | undo changes to a file | [`zev restore`](#zev-restore) | | delete a file | [`zev rm`](#zev-rm) | | put work aside for a moment | [`zev stash`](#zev-stash) | | work on something separately | [`zev branch`](#zev-branch), [`zev checkout`](#zev-checkout) | | combine branches | [`zev merge`](#zev-merge) | | send my work to Zaryn | [`zev push`](#zev-push) | | get others' work | [`zev pull`](#zev-pull) | | ask for a review | [`zev pr`](#zev-pr) | | check nothing got worse (tests, speed, size, model scores) | [`zev eval`](#zev-eval) | | install packages faster through Zaryn | [`zev mirror`](#zev-mirror) | | use my proxy for every app, or as a VPN | [`zev proxy`](#zev-proxy), [`zev vpn`](#zev-vpn) | ## Start a project ### zev init Makes the current folder (or the folder you name) a zev repository. It creates a hidden `.zev` folder for the history and doesn't touch your files. ```bash zev init zev init my-project ``` ### zev clone Copies a repository to your computer: its full history, its files, and `origin` set to where it came from. The folder is named after the repository unless you give one. ```text zev clone
[folder] [--branch ] ``` ```bash zev clone someone/project zev clone someone/project my-copy --branch dev zev clone someone/project@dev zev clone https://zaryn.xyz/someone/project zev clone file:///home/me/backups/project ``` Private repositories need you to be [signed in](#zev-login) with access to them. The folder must not exist yet, or be empty. ### zev config Reads and changes this repository's settings. The two you need are your name and email, which go on every commit. ```bash zev config set user.name "Your Name" zev config set user.email "you@example.com" zev config get user.name zev config list ``` ## Everyday work ### zev status Shows where you are: the branch, what's staged for the next commit, what you changed but haven't staged, files you deleted, and new files zev doesn't track yet. Each section says which command to run next. ```bash zev status zev status --json # for scripts ``` ```text On branch main Changes to be committed: new file: notes.md Changes not staged for commit: modified: todo.txt deleted: old.txt Untracked files: draft.txt ``` ### zev add Stages changes, which means picking them for the next commit. It handles new files, changed files and deleted files. ```text zev add ... ``` ```bash zev add notes.md # one file zev add src # everything in a folder zev add . # everything in the project zev add old.txt # old.txt was deleted: stages the deletion ``` Files matching `.zevignore` are skipped (unless zev already tracks them). Files that haven't changed since the last commit aren't staged, so `zev add .` is always safe to run. ### zev commit Saves everything you staged as a new commit, with a message describing it. ```bash zev commit -m "Fix the login button on small screens" zev commit "Same thing, without -m" ``` If nothing is staged, zev says so and makes no commit. A good message says what changed and why, in a few words. ### zev diff Shows the lines that changed: `+` added, `-` removed, with a little unchanged text around each change. ```text zev diff [file | folder] your changes that aren't staged yet zev diff --staged [file] what the next commit will contain zev diff [] [-- file] between commits ``` ```bash zev diff zev diff todo.txt zev diff --staged zev diff HEAD~3 HEAD # what the last three commits changed zev diff v1.0 main -- src # between a tag and a branch, only in src ``` ### zev log Lists commits, newest first: the ID, author, date and message. ```text zev log [--oneline] [-n | --all] [] ``` ```bash zev log # the last 10 zev log --oneline # one line each zev log -n 30 zev log --all zev log feature # the history of another branch ``` ### zev show Shows one commit and the changes it made. Without a commit it shows the newest one. ```bash zev show zev show 5f7f5e22 # the first characters of an ID are enough zev show HEAD~1 # the commit before the newest zev show v1.0 # a tag ``` **Naming commits.** Everywhere zev asks for a commit, you can write `HEAD` (the commit you're on), `HEAD~2` (two before it), a branch name, a tag name, or the start of a commit ID (at least 4 characters). ### zev restore Undoes changes to files. ```text zev restore ... throw away your changes: back to the last commit zev restore --staged ... unstage: keep your changes, leave them out of the next commit ``` ```bash zev restore todo.txt # undo my edits to todo.txt zev restore . # undo all my edits (careful!) zev restore old.txt # bring back a deleted file zev restore --staged notes.md # take notes.md out of the next commit ``` Changes you throw away with `zev restore` were never committed, so they can't be brought back. If you might want them later, use [`zev stash`](#zev-stash) instead. ### zev rm Deletes a tracked file and stages the deletion for the next commit. ```text zev rm [--cached] [--force] ... ``` ```bash zev rm old.txt zev rm build # a whole folder zev rm --cached secrets.env # stop tracking it, but keep the file ``` zev refuses to delete a file with changes that aren't committed, so you don't lose work by accident. `--force` deletes it anyway. `--cached` is what you want when you committed something by mistake (add it to `.zevignore` too). ### zev stash Puts your uncommitted changes aside and gives you a clean folder (back to the last commit). Later, you bring them back. ```text zev stash [save [message]] put changes aside zev stash list see them zev stash pop [id] bring back the newest (or that one) and delete it zev stash apply [id] bring it back and keep it zev stash drop [id] delete it ``` ```bash zev stash save "half-done search box" zev checkout main # do something else zev checkout feature zev stash pop ``` Stashes include staged and unstaged changes to tracked files. Untracked files stay where they are. `zev stash pop` won't overwrite a file you changed after stashing; it tells you which file is in the way. ## Branches A branch is a separate line of work. You can try something on a branch without touching `main`, then merge it in when it's ready. See [Branches and merging](/docs/en/branches) for the full story. ### zev branch Lists branches (`*` marks the one you're on), makes one, or deletes one. ```bash zev branch # list zev branch new-search # make it (you stay where you are) zev branch -d new-search # delete it ``` ### zev checkout Switches to another branch and updates your files to match it. ```text zev checkout [--force] zev checkout -b ``` ```bash zev checkout new-search zev checkout -b new-search # make it and switch to it, bringing your changes along ``` zev never overwrites your uncommitted work: if switching would replace a changed file, it changes nothing and names the file. Commit or [stash](#zev-stash) first. `--force` throws your changes away and switches. ### zev switch The same as `zev checkout`, by the name some people expect. `zev switch -c ` makes a branch and switches to it. ### zev merge Brings the commits of another branch into the one you're on. ```text zev merge zev merge --resolve when both changed the same lines zev merge --continue | --abort ``` ```bash zev checkout main zev merge new-search ``` If the branches don't overlap, zev combines them by itself. If both changed the same lines, it stops without changing anything and suggests `--resolve`, which marks both versions in the file: ```text <<<<<<< main the line as it is on main ======= the line as it is on new-search >>>>>>> new-search ``` Edit the file to keep what you want, delete the marker lines, then `zev add ` and `zev merge --continue`. `zev merge --abort` puts everything back as it was. [Step by step](/docs/en/branches#when-both-changed-the-same-lines). ### zev rebase Replays the commits of the branch you're on on top of another branch, as if you had started from its latest commit. ```bash zev rebase main ``` If it stops because both changed the same lines, run `zev merge main --resolve` instead: it does the same replay and lets you combine the lines by hand. ### zev cherry-pick Copies one commit from anywhere onto the branch you're on. ```bash zev cherry-pick 47bec4f5 ``` ### zev tag Gives a commit a name that doesn't move, usually a release. ```text zev tag [list] list tags zev tag tag the current commit zev tag -a -m a tag with a message and author zev tag -d delete a tag ``` ```bash zev tag v1.0 zev show v1.0 ``` ## Share on Zaryn ### zev login Signs this computer in to Zaryn (or another zev server). You do this once per computer. ```text zev login --register --email
make an account (an emailed code confirms it) zev login --register --code <123456> finish, if you closed the terminal zev login --device [--client ] approve in your browser (existing accounts, servers, agents) zev login sign in again with this project's identity ``` ```bash zev login zaryn.xyz --register sara --email sara@example.com zev login zaryn.xyz --device ``` The token is saved in `~/.config/zev/credentials`, readable only by you. ### zev whoami Shows the server and account you're signed in as. ### zev logout Forgets the saved sign-in on this computer. The token itself keeps working until you revoke it on Zaryn (Settings → AI agents and tokens). ### zev new Creates the current project on Zaryn and connects it as `origin`. It asks for a name, the kind of project (code, model, dataset, agent or topology), public or private, and a license. ```bash zev new zev push ``` ### zev push Sends your commits to a remote. With nothing after it, it sends the branch you're on to `origin`. ```text zev push [remote] [branch] ``` ```bash zev push zev push origin feature-x zev push me/project main ``` Large files only send the parts that changed. In [encrypted repositories](/docs/en/encrypted-repositories), files are encrypted on your computer before they're sent. ### zev pull Gets new commits from a remote and updates your files to match. ```text zev pull [remote] [branch] ``` ```bash zev pull zev pull origin main ``` If updating would overwrite a file you changed, zev changes no files and names the file. The new commits are still saved; commit or stash, then `zev checkout `. ### zev remote Manages remotes, the named addresses of other copies of the repository. ```bash zev remote # list zev remote add upstream team/project zev remote show upstream zev remote remove upstream ``` ## Work with others ### zev pr Opens a pull request from the branch you're on. zev drafts the title and description from your commits, shows them, and asks before opening. ```text zev pr [--title ] [--desc ] [--target ] [--yes] zev pr list | view | merge ``` ```bash zev checkout -b fix-typo zev commit -m "Fix a typo in the README" zev push zev pr ``` See [Collaboration from the terminal](/docs/en/cli-collaboration). ### zev issue Opens and manages issues (bug reports, ideas, tasks). ```text zev issue [--title ] [--desc ] zev issue list [--all] | view | comment | close ``` ### zev fork-repo Makes your own copy of someone's repository on Zaryn, to change freely and send back with a pull request. ```bash zev fork-repo someone/project --clone ``` `--as ` names the copy differently; `--clone` also clones it to your computer. ### zev ci Turns on CI for a repository and shows recent runs. ```bash zev ci enable zev ci status ``` ### zev mcp Runs an MCP server so an AI agent (Claude Code, Codex and others) can use Zaryn through zev. See [Scripting and AI agents](/docs/en/automation-and-agents). ```bash claude mcp add zaryn -- zev mcp ``` ## Find out more ### zev blame Shows, for each line of a file, the commit and author that last changed it. ```bash zev blame src/login.js ``` ### zev bisect Finds the commit that broke something by halving the history: you mark commits good or bad, and zev picks the next one to test. ```bash zev bisect start zev bisect bad # the current commit is broken zev bisect good 5f7f5e22 # this older one worked # test what zev checks out, then mark it: zev bisect good / zev bisect bad zev bisect reset # done ``` ### zev search Searches commits, experiments, metrics, lineage and snapshots. ```bash zev search commits login zev search all "learning rate" ``` ### zev compare Puts two commits, branches, snapshots or experiments side by side. ```bash zev compare branches main feature ``` ## Private networks ### zev net Joins this computer to one of your team's private networks (Premium): devices reach each other directly and privately, through NATs, over WireGuard. See [Private networks](/docs/en/private-networks). ```text sudo zev net up / join (runs in the background) sudo zev net down [] leave for now (--forget to leave for good) zev net status peers, connections, traffic zev net ls networks you're in zev net map [/] who reaches whom, and what one failure would cost zev net share [--name web] share an app on this device with the network zev net config / a config file for WireGuard's own apps (phones) ``` ## Network devices ### zev site Makes this machine the collector of a site: it reads the site's routers and switches over SSH with read-only commands (Cisco IOS / IOS-XE, Huawei VRP, MikroTik RouterOS, FRRouting, VyOS) for config backups and drift, the live map, the address plan and Path Explain, and runs the site's probes. Passwords stay on the collector. See [Network sites](/docs/en/network-sites), [Path Explain and probes](/docs/en/network-paths) and [Digital twin](/docs/en/network-twin). ```text zev site join [--server URL] make this machine the site's collector zev site cred add --user [--key ] [--enable] zev site cred ls · zev site cred rm the logins kept on this collector zev site test
[--cred ] [--vendor cisco|huawei|mikrotik|frr|vyos] [--config] zev site discover … which addresses answer on SSH, and what they are zev site probe ping|tcp|http|dns [--port N] [--expect X] run a probe from here, as the service does zev site diff / =… [--drills] [--json] what a config change would do, before it's made (exits 1 if traffic would break) sudo zev site install run the collector as a service zev site status this collector and its devices zev site forget-key
after a device's SSH key changed on purpose ``` ## Security and trust ### zev encrypt Encrypts a private repository's files on your devices, so Zaryn stores only data it can't read. See [Encrypted repositories](/docs/en/encrypted-repositories). ```text zev encrypt [status | on | share | recovery | unlock | approve | rotate] ``` ### zev verify-storage Checks, with cryptographic proofs instead of trust, that the server really stores everything from your last push. See [Verified storage](/docs/en/verified-storage). ```bash zev verify-storage ``` ### zev advisory Declares commits compromised (for example a poisoned dataset or a leaked key), so owners of everything built on them are told. See [Advisories and lineage](/docs/en/advisories). ```text zev advisory file | list | show | refresh | withdraw | ack | verify | feed ``` ### zev taint Shows which advisories reach a repository. `zev taint check` is a CI gate: it fails while an unresolved advisory applies. ```bash zev taint zev taint check --fail-on high ``` ### zev identity Shows (and creates the first time) this repository's signing key. ### zev sign `zev sign ` signs an object with your identity; `zev verify ` checks a signature. ### zev notarize Anchors the hash of a snapshot or commit on a blockchain, as public proof that it existed at that time. ```text zev notarize snapshot | commit | verify | list | config ``` ### zev audit Prints a full provenance report for the repository. ## Machine learning `zev eval` catches regressions in any project; the rest tracks the things ML projects care about, next to the code. ### zev eval Runs your tests, builds, benchmarks or eval, finds the numbers (test results, coverage, timings, bundle, binary and firmware sizes, frame times, model scores), records them for this commit on Zaryn and tells you at once whether a pull request into `main` would be blocked. Exits 1 when a metric got worse than its tolerance (in its units or a percentage, like `5%`), so it works as a CI step too. See [Evals and lineage](/docs/en/evals-and-lineage). ```bash zev eval init # once: detects Rust, JS/TS, Go, Zig, C/C++, PlatformIO, Godot, Unity, Python; saves zev-evals.json zev eval init -- python eval.py # or start from your own command zev eval run # before every pull request, or in CI zev eval report junit.xml lcov.info # results files you already have zev eval # this commit next to main zev eval compare main my-branch zev eval badge binary # Markdown for your README ``` ### zev metrics Records numbers (accuracy, loss, latency…) with commits, and compares them. ```bash zev metrics set accuracy 0.913 zev metrics show zev metrics compare ``` ### zev check A regression gate for CI: exits with an error if a metric got worse than the [thresholds](#zev-threshold) allow. ```bash zev check ``` ### zev threshold Sets the limits `zev check` enforces. ```bash zev threshold set accuracy --min 0.9 zev threshold list ``` ### zev history Shows a metric's trend over the commits, as a small chart. ```bash zev history accuracy ``` ### zev sdiff A semantic diff: changed metrics, and structural code changes (renamed functions, changed signatures) instead of only lines. See [Semantic diffing](/docs/en/semantic-diff). ### zev experiment Tracks a hypothesis from start to result. ```text zev experiment start [description] | list | show | complete | abandon | compare ``` ### zev dataset Registers datasets, splits them into shards, and records which shards were used where, so you know what a bad shard affected. ```text zev dataset register --name | split --shards | assign | lineage | impact --shard | list ``` ### zev lineage Records what was made from what: data, scripts, models. ```text zev lineage record zev lineage upstream zev lineage add | link | show | list | graph | provenance ``` `record` and `upstream` work on Zaryn: what this repository came from, and whether that changed since. The rest keeps a graph inside this repository only. ### zev context Records whether a change came from a person or an AI model, and with what prompt. ```bash zev context add src/parser.py --model claude --kind llm zev context blame src/parser.py ``` ### zev wdiff Compares model weight files (`.safetensors`, PyTorch, NumPy) tensor by tensor. ```bash zev wdiff base.safetensors tuned.safetensors ``` ### zev merge-weights Merges two checkpoints: average, weighted, SLERP or TIES. ```bash zev merge-weights a.safetensors b.safetensors --output merged.safetensors --strategy slerp --alpha 0.5 ``` ### zev drift Notices when metrics drift away from a baseline. ```text zev drift baseline | config --metric --delta | check | show | history | watch ``` ### zev reproduce Captures a command and its output, and later checks that it reproduces within a tolerance. ### zev snapshot Named snapshots of the repository's state, optionally permanent. ```text zev snapshot create | list | show | restore | diff ``` ### zev suggestions Lists lineage that Zaryn inferred from model weights ("this model looks fine-tuned from that one"), for you to accept or dismiss. ## Advanced These are for special setups and tooling. You won't need them for everyday work. | Command | What it does | |---|---| | `zev hook list \| add