Developer guide · Zikaron

Command line

zikaron offers the same ledger operations as the window, one subcommand per action. It is built for scripts: the output is a single JSON value, and the verdict is in the exit code. The full output shapes, exit codes, refusal reasons and flags are in CLI-SCHEMA.md in the source; zikaron contract also prints that contract as one value, made from the same tables in the code. The one exception is zikaron mcp: it speaks the Model Context Protocol on standard input and output, one message per line; see AI apps below.

Where it is

Installed from the dmg
/Applications/ZIKARON.app/Contents/MacOS/zikaron. Turn on “Enable the zikaron command” under “Terminal” in the app’s Settings › Command line and AI control and it places a link at /usr/local/bin/zikaron, with macOS asking for an administrator password when needed; turn it on in the app once it is in Applications.
Installed from the pkg
/usr/local/bin/zikaron, ready right after installing; “Enable the zikaron command” shows “Taken by another install”, and you can leave it as it is.
Installed from the deb
/usr/bin/zikaron; “Enable the zikaron command” shows “Provided by the installed package”. With the AppImage, install the .deb for the command line; the switch shows “Not supported for this install”. “Copy config” under “Connect an AI app” is grey in the AppImage and in an app opened straight from its disk image, likewise.
Windows
zikaron.exe in the unpacked folder, run in a terminal; double-clicked, it only flashes a window. “Enable the zikaron command” writes the folder into this user’s Path, and terminals opened afterwards find zikaron.
Built from source
target/release/zikaron; “Enable the zikaron command” links it into /usr/local/bin on macOS and ~/.local/bin on Linux, a folder that has to be on your PATH.

Three conventions

Standard output is one canonical JSON value
Each call prints one value, ending at the value’s last character. The byte format follows law §3.4: compact, members sorted by bytes.
Misuse leaves standard output empty
For wrong arguments or an unreadable path, the exit code is 2, standard output has zero bytes, and the first line of standard error reads <reason> <subject>. The subject uses the command line’s own names alone: a flag from the flag table is written --name, and any other value or path is named only by where it stands among the arguments and its length, as in E_UNREADABLE #3 (15 bytes), so a private key or a node address carrying an access key stays with you, and terminals and logs see its place and length alone. A second line explains it for people, in Chinese when the system locale (the first of LC_ALL, LC_MESSAGES, LANG and LANGUAGE that is set) is Chinese and in English otherwise, and is outside the contract. Whether standard output holds any bytes tells a caller an answer from a misuse.
Status words pass through unchanged
GREEN, PARTIAL, FAIL, COMPLETE, GAPS and the like are written by the cores and passed on by the command line as they are.

When the law refuses an entry being written (E_ENTRY with the token E_BODY_FIELD, exit code 1), standard error carries one more line for people, naming the member and the flag that gives it, for example statement_md: missing or malformed; given by --statement; this line also follows the system language, is words for people, and leaves standard output and the exit code as they are.

Files are written one way: --out first writes a whole temporary file alongside, syncs it to disk, then renames it into place; when a file of that name already exists, the write stops and the existing file keeps every byte. kit-verify --originals-to takes originals out one way too: laid out in a staging folder inside the chosen folder, each checked against its fingerprint, then placed one by one, replacing nothing; a name already in the chosen folder refuses the whole batch, and nothing is written.

Exit codes

