zop.dev · a terminal app for your cloud

zn
your whole cloud,
without leaving
the terminal.

See what you are spending, find what you are wasting, schedule it, ship to it and debug it — from one screen you drive with the keyboard or the mouse. Ask questions in plain English and your own AI agent answers them, rendered in zn’s own components. Nothing to memorise, everything scriptable.

5commands, total
119operations, none memorised
50k+resources, one view
0API keys to store
One

How it works

Nine walkthroughs: the shape of the tool, how you get anywhere in it, how changes are batched and reviewed, how it behaves at fifty thousand resources, and how it works with the AI agent you already run.

Five commands, one surface

The UI is the product. The other four exist because a UI cannot be piped, scheduled, or called by an agent.

   zn                       the UI. everything, keyboard and mouse
    │
    ├── zn auth              login · logout · token new · org use
    ├── zn run <op> [flags]  any of the 119 operations, non-interactively
    │      └── --raw         the 27 prefixes with no catalogue entry
    ├── zn doctor            what works, what does not, and why
    └── zn mcp serve --stdio the agent bridge

   THE BRIDGE BETWEEN THEM
     every action in the UI displays its `zn run …` equivalent
     y copies it

     so: you never memorise a command,
         and you never have to leave the UI to find one.

How you get anywhere

Three ways to reach everything, because a developer tool that only works one way is a tool half the team will not use.

   KEYBOARD                MOUSE                   PALETTE
   1–9   view               click sidebar           ctrl-k
   j k   row                click row               fuzzy over
   ↑ ↓   row                wheel scroll              · 119 operations
   /     search             drag to range-select      · 9 views
   space select             click tab                 · recent actions
   a     actions            click column to sort      · your own history
   ⏎     open
   A     staged             shift+drag → native     ⏎ runs it
   ?     keys                 text selection        y copies the script

   Nothing is mouse-only. Nothing is keyboard-only.
   The palette is the safety net for everything you have not learned yet.

Stage, review, apply

The change set is why a TUI beats a CLI here. Cost work is inherently multi-resource, and applying 40 changes as 40 commands is how mistakes happen.

   Resources ──┐
   Recs      ──┼──▶  select across views  ──▶  staged change set
   Cost      ──┘        (space · drag · ctrl-a on a filter)     │
                                                               │
   an AGENT can stage into the same set ────────────────────────┤
     "zn:stage_schedule_attach"  → shows up under A             │
                                                               ▼
                                              ┌────────────────────────────┐
                                              │  A · review                │
                                              │  grouped by action + tier  │
                                              │  total saving computed     │
                                              │  T3 items called out       │
                                              └─────────────┬──────────────┘
                                                            │
                              ┌─────────────────────────────┴──────────┐
                              │ any T3 in the batch?                   │
                              │   yes → type that resource's name once │
                              │         (or x to drop it and apply 6)  │
                              │   no  → [y/N]                          │
                              └─────────────────────────────┬──────────┘
                                                            ▼
                                   applied as ONE batched request,
                                   permission-checked per resource,
                                   with one entry in your history

   One request, one entry in your history, one thing to undo — instead
   of forty commands and forty chances to get one of them wrong.

A view over 51,204 rows

The estate never enters this process. Every list is a window, every filter is a query, and the refresh budget is shared with the web app.

   viewport 40 rows          ┌───────────────────────────────────┐
        │                    │  GET /resources?limit=50&page=N   │
        ▼                    │    + server-side filters          │
   fetch page N ─────────────┤    + a stable order, so nothing   │
   prefetch N+1              └───────────────────────────────────┘
        │
        ├── / search  ──▶  a QUERY, never a client-side filter
        ├── sort      ──▶  a QUERY (allowlisted columns only)
        └── ctrl-a    ──▶  selects the FILTER, not the rows
                             "all 1,088 running aws resources"
                             so a 40k-row selection is one predicate,
                             not 40k ids in memory

   REFRESH BUDGET       shared with the web app, so zn is deliberately
     overview   30s     conservative and tells you when it is waiting
     lists      manual  · r to refresh
     k8s table  10s     cached
     k8s live   on select only

The mouse, and what it costs

