Skip to content
ArchiveZaunEkko Docs
Reading
Text size
Fonts
简体中文English
Show contents

Command line and agents

Status
Current
Updated
2026-09-15
Scope
ekko CLI

ekko is the command-line counterpart of what ZaunEkko offers on the web. Whatever you can see in a browser, it can read — including content behind level gates, because it uses your own identity.

It is not only a command line for people. It is built so that someone else's agent can use it as smoothly as a person browses the site: a machine-readable capability listing, stable error codes, and output that switches to JSON on its own inside a pipe.

Install

npm install -g @zaunekko/cli

The package ships a launcher plus prebuilt binaries for each platform, so ekko is available right after install.

ekko version

Do not try to build from source — that repository is private, and the path is closed to you.

Sign in

ekko login

The command opens your browser at the ZaunEkko Account sign-in page. Once you approve, the browser shows a completion notice and the terminal receives the credential. It is the same sign-in screen you already use.

If this machine cannot open a browser (a server, a container, an SSH session), the command falls back to a verification code: the terminal prints a URL and a short code, and you open that URL on any device that has a browser. Your phone works.

Either way the terminal always prints the URL. Opening a browser fails silently in many environments, and printing the link is what keeps you unblocked when it does.

ekko login --no-browser   # never try to open a browser, just print the link
ekko login --device       # go straight to the code flow
ekko login --force        # re-authorize even when already signed in

One sign-in lasts a long time: the credential renews itself, and only a long stretch of complete inactivity ends it.

What you are granting

The consent screen lists the permissions. One of them deserves a note: blog.read lets the command line read every Blog post and moment that you yourself can read, including the ones behind level gates. That is exactly the point of this tool — your agent sees what you see — but you should know what you granted.

All of it is read-only. Publishing posts or moments, commenting and uploading are not included.

Revoking

Account → "Sign-in and security" → "Authorized applications" revokes it at any time. After revoking, that machine cannot renew; an access token already issued stays valid for up to 15 more minutes.

ekko logout only clears the local credential — it does not revoke the grant on the server. If a machine is lost, use the page above.

What it can do

Sign-in
  ekko login                      browser sign-in; falls back to a code
  ekko logout                     clear the local credential
  ekko whoami                     what the local credential says; no network
  ekko account                    live level, points and site roles; read-only

Catalog and calls
  ekko catalog ls                 list public services
  ekko catalog show <service>     details; --version + --contract for schemas
  ekko invoke <service>           make one call (spends points)
  ekko invocations ls             call receipts
  ekko invocations show <id>      a single receipt
  ekko rate-limit                 your current call window

Service status
  ekko status                     public health summary
  ekko status incidents           incident record

ZaunEkko's Blog (read-only)
  ekko blog posts ls              posts you can read
  ekko blog posts show <slug>     a single post
  ekko blog moments ls            moments

For agents
  ekko schema                     machine-readable capability listing

Without a valid credential nothing works except login, logout, version, help and schema. There is no anonymous read-only fallback, and that is deliberate: a tool that half-works while signed out leaves you unable to tell "I am not signed in" from "this does not exist" — and on Blog, that difference is whether you are seeing everything or only half of it.

Publishing a service and registering a provider are irreversible and stay in the Marketplace console.

Making a call

ekko invoke pixiv.daily-ranking \
  --version v1 \
  --idempotency-key daily-ranking-2026-09-15 \
  --input '{"mode":"daily"}'

--input takes a JSON literal, @path/to/file, or @- to read standard input.

--idempotency-key is required, and getting it wrong costs money

It exists to prevent double billing. On a timeout, a dropped connection or a retry you cannot tell whether the request arrived. Resend with the same key and the platform recognises the same call, returning the original result instead of charging you again.

So the key must be:

A workable pattern is to combine a business identifier with a time window, for example daily-ranking-2026-09-15.

Do not use a random value. Generating a fresh key on every retry turns the mechanism off — and the cost of turning it off is being charged twice, with nothing reporting an error.

The full contract lives in Authentication and calls, which is authoritative for the call surface.

Two kinds of credential

ekko loginZAUNEKKO_API_KEY
Suited toyou, at a terminalunattended scheduled jobs
Can doevery commandcall services only
Reads Blogyesno
Lifetimerenews itselflong-lived, revocable

Create an API key on the "API key" page in Account, then put it in the environment:

export ZAUNEKKO_API_KEY=zek_live_...
ekko invoke ... # no sign-in needed

A key can only call services. Governance commands reject it explicitly, rather than letting the server return a 403 whose cause you cannot see.

The contract agents rely on

The pipe decides the output shape, not a flag

ekko catalog ls              # a person at a terminal → table
ekko catalog ls | jq         # piped → JSON
ekko catalog ls > out.json   # redirected → JSON

Same convention ls and git use for colour. --json and --table override it explicitly.

Tables are for people, the layout may change at any time, do not parse them. JSON forwards the server response as-is.

Exit codes

CodeMeaning
0success
2not signed in — trigger re-authentication in CI
1any other failure

2 is reserved for "not signed in" so that scripts never have to grep the message. Messages change, and one reworded word would silently break your check.

Error body

In JSON mode the error goes to stdout as well — an error is a kind of result, and writing it to stderr would leave the caller reading an empty stdout and guessing:

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "...",
    "hint": "no call happened and nothing was charged; submit a new call after retryAfter seconds",
    "retryAfter": 37
  }
}

code is stable: NOT_LOGGED_IN, USAGE, NETWORK, UNAUTHORIZED, FORBIDDEN, NOT_FOUND, RATE_LIMIT_EXCEEDED, SERVER_ERROR, UNKNOWN.

Branch on code, never on message.

Self-description

ekko schema

Prints every command, its parameters, which ones need a sign-in, which ones spend points, plus the output and exit-code conventions. An agent can learn what the tool does without reading this page first.

That listing is itself a contract, so its fields are deliberately few and stable; a changed schemaVersion means the shape changed.

Configuration

Everything is an environment variable. There is no config file — on a tool installed on someone else's machine, a config file becomes the layer nobody can see while debugging.

VariablePurpose
ZAUNEKKO_API_KEYunattended credential
ZAUNEKKO_HOMEwhere credentials live (default ~/.zaunekko)
ZAUNEKKO_DEVICE_NAMEthe machine name shown under "Authorized applications"; set it empty to report nothing

Versions

ekko carries its own version, unrelated to site releases. It never assumes it matches the server: an old version warns but does not block, and a newer version is only ever announced, never installed for you.

Upgrading and installing are the same command:

npm install -g @zaunekko/cli