CodeMeaningExample
0Answered, affirmativeGREEN, COMPLETE
1Answered, negativeThe entry was refused, the write would break the ledger (E_WOULD_BREAK), the node refuses the gas estimate for a reason about this transaction or estimates it above 200,000 (E_GAS_REFUSED), the transaction was included but failed (E_TX_STATUS), what was sent before has lapsed (E_TX_VOID), a grant file does not open (E_GRANT_FILE), the chain already holds this key’s anchor of a hash given (E_ON_CHAIN), a record kit does not hold (E_KIT) or an original in it is not the one recorded (E_RECORDS), originals not taken out (E_EXTRACT, nothing written in the chosen folder), an encrypted record package that does not open, is damaged, or whose recipient address has no anchor on chain (E_ADDRESSED), attest or succeed through the desktop (E_ON_DESKTOP), the desktop refused the action (E_DESKTOP_REFUSED) or refused an anchoring before anything went out (E_SEND_REFUSED), network refusals aside, the credential missing, expired or malformed (E_CREDENTIAL_MISSING, E_CREDENTIAL_EXPIRED, E_CREDENTIAL_SHAPE), the desktop writing the data folder at this moment (E_HOME_HELD), a writer mark naming another machine (E_HOME_OTHER_MACHINE), a folder the desktop adopted (E_ADOPTED), a read-only data folder or a broken ledger (E_READ_ONLY), a ledger handed off (E_HANDED_OFF), a handoff not taken (E_HANDOFF), or the verdict is FAIL, BROKEN_CHAIN or NO_LABEL
2MisuseWrong arguments, an unreadable path, --key together with --key-file, a key file others can read, --form registry without --registry, --home with a verb or flag that does not take it, --key or --key-file with a data folder’s --ledger, anchor --ledger with --endpoint or any other of the eight flags it refuses, a --ledger naming a sealed folder outside its data folder, --to with --to-key or either with --as folder, a malformed address or a key off the curve, an encrypted package with no key to open it (E_ARGS --key --ledger --home), kit-verify given --key with --ledger, mcp given any flag; standard output is empty
3Answered, in betweenPARTIAL, GAPS, UNAVAILABLE; an anchor through the desktop or with the credential that was only queued (E_QUEUED); a record kit with a record not anchored, the chain not read or an original missing (E_RECORDS)
4Answer absentNode unreachable, nodes disagreeing, scan refused, no randomness available, a node refusing the gas estimate for its own reasons (E_UNREACHABLE), no answer from the desktop (E_DESKTOP), a network refusal from the desktop (E_DESKTOP_REFUSED), an anchoring refused for the network before anything went out (E_SEND_REFUSED), a recipient’s key not found while some network was not read through (E_ADDRESSED, token ADDRESS_CHAIN_UNREAD; through the desktop, E_DESKTOP_REFUSED with that code)

The weight of this table is that 3 and 4 each have a code of their own. Fold “not yet on chain” into 0, and a buyer takes an unanchored grant as cleared; fold it into 1, and a passing “not yet known” reads as “forged”. Fold “node unreachable” into 1, and a network fault reads as “this chain is fake”. A failed scan is an absent answer, and the caller retries or changes nodes.

Twenty-six subcommands