Capturing the mouse takes away the gesture developers use most. This is the whole mitigation, and it is on screen permanently rather than in a man page.

   WHILE THE UI RUNS            mouse captured · SGR 1006 + DECSET 1002
     click        select row / tab / sidebar
     drag         range-select rows
     wheel        scroll
     click header sort

   THE COST                     native drag-to-select is gone

   THE THREE WAYS BACK          all three visible in the footer
     shift+drag   your terminal's own selection, untouched
     y            yank the row over OSC 52 — works through SSH,
                  which native selection does NOT
     --no-mouse   release capture entirely for the session

   RELEASED AUTOMATICALLY       TERM=dumb · NO_COLOR · CI=true · no tty
                                and whenever the UI shells out

   OUTSIDE THE UI               zn run and zn doctor never touch the
                                mouse and use OSC 8 hyperlinks instead

A question, routed to your agent

zn gives you the chat surface. Your agent supplies the intelligence, on your subscription. Nothing here needs a model, a key, or a bill.

   you type in zn                 the answer comes back INTO zn
        │                                        ▲
        ▼                                        │
   zn context  ─ org · view · filter · selection ids
        │
        ▼
   the connector decides HOW to invoke it
     claude   claude -p "{prompt}" --output-format stream-json
     codex    codex exec "{prompt}"
     aider    aider --message "{prompt}"          (shell mode)
     yours    six lines of TOML
        │
        ▼
   the agent works — and calls back into zn for data
        │
        │   ┌──────────────────────────────────────────────────┐
        └──▶│  zn IS the MCP server it is calling.             │
            │  So it does not parse prose to learn what        │
            │  happened — it SERVED the calls, and renders     │
            │  them as first-class rows even when the agent's  │
            │  own output is opaque or unstructured.           │
            └──────────────────────────────────────────────────┘
        │
        ▼
   writes become PROPOSALS in the change set, not actions
        │
        ▼
   ⊕ staged 2 changes · A to review · you approve

   TWO DEPTHS
     a / ⏎   quick ask — headless, rendered inside zn, keeps the thread
     C       full session — hand over the terminal (tmux split, or
             suspend and resume) when you want the agent's own UI

Bring your own agent

zn ships no model, stores no API key, and pays for no inference. It makes itself the best possible tool for the agent you already run.

   WHAT zn DOES NOT DO
     no model selection · no API key · no prompt UI · no chat history
     no inference bill · no vendor lock

   WHAT IT DOES INSTEAD                      $ZN_AGENT is to zn
     ┌──────────────────────────────┐        what $EDITOR is to git
     │  zn mcp serve --stdio        │
     │    --propose-only            │        one line registers it:
     └──────────────┬───────────────┘          zn mcp install
                    │                          (detects claude, cursor,
        ┌───────────┴───────────┐               codex, aider on PATH)
        ▼                       ▼
   claude · cursor         any agent with a shell
   codex · aider              zn run --list
   (MCP clients)              zn run <op> --stage

   INSIDE THE UI            press c
     $TMUX set    ──▶  vertical split: zn left, your agent right
     no tmux      ──▶  suspend, release the mouse, hand over the
                       terminal, resume when the agent exits

   WHAT IT HANDS OVER       `zn context` — six lines
     org · view · filter · selection ids · staged count · tool access
     NEVER a data dump. The agent pulls what it needs through the tools.

The agent proposes, you dispose

Two independent layers, so neither one being wrong is enough. This is also where the PAT-scope finding stops mattering.

   LAYER 1 — the token                     LAYER 2 — the bridge
   mint a read-scoped PAT for the agent     zn mcp serve --propose-only
        │                                        │
        ▼                                        ▼
   the server refuses a write               a write tool call becomes
   before it reaches anything —             a STAGED PROPOSAL, never
   not zn's discretion, the rule            an executed action
        │                                        │
        └────────────────┬───────────────────────┘
                         ▼
              proposals land in the change set
                         │
                         ▼
              a human opens zn, presses A, and sees
                FROM YOU        · 2 changes
                PROPOSED BY …   · 2 changes, with the agent's reasoning
                         │
                         ▼
              the tier ladder applies to the batch
              a T3 member still needs its name typed

   The agent does the analysis. You keep the authority. That split is
   the whole design, and it is enforced in two places rather than one.