SubcommandWhat it does
keygenGenerate a key and print its address and private key
init ✦Write the ledger’s creation entry into an empty ledger
history ✦Append a record (--file records a file by the app’s convention)
grant ✦Sign a grant and write it to the ledger
revoke ✦Sign a revocation and write it to the ledger (ruling file digest optional)
adopt ✦Write an adoption entry; a co-signature with only one of its two halves is refused
attest ✦Produce a co-signature with an outside key
succeed ✦Write a succession entry (a key rotation or a handover)
annotate ✦Write a note
retract ✦Write a deletion entry (the target must be a record in this ledger that is still undeleted)
anchor ✦Anchor hashes on chain, through the registry contract or as a bare self-transfer; before signing it asks whether the chain already holds them, then estimates gas, and a rerun asks first; with --ledger naming a ledger in a desktop data folder, it sends that folder’s queue with the credential
scanScan for anchors using the chain settings (--endpoint takes http and https; with --ledger in place of --basis, the scan range comes from that data folder’s settings and ledger; with no --endpoint, the data folder’s own nodes, with the credential)
auditAudit a ledger against scan results and print a report and verdict (--ledger takes a ledger folder, a ledger in a desktop data folder (with the credential), a ledger mirror or a record kit (a .zkit file or a folder); --out saves this run’s audit input; an encrypted record package is refused with E_ADDRESSED (ADDRESSED_ELSEWHERE); kit-verify opens it)
check-grantRun the six checks on a grant (--grant takes a grant entry file or a .zkgrant grant file; over a desktop data folder’s ledger it reads the issuer’s whole ledger and so answers whether the grant was revoked)
chain-checkCheck a sublicense chain hop by hop (--hop <grant file>[=<audit input file>], repeatable)
depthDepth readings for a record
fpm-signSign a fingerprint manifest
ack-signSign an acknowledgement
badgeEncode or decode a credential (exactly one of --encode and --decode)
kit-export ✦Export a record kit, written once it passes its self-check; one file by default, a folder with --as folder; --to <address> or --to-key <public key> encrypts that one file to one recipient
kit-verify ✦Verify a record kit record by record (--kit takes a .zkit file or a folder): is each original the one recorded, is it anchored, judged as the desktop’s “Verify record” judges; --fragment gives a scan reading, and without it every record is unread; --originals-to takes the matching originals out into a folder that exists; an encrypted package is opened with --ledger <home>/ledger (this machine’s identities, with the credential), --key or --key-file
hand-overWrite the whole ledger into a handoff file (--out); this place stops writing it
take-overTake a handoff that follows on (--handoff); this place writes again
showShow an entry’s author, ID, type, previous entry, sequence and content
mcpLets AI apps call the command line through the Model Context Protocol (standard input and output, one message per line); see AI apps below
contractPrint the command line’s own contract: verbs, each verb’s flags (and its other table with --home), exit codes and refusal reasons

The twelve marked ✦ take --home: eleven are handed to the desktop, and succeed with --home always answers E_ON_DESKTOP; see Through the desktop below. Any other first word counts as misuse, with exit code 2.

Flags

All sixty-two flags are long flags, and each takes a value; every subcommand has its own table of flags, and a flag outside it counts as misuse. Members the law requires in an entry’s body may all be left off the command line; the core then refuses the entry under the law, and the command line checks the few items it needs for its own work. That way each rule of judgment exists once, in the core.

--key-file
Reads the private key from a file instead of --key, one or the other; the file must be readable by its owner alone. Every subcommand that takes --key takes it.
--originals-to
Taken by kit-verify: a folder that exists, into which every original matching its record is taken out, all of them or nothing written (E_EXTRACT); a signed folder comes out whole; taken, the answer adds taken (the names) and path.
--originals
Taken by kit-export from a data folder the desktop keeps (by --ledger with the credential, or --home through the desktop): none is its one word, and the chosen records’ originals stay out of the package. Left out, they go in, taken as the desktop’s export page takes them, and the answer lists originals and leftOut. Given with a plain ledger folder, it is misuse; that folder’s originals are each given with --file.
--to, --to-key
Taken by kit-export, one or the other: --to is the recipient’s address, whose public key the command line recovers from an anchoring transaction that address itself signed on chain; --to-key is a public key, 0x and 66 or 130 hex digits, a point of the curve. Only one file is encrypted, so either with --as folder is misuse. --to on a plain ledger folder needs --endpoint (each chain one the built-in deployments table names); on a desktop data folder’s ledger, that data folder’s network and this machine’s read-only networks are read, and --endpoint is refused.
--key (kit-verify)
The key that opens an encrypted record package; a plain package takes none. Given with --ledger, misuse.
--proxy
Taken by anchor, scan and kit-export with --to: system (the default), none, or one proxy address scheme://[user[:password]@]host:port, the scheme http, https, socks5 (or socks5h) or socks4 (or socks4a, a user id alone); the user name and password are percent-encoded, at most 255 bytes each, and a password written on the command line is visible to other processes of this machine while the command runs. Nodes on this machine are always reached straight; with a proxy address, private, link-local and .local nodes are too. system reads the terminal’s proxy variables first: when any of https_proxy, http_proxy or all_proxy (either case) is set, they are followed, with no_proxy, on every system; with none set, the system’s proxy settings are read: the automatic configuration script the system names first, then the explicit proxies (macOS its network settings, Windows the settings the system answers, Linux the KDE or GSettings settings stored on disk, else the environment); the system’s automatic proxy discovery is left unread. The data folder roads with the credential (anchor --ledger, scan --ledger with no --endpoint, kit-export --to --ledger) without --proxy use this machine’s proxy setting, and its following the system reads the system’s settings alone, leaving the terminal’s proxy variables unread; anchor --ledger takes no --proxy.
--home
Hands the work to the running desktop app; see below.

Each subcommand’s flags and the environment variables (the overall deadline of each exchange with a node ZKA_TIMEOUT_SECS, 30 seconds by default; the answer limit ZKA_MAX_ANSWER_BYTES, 64 MiB by default; and so on) are listed in CLI-SCHEMA.md.

Example

Generate a key, create a ledger, record a file, anchor it, audit:

zikaron keygen # {"address":"0x…","ok":true,"privkey":"0x…"} zikaron init --ledger ./ledger --key-file ./key.txt --statement "Records of my work" zikaron history --ledger ./ledger --key-file ./key.txt --file manuscript.pdf # {"entryId":"0x…","ledger":"…","ok":true,"seq":1,"written":true} zikaron anchor --key-file ./key.txt --endpoint <chain-id>=<node> \ --form registry --registry <contract address> --hash <entryId> zikaron scan --endpoint <chain-id>=<node one> --endpoint <chain-id>=<node two> \ --basis basis.json > fragment.json zikaron audit --ledger ./ledger --fragment fragment.json echo $?

history --file fills the entry by the convention the app uses to record a file: content is the SHA-256 of the file’s bytes, and mode is {"mark":"bytes-sha256/1","toolchain":<the SHA-256 of the text "bytes-sha256/1">}; for one file, the command line and the app write these two members alike. You can also leave out --file and give --content, --mark and --toolchain yourself; the two ways cannot be mixed.

Node addresses may be http:// or https://, in any case, an IPv6 address in brackets; https checks the certificate chain and host name against the roots compiled into the program, the same transport the app uses. Every question has one 30-second overall deadline, an address that resolves to several IP addresses has each tried, a reading question cut off mid-connection is asked once more on a fresh connection, and a transaction is broadcast once; an access key inside a node address is hidden in all output.

anchor takes exactly one --endpoint: it reads that node’s base fee and the paid tips of the last 20 blocks, sets the fee by the app’s rule (blocks whose median is zero are left out unless all are zero), then asks the node to estimate gas for this very transaction and carries one and a half times the estimate, rounded up, at most 200,000. If the node refuses the estimate for a reason about this transaction (it would revert), or estimates it above 200,000, it refuses with E_GAS_REFUSED; if the node refuses for its own reasons (a rate limit, an unsupported method, credentials needed, a wrong chain and the like) or does not answer, it reports E_UNREACHABLE; either way the command stops before broadcasting. Once sent, it asks for the receipt round after round until --wait-secs runs out.

What the chain holds stays unsent. With --form registry and --hash, before signing, anchor asks its node whether the registry already holds this key’s anchor of any of those hashes (the Anchored logs read as the scan reads them, from the registry’s deployment block to the head). Any one there answers E_ON_CHAIN, names listing them and tx and blockNumber the earliest, and nothing is sent; a node that cannot answer gives E_UNREACHABLE, and nothing is sent. --form bare and --calldata are sent as given.

A rerun asks first. Run with its own key, anchor keeps the nonce and hash of every transaction it signs for one anchoring (the same chain, key, recipient and data) in cli-sent/ in the machine folder, before broadcasting, and keeps these two alone. When the same command runs again, it first asks the node where those transactions stand, by their hashes: one already included is answered as included; one still in the pool is waited on; if none is held and their nonce is unused, it signs again at that same nonce, so at most one can ever be included; if their nonce was used by another transaction, it answers E_TX_VOID and stops there, and the next run starts afresh. Running the same command again after it succeeded therefore answers the earlier transaction, and one anchoring is paid for once.