What is generated, and what is not

Every screen, form, gate and help string is generated from the same catalogue the platform already uses, so a new capability appears here the day it ships.

   the operation catalogue  —  one reviewed source of truth
        │
        └── generated ──────▶ the app, at build time
                                        │
        ┌───────────────────────────────┼───────────────────────────────┐
        ▼                               ▼                               ▼
   PALETTE ENTRY                   ACTION FORM                     zn run
   name · short · tier             from the JSON Schema            flags
   fuzzy-searchable                  scalar  → text field          + the
                                     enum    → picker                same
                                     default → prefilled             gate
                                     pattern → validation
                                     object  → editor pane

   Of 119 operations, 110 take nothing but simple values, so their
   forms are exact. The remaining nine get a structured editor.

   Add a capability to the catalogue and it appears here as a palette
   entry, a form, a confirmation gate and a scriptable command — all of
   it, on the same day, with nothing to keep in sync by hand.
Two

Keys

Everything is reachable by keyboard, by mouse, and by the palette. The tier is read from the registry, never decided by the app.

Every key

Fifteen bindings is the whole surface. The palette covers everything else.

1–9 · clickswitch view
ctrl-kcommand palette
/search, server-side
j k ↑↓ wheelmove
space · dragselect
ctrl-aselect the filter
aactions on selection
Areview staged changes
open / drill
llogs -f
rrefresh · restart in k8s
yyank over OSC 52
shift+dragnative text selection
?keys
q · escback / quit

Exit codes

zn run and zn doctor are the scriptable surface, so their codes are a contract. 77 is “go get a role”; 4 is “you are not allowed”.

0success
1the operation failed
2usage error, or a refused unbounded fetch
3not authenticated, or the token was rejected
4denied by policy
75UNKNOWN — a write whose outcome cannot be determined
77you lack the capability (it names which)
78a T3 gate was not satisfied non-interactively

The risk ladder

Applied once per batch rather than once per resource — the change set is what makes that safe, because you see everything it covers before you confirm.

TierWhat it isIn the UICount
T0readopens85
T1bookkeeping, idempotentruns6
T2state change[y/N] once, per batch17
T3irreversibletype the name · --confirm11
Three

Every screen

Twenty screens, drawn against an estate of fifty thousand resources.

the front door

zn

No subcommand. The whole product opens, and the first screen answers the question people actually have: what is this costing, what is broken, what changed.

dev@acme.io — zn — 142×48
$ zn
┌─ zn · Acme · acme-prod ───────────────────────────────────── $18,204/mo  ▲6.2%  ·  3 alerts ─┐
├────────────────┬──────────────────────────────────────────────────┬──────────────────────────┤
 1 Overview       SPEND       SAVEABLE     RESOURCES               TOP MOVERS               
 2 Resources      $18,204     $2,840       51,204                                           
 3 Cost                                                            aks-9920                 
 4 Recs           ALERTS                                             platform-eu  ▲ $312    
 5 Schedules       budget q3-platform at 94%                      db-3f10bc                
 6 Deploys         3 pods CrashLoopBackOff · platform-eu            orders-pg    ▲ $141    
 7 Kubernetes      discovery stale 4h · gcp-prod                  i-0abc123                
 8 Govern                                                            api-prod     ▼ $38     
 9 Settings       RECENT                                                                    
                  14:02 deploy checkout → staging  ok              COVERAGE                 
 staged           11:40 bulk stop 12 resources     ok                scheduled  38%         
  0 changes       09:15 schedule nights created    ok                tagged     91%         
                                                                                            
                                                                                            
├────────────────┴──────────────────────────────────────────────────┴──────────────────────────┤
 ctrl-k palette · / search · ? keys · shift+drag select text · q quit                         
└──────────────────────────────────────────────────────────────────────────────────────────────┘
browse · 51,204 rows

Resources

Virtualised against the server, never held in memory. Multi-select with the keyboard or a mouse drag; the inspector follows the cursor.