Each question scan asks names the senders in the scan range, so only their logs come back; when a node declines, the same question is asked again, and only after three refusals is the range split. basis.json states the scan range: which chains, which registry contracts, which senders, and the start and end blocks; the format is in law §9.4. The command line keeps no record of facts checked before, and every scan asks about every log.

Audited before written

Every subcommand that writes an entry (init and retract included) passes through one gate: once the entry is signed, the core audits “this ledger plus this entry” offline, and any chain finding of law §8.3 the ledger did not already have (an old key writing after a key change, a sequence gap, a second entry at one place, a link to the wrong entry) refuses the write with E_WOULD_BREAK, names listing the findings, and not one byte is written. --seq and --prev given by hand pass the same gate. When a ledger holds two roots and no --root is given, every write is refused with E_TIP_FORKED.

Through the desktop

With --home <the desktop’s data folder>, eleven subcommands, init, history, grant, revoke, adopt, attest, annotate, retract, anchor, kit-export and kit-verify, are handed to the running ZIKARON Desk, unlocked and holding that data folder as its writer: the entry is written into the desktop’s ledger with the desktop’s identity and shows in its window at once; kit-verify is verified by the desktop on its own networks, a package encrypted to one of its identities opened with that identity first; the private keys and the passcode stay in the desktop, and the desktop does all the writing.

  • While “Through the desktop app” is on in Settings › Command line and AI control and the desktop holds the data folder, it keeps a local channel open for it: on macOS and Linux a socket file in the machine folder readable and writable by its owner alone, on Windows a named pipe only this user can reach. Once connected, each side asks the system who the other runs as and refuses another user. Locking, closing or switching the data folder, or quitting, closes the channel; while “With a credential” is on, the desktop keeps it closed.
  • Arguments are judged for misuse as usual first; with --home, each subcommand has a table of its own, and the desktop decides the ledger, key and sequence itself (history takes --file and --note, and anchor takes --home alone, for example); a flag outside the table is misuse. Requests are done one at a time in the order they arrive, along the same action path in the desktop as a click.
  • anchor follows “Putting on chain from the command line” under “Anchoring” in Settings › Command line and AI control: “Send automatically” sends as the queue page’s “Put all on chain” does, answering as anchor --ledger does; “Queue only” only queues and answers E_QUEUED (exit 3).
  • attest and succeed always answer E_ON_DESKTOP: attesting asks for the passcode, given on the desktop alone, and handing the ledger to another key is done on the desktop by hand, so succeed leaves the desktop unasked. kit-export takes --entry, --note, --out, --as (one file by default), --to, --to-key and --originals; the chosen records’ originals go in as the desktop’s export page takes them (none with --originals none), other attachments and proof bundles are chosen on the desktop, and the key for --to is looked for on the desktop’s network and read-only networks. kit-verify takes --kit and --originals-to.
  • When the desktop is locked, has not opened that data folder or has quit, the answer is E_DESKTOP (exit 4); while “With a credential” is on, its detail is ALONE: write without --home. anchor refused before anything goes out answers E_SEND_REFUSED, and E_ON_CHAIN when the chain already holds the anchors; another verb the desktop refuses answers E_DESKTOP_REFUSED, its token the desktop’s own code; a network refusal is exit 4, any other 1. When kit-verify takes no originals out or opens no encrypted package, token is the desktop’s code (EXTRACT_EXISTS, EXTRACT_LINK and the like, or the codes of E_ADDRESSED); ADDRESS_CHAIN_UNREAD exits 4.

The command line with --home finds the machine folder by the desktop’s own rule. The flags each subcommand takes with --home are in section 11 of CLI-SCHEMA.md.

With a credential