dev@acme.io — zn — 142×48
┌─ zn · Resources ─────────────────────────── 51,204  ·  filter: aws · running  ·  3 selected ─┐
├────────────────┬──────────────────────────────────────────────────┬──────────────────────────┤
 1 Overview        ID          NAME          TYPE      COST SCH    i-0abc123                
 2 Resources    i-0abc123   api-prod      ec2       $412      api-prod                 
 3 Cost          i-0def456   worker-batch  ec2       $286 nights                          
 4 Recs          db-3f10bc   orders-pg     rds       $884      cpu p95   3.1%           
 5 Schedules     vol-7712aa  orders-pg-dataebs        $96      net       0.4 MB/s       
 6 Deploys       fn-checkout checkout      lambda     $18      uptime    42d            
 7 Kubernetes    i-0aa9911   ci-runner-3   ec2       $204      cost      $412/mo        
 8 Govern        aks-9920    platform-eu   aks     $1,204 wknd                            
 9 Settings                                                        RECOMMENDED              
                  … 51,197 more · scroll or / to narrow             ec2-idle-30d            
 staged                                                             saves $412/mo           
  3 changes                                                                                 
                                                                   a actions on 3           
                                                                   A review staged          
├────────────────┴──────────────────────────────────────────────────┴──────────────────────────┤
 space select · drag range · a actions ·  open · / search server-side · y yank               
└──────────────────────────────────────────────────────────────────────────────────────────────┘
discovery

ctrl-k

The answer to “I don’t want to remember commands”. Fuzzy over all 119 operations and every view — and it shows the scriptable form of whatever you highlight.

dev@acme.io — zn — 142×48
┌─ zn · Resources ──────────────────────────────────────────────────────────────────── 51,204 ─┐
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  ctrl-k  sched                                        119 operations                        
├──────────────────────────────────────────────────────────────────────────────────────────────┤
Attach selection to a schedule              schedule attach                   T2           
   Create a schedule                           schedule create                   T2           
   List schedules                              schedules list                    T0           
   Detach a resource from a schedule           schedule detach                   T2           
   Go to Schedules view                        view · 5                                       
   Schedule success report                     reports schedule-success          T0           
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  runs non-interactively as  zn run schedule-attach --schedule=nights --resource=i-0abc123    
  y copies that line. You never memorise a command; the palette                               
  hands you the script when you need one.                                                     
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  run · ↑↓ move · y copy as script · esc close                                               
└──────────────────────────────────────────────────────────────────────────────────────────────┘
generated input

an action form

Built from the tool’s JSON Schema, not hand-authored. 92% of arguments are plain scalars; enums become pickers, patterns become validation, defaults are prefilled.

dev@acme.io — zn — 142×48
┌─ zn · schedule create ─────────────────────────────── generated from the tool's JSON Schema ─┐
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  name          nights                    string · required                                 
    timezone      UTC                       enum · 11 values        ← ⇆ to cycle              
    crons[0]      0 19 * * 1-5  ·  stop     array<object> · required                          
    crons[1]      0 8  * * 1-5  ·  start                            + to add a row            
    resource_ids  3 selected                from your selection     e to edit                 
    description                             string · optional                                 
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  T2 · reversible     3 resources will start and stop on this timetable                       
  idempotency key minted automatically · never surfaced                                       
├──────────────────────────────────────────────────────────────────────────────────────────────┤
 tab next ·  create · y copy as zn run · esc cancel                                          
└──────────────────────────────────────────────────────────────────────────────────────────────┘
the change set

A · review

The feature a CLI cannot have. Stage changes across views, see the total saving, then apply once as a single bulk action — with the T3 gate applied to the batch rather than seven times.

dev@acme.io — zn — 142×48
┌─ zn · Review staged changes ───────────────────────────────── 7 changes  ·  saves $1,986/mo ─┐
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  ATTACH TO SCHEDULE nights   T2                                                              
    i-0abc123    api-prod            saves $412                                               
    i-0def456    worker-batch        saves $286                                               
    vol-7712aa   orders-pg-data      saves $96                                                
                                                                                              
  STOP NOW   T3                                                                               
    i-0aa9911    ci-runner-3         saves $204                                               
                                                                                              
  RESIZE   T2                                                                                 
    aks-9920     platform-eu         saves $604                                               
    fn-checkout  checkout            saves $122                                               
    db-3f10bc    orders-pg           saves $262                                               
                                                                                              
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  1 change is T3 and irreversible. Type ci-runner-3 to include it,                            
  or press x to drop it and apply the other 6.                                                
                                                                                           