The “Automation level” group in Settings › Command line and AI control has two switches, and there is one command-line path at any time. With “Through the desktop app” on, the way is --home. With “With a credential” on, “Through the desktop app” is greyed and the desktop keeps its channel shut; the command line, without --home, reads and writes the ledgers the desktop keeps sealed and sends their queues with a credential in the machine folder that only its owner can read and write, the desktop open, locked or closed. Turning “With a credential” on asks for the passcode and a validity: days, hours and minutes, together a minute to a year, or “Does not expire”.

  • Writing: with --ledger naming the ledger folder in a data folder, history, grant, revoke, adopt, succeed, annotate and retract write the sealed ledger with the credential, signing with the key the desktop’s vault keeps for that identity and role; --key and --key-file are misuse there. The entry passes the same audit (E_WOULD_BREAK) and is queued for anchoring as the desktop queues its own; the file of history --file goes into this machine’s index of signed files, so an exported record kit carries the original. init is refused there with E_NOT_EMPTY.
  • Reading: audit, check-grant, chain-check, depth, show --entry and kit-export read that ledger by the same opening, taking no writer lock. kit-export takes the originals, the terms documents and the anchored-on: line as the desktop does, the originals staying out with --originals none; scan --ledger takes its scan range from the data folder’s settings and ledger, its last block the head its nodes give, and with no --endpoint its nodes from the data folder’s settings too. kit-export --to looks for the recipient’s key on the data folder’s network and this machine’s read-only networks. kit-verify --ledger takes, with the same credential, every seat’s key of every identity on this machine to open an encrypted record package.
  • Sending: anchor --ledger sends the data folder’s queue with the credential: the chain, registry and nodes from the data folder’s settings, the proxy from this machine’s; it refuses --key, --key-file, --endpoint, --form, --registry, --hash, --calldata and --proxy, and --wait-secs defaults to 90 seconds. At “Send automatically” it sends everything the queue can send, waits for the receipt and settles it; at “Queue only” it answers E_QUEUED. With nothing to send and a batch in flight, it asks about that batch by its hash; a batch no node’s pool holds whose nonce is still unused is signed again as recorded at that nonce and sent under “Send automatically”; with neither, the answer is E_SEND_REFUSED with token QUEUE_EMPTY. “Resend with higher fees” is pressed on the desktop alone.
  • Taking turns with the lock: the command line takes the data folder’s writer lock for each write and lets it go after; the desktop then does the same, reading again first if the command line wrote. A send holds the lock while it readies, signs and broadcasts the batch, lets it go during the receipt wait and takes it back to settle; a lock not taken back within sixty seconds answers E_HOME_HELD, the batch staying in flight.
  • Write gates, asked before a write, a send or a handoff: a data folder under its read-only mark (LEDGER_NOT_FETCHED, NEWER_ELSEWHERE) or a ledger whose own entries break its chain (BROKEN) answers E_READ_ONLY for a write or a handoff and E_SEND_REFUSED for a send, token that code; a ledger handed off answers E_HANDED_OFF for a write and E_SEND_REFUSED (HANDED_OFF) for a send.
  • Refusals, each exit 1 with nothing written: E_CREDENTIAL_MISSING (the switch is off), E_CREDENTIAL_EXPIRED (expired, and removed), E_CREDENTIAL_SHAPE (it fails to read or open, or belongs to an earlier master key), E_HOME_HELD (the desktop is writing at this moment; try again shortly), E_HOME_OTHER_MACHINE (the writer mark names another machine). The reading verbs are refused by the three credential reasons and E_HOME_OTHER_MACHINE alike.
  • The folder after adoption: once the desktop has taken in a plain ledger the command line made (“Import key”, then “Adopt existing ledger folder”), every write to its original folder, hand-over and take-over included, answers E_ADOPTED, with “With a credential” on or off, and the folder keeps every byte; to go on writing it from the command line, turn on “With a credential” and give the ledger in the data folder.

Taking originals out and encrypted record packages

kit-verify --kit <package> --originals-to <folder> verifies record by record as usual, then takes the originals that match their records into that folder under the names they had; a signed folder comes out whole under the paths it was signed with. The originals are read from the package again, laid out in a staging folder inside the chosen folder, each checked against its fingerprint, then placed one by one, replacing nothing; a name already there, a link, two originals taking one name, or any step failing answers E_EXTRACT, takes back what was placed, and leaves the chosen folder as it was. A plain package needs no home and no key.