├──────────────────────────────────────────────────────────────────────────────────────────────┤
 a apply · x drop · d diff · esc back · executes as one bulk action                           
└──────────────────────────────────────────────────────────────────────────────────────────────┘
analysis

Cost

Dimensions on tab, drill on enter. It states its own limits: USD, UTC, and that the last day or two reads low because the rollup runs at 19:55 UTC.

dev@acme.io — zn — 142×48
┌─ zn · Cost ─────────────────────────────────── 1–30 Jul 2026 UTC  ·  $18,204  ▲6.2%  ·  USD ─┐
├────────────────┬──────────────────────────────────────────────────┬──────────────────────────┤
 1 Overview       by provider        (tab: team · tag · resource)  DRILL                    
 2 Resources                                                                                
 3 Cost           aws    ████████████████████████████   $11,880    platform                 
 4 Recs           gcp    ███████████            $4,410               $6,204  ▲9%            
 5 Schedules      azure  ████                   $1,914             data                     
 6 Deploys                                                           $5,110  ▲4%            
 7 Kubernetes     30-day trend                                     web                      
 8 Govern         ▁▂▂▃▃▄▄▅▅▅▆▆▆▇▇▇███▇▇▆▆▅▅▄▄▃▂▁                     $3,880  ▼2%            
 9 Settings                                                        untagged                 
                  data through 29 Jul — the last 1–2 days read low   $3,010  ▲8%            
                  every figure is USD, every window is UTC                                  
                                                                    drill in               
                                                                   e export CSV             
                                                                     CSV                    
├────────────────┴──────────────────────────────────────────────────┴──────────────────────────┤
 tab dimension ·  drill · e export CSV · / filter                                            
└──────────────────────────────────────────────────────────────────────────────────────────────┘
operations

Kubernetes

The table comes from the cheap reports endpoint; the expensive live call fires only for the focused row, because the live endpoints scan the whole org inventory to find one.

dev@acme.io — zn — 142×48
┌─ zn · Kubernetes · platform-eu ──────────────────────────────── 41 pods · 3 unhealthy · aks ─┐
├────────────────┬──────────────────────────────────────────────────┬──────────────────────────┤
 1 Overview        pods   deployments  events  nodes               checkout-7d9f            
 2 Resources                                                       prod · Running           
 3 Cost           NAME                  READY  RST  CPU   MEM                               
 4 Recs          checkout-7d9f-x2k1    1/1    0    120m  412Mi    LOGS        l            
 5 Schedules      checkout-7d9f-p81q    1/1    0    98m   388Mi    14:02 INFO               
 6 Deploys        worker-5b8c-mm40      0/1    14     14:02 WARN               
 7 Kubernetes     etl-2c1a-77zz         1/1    0    1.2   2.1Gi    14:02 ERROR              
 8 Govern         api-gw-9f2e-k0d1      1/1    2    340m  701Mi                             
 9 Settings       redis-0               1/1    0    40m   120Mi    d describe               
                                                                   y yaml                   
                                                                   r restart T3             
                                                                                            
                                                                   cached table             
                                                                   live on select           
├────────────────┴──────────────────────────────────────────────────┴──────────────────────────┤
 l logs -f · d describe · r restart T3 · live data is fetched only for the focused row        
└──────────────────────────────────────────────────────────────────────────────────────────────┘
keys

?

Everything reachable two ways. The text-selection escape hatches are on this screen and in the footer, permanently.

dev@acme.io — zn — 142×48
┌─ zn · Keys ───────────────────────────────────────────────────────────────────── ? to close ─┐
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  MOVE                          SELECT                        ACT                             
  j k  ↑ ↓    row               space       toggle row        ctrl-k      palette             
  ctrl-d/u    page              drag        range             a           actions             
  wheel       scroll            ctrl-a      all matching      open                
  g G         top / end         x           clear             /           search              
  1–9 · click view              A           review staged     e           edit                
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  TEXT SELECTION                                                                              
  shift+drag   your terminal's own selection, untouched                                       
  y            yank the row over OSC 52 — works through SSH,                                  
               which native selection does not                                                
  zn --no-mouse release the mouse entirely                                                    
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  Mouse is captured while the UI runs. That costs native drag-select,                         
  so the two ways to get it back are on screen at all times.                                  
└──────────────────────────────────────────────────────────────────────────────────────────────┘
debugging

zn doctor

Everything that decides whether the tool works, including three things the platform will not tell you on its own.

dev@acme.io — zn — 142×48
$ zn doctor

   binary      zn 0.1.0 · darwin/arm64
   spec        119 ops · generated 2026-08-18
   service     api.zop.dev · 41ms
   spec skew   none — embedded matches live tools/list
   auth        dev@acme.io · token expires in 88d
   org         acme-prod Acme · 51,204 resources
   clock       local is IST · all requests sent UTC

  ! rate budget shared across your organisation
                  zn paces itself so it never crowds the dashboard.

  ! agent       cursor detected, never connected
                  open it once, then zn connect

  terminal
   truecolor    yes         mouse SGR 1006  yes
   OSC 8 links  yes         OSC 52 clipboard yes
   box drawing  yes         size            142×48

  3 warnings, 0 errors. zn doctor --verbose for the checks behind each.
identity

zn auth

Paste a token. No device-code flow exists and building one is auth-service work, so this is honest about what it is.

dev@acme.io — zn — 142×48
$ zn auth

  dev@acme.io   acme-prod Acme
    token   zn_pat_…9f3c   expires in 88 days

    login          paste a token from Developer Settings
    logout         forget it
    token new      mint another
    org use    switch


$ zn auth login

  Create one at https://app.zop.dev/settings/tokens
  Paste token › ••••••••••••••••••••

   dev@acme.io   stored ~/.config/zn/credentials (0600)

  ! A token carries your own permissions. Mint a narrower one
    for CI or for an agent — zn auth token new.

  Which org?  1 Acme 51,204   2 Northwind 8,9101

   ready. Run zn.
scripting

zn run

One command for all 119 operations, plus --raw for the 27 prefixes with no catalogue entry. This is what the palette copies.

dev@acme.io — zn — 142×48
# the palette handed you this line. it is the whole scripting surface.
$ zn run resources-list --provider=aws --state=running --limit=50
{"items":[{"id":"i-0abc123",…}],"total":1088,"hasMore":true}

$ zn run --list | head -4
resources-list        T0   List resources in this org, one page at a time
resource-stop         T3   Stop a running resource
schedule-create       T2   Start and stop things on a timetable
service-deploy        T2   Ship a revision to an environment

$ zn run resource-stop --resource=db-3f10bc --confirm=orders-pg
   stopped  orders-pg

$ zn run --raw GET event-readiness
{"items":[{"id":"er-14","name":"diwali-sale"}]}
  --raw reaches anything the catalogue does not cover yet.

$ zn run resources-list --json | jq -r '.items[].id'
i-0abc123
i-0def456
db-3f10bc

  Stdout is data, stderr is everything else, so every command pipes.
agents

zn mcp serve

The same operations, the same permissions, the same trail — and the agent stages into the change set you review, rather than acting behind you.

dev@acme.io — zn — 142×48
$ claude mcp add zn -- zn mcp serve --stdio
   zn   119 tools, filtered to what this token may call

$ claude
> which aws resources cost the most and are doing nothing?

   zn:get_recommendations (rule=idle, provider=aws, limit=10)
    ↳ 10 of 47 · $2,840/mo · did not enumerate 51,204 resources
   zn:get_resource_overview (id=i-0abc123)
    ↳ cpu p95 3.1% · net 0.4 MB/s

  Three EC2 instances are under 5% CPU. A nights-and-weekends
  schedule saves $1,240/mo. Want me to stage it?

  The agent stages into the SAME change set the UI shows. You open
  zn, press A, and review what it proposed before anything applies.
chat, without shipping a model

the ask pane

Type a question; it goes to whichever agent you have connected. Because zn served the tool calls, it renders the answer with its OWN components — that table is the real one, selectable and actionable, not markdown the agent printed.