kit-export --to <address> or --to-key <public key> exports one .zkit only the recipient opens; the answer is the plain package’s. kit-verify opens it: with the credential, --ledger <home>/ledger offers this machine’s identities; directly, --key or --key-file; through the desktop, the desktop’s identities. The opened plaintext sits in a folder of its own in the system’s temporary place and is removed when the command ends. No key opening it answers ADDRESSED_NOT_RECIPIENT, a segment that fails ADDRESSED_BROKEN, a head that does not read ADDRESSED_HEAD. The format is under Files and formats.

Handing a ledger over

A ledger can pass back and forth between two places, such as a command line’s ledger folder on a remote machine and the desktop’s data folder here, one place writing at any time. hand-over --ledger <this place> --out <file> writes the whole ledger into a handoff file (.zkhand) and this place stops writing it: a write answers E_HANDED_OFF; a handoff lost on the way is made again, the same, by running it once more. take-over --ledger <this place> --handoff <file> takes a handoff that follows on: every entry this place has is in it and its entries make one line; then the entries this place lacks are written in sequence and this place writes again. A place that handed its ledger off takes back only the handoff after its own. Anything else answers E_HANDOFF, token NOT_BACK, AHEAD, NOT_ONE_LINE, E_HANDOFF_NOTE or the file layout’s code. This machine’s side reads and writes with the credential, the desktop locked or not, and a desktop that is open shows the new entries at once. Whether an entry is on chain stays out of the handoff: the desktop reads it from the chain at its next ledger check and queues only what the chain lacks.

AI apps

zikaron mcp lets AI apps call the command line through the Model Context Protocol (MCP): the AI app starts it as a child process, and each line on standard input and output is one JSON-RPC 2.0 message, one canonical JSON value; it opens no port and no local channel and writes no file, and exits 0 when its input closes. It takes no flag and holds no right of its own: each tool call starts this same program again and runs that verb as a person would type it, answering with that command’s bytes and exit code. A write tool checks at each call whether this machine holds the credential: if so it goes --ledger <home>/ledger, otherwise --home <home>. Protocol versions 2025-11-25 and 2025-06-18 are spoken; the full contract is section 13 of CLI-SCHEMA.md, and how to connect is under Integration.

Time is injected by the caller

Deadlines and periods are judged by chain time and the moment injected with --now; when --now is left off, chain time alone applies. Every moment comes from the caller, so the same input always reaches the same verdict.

Reading the app’s own ledger

A ledger in ZIKARON Desk’s data folder is encrypted (its files start with zikaron-local/2) and the command line holds no passcode. While “With a credential” is on in Settings › Command line and AI control, the command line reads and writes the ledgers in the desktop’s data folders with that credential; see With a credential above. A ledger folder copied out of its data folder fails to read, refused as misuse with exit code 2:

E_UNREADABLE #3 (40 bytes) Locked: this is local data ZIKARON Desk keeps sealed; the command line reads it only as the ledger of a home the desktop keeps, with the credential

To write into the app’s own ledger, turn on “With a credential” and point --ledger at the ledger folder in the data folder, or hand the work to the desktop with --home. To let a command line elsewhere read it, export a “Ledger mirror” or a record kit in the app first: the --ledger of audit (and, through it, check-grant, chain-check and depth) and of show --entry can point straight at the mirror folder (the level holding mirror.json) or a record kit (a .zkit file or a folder); a kit is first checked under the kit law and refused with E_KIT if it does not hold; an encrypted record package is refused with E_ADDRESSED (ADDRESSED_ELSEWHERE), and kit-verify opens it. The subcommands that write entries take ledger folders and the ledgers in desktop data folders, and init takes ledger folders alone; to pass one ledger between two places, use hand-over and take-over; see Handing a ledger over above.