dev@acme.io — zn — 142×48
┌─ zn · Ask ─────────────────────────────────────── claude · connected · 3 resources attached ─┐
   ask    resources   cost   recs   k8s                                                       
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  you                                                                                         
    which of these are safe to stop overnight?                                                
                                                                                              
  claude                                                                                      
     get_recommendations    rule=idle provider=aws    10 of 47                               
     get_resource_overview  i-0abc123                 cpu p95 3.1%                           
     get_blast_radius       aks-9920                  2 dependents                           
                                                                                              
    Two are safe. aks-9920 backs a prod ingress, so I left it out.                            
                                                                                              
      ID          NAME           CPU p95  IDLE      SAVES                                     
    i-0abc123   api-prod       3.1%     30d        $412                                     
    i-0def456   worker-batch   1.4%     30d        $286                                     
    aks-9920    platform-eu    44%          $604                                     
    ↑ the same table as the Resources view — space select ·  open                            
                                                                                              
     staged 2 changes   attach to nights   saves $698/mo   A review                          
                                                                                              
                                                                                            
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  send · @ attach selection · C full session · ^p switch agent · nothing here is markdown    
└──────────────────────────────────────────────────────────────────────────────────────────────┘
chat, without shipping a model

zn connect

Every agent you have, and whether the wiring actually works. A config file containing the right line is not proof of anything.

dev@acme.io — zn — 142×48
$ zn connect

  agent        status        tools   transport    last used
  ──────────────────────────────────────────────────────────────────────
  claude       ✓ connected    119     stream-json  2h ago      default
  codex        ✓ connected    119     text         yesterday   
  cursor       ! never opened —       —            —           
  aider        · shell mode   —       zn run       —           

  cursor — config written but it has never connected. Open Cursor once;
  a config file with the right line in it is not proof the wiring works.

  Add your own in ~/.config/zn/config.toml — six lines, no plugin to install:

  [connector.mine]
  detect   = "my-agent"
  ask      = ["my-agent", "-p", "{prompt}"]
  register = "my-agent mcp add zn -- zn mcp serve --stdio"
  speaks   = "mcp"   # or "shell" — then it gets zn run instead of tools

  No token is written to any of their config files. They hold a command;
  zn holds the credential. Rotating it is zn auth login, once.
bring your own agent

zn mcp install

zn ships no model and stores no API key. It finds the agents already on your machine and registers itself as a tool provider for them.

dev@acme.io — zn — 142×48
$ zn mcp install

  looking for agents on this machine…

   claude        Claude Code 2.1.4        ~/.claude.json
   cursor        Cursor 0.48              ~/.cursor/mcp.json
  · codex         not installed
  · aider         not installed

  Register zn with both? [Y/n] › y

   claude   zn mcp serve --stdio --propose-only
   cursor   zn mcp serve --stdio --propose-only

  Both now see every operation your token is allowed to call.
  Writes are proposals, not actions — they land in your change set.

  zn ships no model, stores no API key, and pays for no inference.
  Your agent, your subscription, your context window.
bring your own agent

c · ask your agent

The $EDITOR pattern. zn hands over the terminal — or opens a tmux split — and your own CLI does the talking, with zn as its hands.

dev@acme.io — zn — 142×48
# inside zn, press c — $ZN_AGENT is to zn what $EDITOR is to git
┌──────────────────────────────────────────────┬───────────────────────────────────────────────┐
 zn · Recommendations                          claude  (your CLI, your subscription)         
 filter rule=idle provider=aws                                                               
                                               zn handed me:                                 
  rec-8821  i-0abc123   $412                    org acme-prod · Recommendations             
  rec-8830  vol-7712aa  $186                    3 selected · rule=idle                      
  rec-8844  aks-9920    $604                    119 tools via MCP                           
  rec-8851  fn-checkout $122                                                                
                                               > are these safe to stop at night?            
 3 selected · $1,202/mo                                                                      
                                                zn:get_resource_overview x3                 
 c ask your agent                                ↳ all three idle 30d, no traffic            
 a actions                                                                                   
 A review staged                               Two are safe. aks-9920 backs a                
                                               prod ingress — I staged the two               
                                               and left it out.                              
                                                                                             
└──────────────────────────────────────────────┴───────────────────────────────────────────────┘

  In tmux, c opens a split. Without tmux, zn suspends, releases the mouse,
  and hands over the terminal — then resumes when the agent exits.
bring your own agent

the agent proposes

Two layers stop an agent acting alone: a read-only token the platform enforces, and a bridge that turns every write into a proposal.

dev@acme.io — zn — 142×48
┌─ zn · Review staged changes ──────────────────────────── 5 changes  ·  2 proposed by claude ─┐
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  FROM YOU                                                                                    
    ATTACH TO nights   T2                                                                     
      i-0def456    worker-batch        saves $286                                             
      vol-7712aa   orders-pg-data      saves $96                                              
                                                                                              
  PROPOSED BY claude   14:06                                                                  
    ATTACH TO nights   T2                                                                     
      i-0abc123    api-prod            saves $412    idle 30d, no traffic                     
      rec-8830     orders-pg-data      saves $186    gp2→gp3, restore-reversible              
      note  left aks-9920 out — it backs a prod ingress                                       
                                                                                              
├──────────────────────────────────────────────────────────────────────────────────────────────┤
  The agent could not apply any of this. It has a read-scoped token                           
  and the bridge runs --propose-only, so a write is physically a                              
  proposal. You are the only thing that can press a.                                          
├──────────────────────────────────────────────────────────────────────────────────────────────┤
 a apply all 4 · x drop one · d why? · esc back                                               
└──────────────────────────────────────────────────────────────────────────────────────────────┘
bring your own agent

any agent, six lines

The contract is a command to run and a context block to read. Claude, Codex, Cursor, aider or a shell script — zn does not care which.

dev@acme.io — zn — 142×48
# any agent. zn only needs a command to run.

  ~/.config/zn/config.toml

  [agent]
  command = "claude"
  args    = ["--continue"]

  # or just: ZN_AGENT=codex zn
  # or aider, cursor-agent, opencode, a shell script — zn does not care


# what the agent is handed. ids and shape, never a data dump.
$ zn context
org       acme-prod  Acme  ·  51,204 resources
view      recommendations  ·  filter rule=idle provider=aws
selected  3   rec-8821 rec-8830 rec-8844
staged    2 changes
tools     mcp: registered (propose-only)  ·  shell: zn run --list
budget    rate limit 100/min, org-wide — prefer summaries to enumeration

  Six lines, not six thousand rows. The agent asks for what it needs
  through the tools; zn does not pre-load its context window.
when things break

failure states

A terminal app has to draw its own bad news. Each of these is a state zn will really be in, not a hypothetical.

dev@acme.io — zn — 142×48
# the states a real terminal app has to draw

   cannot reach zop.dev
    last good 14:02 · showing cached view, read-only
    retrying in 8s · r to retry now

  ! slowing down
    backing off 4s · 12 of 22 pages · the budget is shared
    with everyone in your organisation

  ! token rejected
    expired, revoked, or the service is briefly unavailable
    zn auth login · or zn doctor to tell them apart

   write outcome unknown
    the connection dropped after the request was sent.
    redeploy is not idempotent — zn will not retry it for you.
    key 9f2c-4410-b8 ·  to open the deploy list and check
Four

What lands when

Reads first, then actions and the change set, then the operations views, then your own agent.

WhenWhat lands
NowThe view: overview, resources, cost and recommendations. Search, filters, and all of it scriptable.read
NextActions and generated forms. The staged change set, with the risk ladder applied to the batch.act
ThenKubernetes, deploys and governance. A real log tail.operate
SoonConnectors: register zn with Claude, Codex, Cursor or your own agent.connect
AfterThe ask pane: a question from inside zn, answered by your agent, rendered in zn’s own components.ask
Five

What it deliberately is not

The decisions we made by leaving things out.

It ships no model

No API key to store, no inference to pay for, no vendor to be locked into. You bring the agent you already run.

Your token never leaves zn

Connectors put a command in your agent’s config, never a credential. Rotating is one login, once.

The agent proposes, you approve

Writes from an agent land in the change set as proposals. Only a person can apply them.

It never guesses about your money

Costs are labelled, windows stated, and where a figure is still settling the screen says so.

It refuses rather than truncates

Asked for more than it can safely return, zn stops and names the command that answers the question properly.

It will not retry a write for you

When an outcome is genuinely unknown, zn says unknown and hands you the command to check.

Nothing is mouse-only or keyboard-only

Every action has both, and the palette is the safety net for whatever you have not learned yet.