By the end of this article you will know what the command line is for, how to install it, and what it can do. You will also know how it treats your API key and how it handles a write.
Who is the Uku CLI for?
Section titled “Who is the Uku CLI for?”The Uku CLI is for people and programs that already work in a terminal. Examples include a developer scripting a change across many records, and a CI job. Coding agents such as Claude Code or Cursor also use it, operating Uku on someone’s behalf.
The Uku CLI is not the right surface for non-technical staff. Someone who wants to ask a question in plain language should use the AI assistant instead. The AI assistant needs nothing installed and no credential of its own on their machine.
Its advantage over the assistant is economy. A command is a single line of text, so an agent can chain several operations into one step. Without chaining, each operation costs a separate round trip. When the work is a list of changes rather than one question, that difference is the reason to reach for the command line.
Install the Uku CLI
Section titled “Install the Uku CLI”The Uku CLI is a single self-contained program. There is no runtime to install beside it, no package tree and no interpreter — it is one file you put somewhere on your PATH.
On macOS and Linux, one command installs it:
curl -fsSL https://getuku.com/install-cli | shThe install takes a few seconds and asks nothing of you beyond three ordinary tools — curl, openssl and a checksum tool. The installer refuses to run without them, rather than skip a check. In order, it:
- Finds the newest release, and works out which build fits your machine — macOS or Linux, Intel or Apple silicon and ARM.
- Downloads the fingerprint list for that release, together with the signature that proves Uku published it. Checks that signature against a key built into the installer itself.
- Downloads the one build for your machine and checks its fingerprint against that signed list.
- Installs it to a folder on your PATH, and adds that folder to your PATH if it is missing. Warns you if a shell alias named
ukuwould hide it. - Offers to sign you in and to connect your coding agents, if you are at a terminal. Say no and nothing else happens.
If any of those checks fails, nothing is installed. Not a partial install, not a warning you can click past. The installer stops and says what failed, and a missing signature counts as a failed one.
Check it worked with uku --version, and uku doctor once you have signed in.
Installing on Windows
Section titled “Installing on Windows”There is no one-line installer for Windows, and the script says so rather than half-working. Download it by hand instead: open the project’s releases page, take the newest windows-amd64 file together with SHA256SUMS, SHA256SUMS.sig and release-pubkey.pem beside it. Check that the file’s fingerprint matches its line in SHA256SUMS. If you have openssl (Git for Windows and WSL both ship it), also check the signature on SHA256SUMS against the public key. The signature check confirms the list is really Uku’s — the one-line installer does both checks for you automatically. Without openssl you have checked integrity only. Then rename the file to uku.exe and put it in a folder on your PATH. The exact commands are in the project’s README.
Building from source
Section titled “Building from source”Building it yourself is always available, and it is the answer for a platform the published builds do not cover. Clone the project, run its build script, and copy the resulting program onto your PATH. Building needs Go 1.26.8 or newer and nothing else — no separate build tool, no code generation step.
Keeping it up to date
Section titled “Keeping it up to date”uku update upgrades it in place. The update fetches the same signed installer, checks the signature, and runs it, so an update passes through exactly the checks a fresh install does.
Nothing updates by itself. At most once a day, while running an ordinary command, the CLI checks whether a newer version exists and prints one line if it does. The check stops there — nothing is downloaded and nothing is installed until you run uku update yourself.
How do you sign in?
Section titled “How do you sign in?”Signing in to the Uku CLI takes one command, uku auth login. The command prompts for the two values every API v3 request needs: your Company UUID and an API key. The CLI checks them against the API before writing anything to disk. A mistyped key then fails at the prompt rather than on your first real command.
Who can do this. Company Owners and Company Admins on the Elite plan can generate the key the CLI signs in with. Anyone holding a key can then use it.
Path: Settings & Apps → Public API → Public API
Creating the key is described in full in Public API v3. The CLI uses an ordinary v3 key and adds no credential of its own.
Once signed in, the credential is stored in a file under your home directory that only your own user account can read. The file is parsed, never executed: a damaged or tampered profile is treated as data, so nothing in it can run as a command.
You can also keep the key in your operating system’s credential store instead — macOS Keychain, or the Secret Service on Linux. The credential store is off unless you switch it on. Being exact about what it buys matters. The key is then not in a file the CLI wrote, so a backup or a synced dotfiles folder does not carry it. The credential store does not hide the key from anything already running as you.
If you hold several companies in Uku, the CLI keeps one profile per company under a name you choose. You switch between them with a flag on a single command, or by making one of them active. Keeping a sandbox company beside your real one is the recommended habit: rehearse a change there, then run the same command against the firm.
What can you do with it?
Section titled “What can you do with it?”Everything the CLI does is the public API underneath, so the answer to “can it do X” is usually yes. What it adds on top is the everyday work, shaped so a person or an agent can run it without reading an API reference first.
- Look things up. Clients, tasks, time entries, invoices, contracts, projects, contacts, teams and the audit trail all list and open from the command line. Search by name, or paste a link from the browser, instead of hunting for an id. When a name matches more than one record, the CLI refuses and lists the candidates rather than guessing.
- See real work in the task list. An unfiltered task list shows the work a person would recognise as work. Magic-button timer rows and both kinds of workflow template rows are left out, and the count follows the same rule. Ask for the timers or a template’s rows and you get them.
- Log a timesheet in one request. Up to 200 time entries go up together, in a single transaction: either all of them are recorded or none is. One rejected line means nothing was written, and the CLI names the line that caused it. There is never a half-loaded timesheet to reconcile.
- Create and roll out contracts. A contract and all its rows are created as one thing. A preview asks the server what would happen without writing anything, so you see what would be created and what would be refused first. Rolling a template out to a list of clients is one command, and any client it could not act on is named with the reason.
- Debug a webhook. List your subscriptions, see one row per delivery attempt with whatever your endpoint answered, re-send a single event, and unsubscribe. Creating a subscription and rotating its secret are deliberately not CLI commands. Both answer with the signing secret, so a command would leave a live credential in your shell history and in an agent’s transcript.
- Find billable work an invoice already locked. The missed billing report runs the billing engine itself over your contracted clients, so what it reports is what a re-bill would really charge. The report is slow by nature, one pass per contracted client, so narrow it to one client when you can.
- Read reports. Headline figures, a series, a breakdown and hours per client or person come back as plain columns and rows, exactly as the server sent them.
Run uku --help for the current command surface. The list of commands is deliberately left out here. The CLI’s own help is generated from what the tool actually does, and a copy here would age.
What is a key allowed to do?
Section titled “What is a key allowed to do?”A key’s permissions are the API’s permissions — the CLI adds no rights of its own and removes none. What a command may do is decided by the key you handed it.
When you generate a key you choose between the Read, Edit and All scopes, and you decide separately whether the key may reach financial data. The financial choice is its own checkbox rather than part of a scope. The separation is the useful part: read access and money access are independent. A request that touches financial data with a key that lacks the financial permission is refused by the API, whichever scope the key holds. The check runs in Uku rather than in the CLI.
The practical consequence for agent work: give a coding agent a Read key, which can look things up and answer questions, while writes are refused. Add the financial permission only when the job genuinely needs invoice or rate data. Give each tool its own key too, so you can revoke one without disturbing the rest. The full permission model, including exactly which records count as financial, is in Public API v3.
How are writes guarded?
Section titled “How are writes guarded?”Writes through the CLI are deliberate rather than incidental, because the same terminal that lists clients can also send an invoice.
- A write outside a terminal needs
--yes. Run without a person present — in a script, a CI job or an agent. A write that carries no explicit confirmation flag is refused rather than performed. - A write in a terminal prompts. You confirm before anything is sent.
- A deletion restates its target before asking, so you can see which record is about to go.
- A partial failure is never reported as success. Sometimes the API accepts a request but reports that some of the records inside it failed. The CLI names those failures and exits with an error, rather than printing “done” over work that did not happen.
- Every non-GET is written to a local log in the CLI’s own configuration directory, readable only by your user account.
The log is worth describing precisely, because it is the file people attach when something has gone wrong. Each write adds one tab-separated line: the time, which account was used, the method, and the request path with any query string removed. The line also carries the status the API answered with. There are no request or response bodies in it and no key. Because the query string is stripped, a client name you searched for does not reach the file. Record ids in the path do reach it, though — a receipt has to say which record changed. The log rotates once it passes five megabytes or ten thousand lines, keeping one previous generation.
When does a failed write get sent again?
Section titled “When does a failed write get sent again?”Almost never, and the exception is narrow enough to state exactly: the CLI resends a write automatically only when the API answered 428. A 428 response means the API refused the request for want of a version stamp, and nothing was changed. Resending that one is safe by construction — the CLI fetches the current stamp and sends the request once more.
Every other failure is handed back to you, because in every other case the outcome is genuinely unknown:
| The API answered | What it means | What the CLI does |
|---|---|---|
428 — version stamp missing | The write was refused; nothing changed | Fetches the stamp and resends once |
412 — someone else changed the record | The write was refused; nothing changed | Stops. Re-read the record, re-apply your change, write again |
429 — rate limited | For a write, the outcome is unknown | Stops. Check with a read before sending anything else |
5xx or a timeout | Outcome unknown | Stops, for the same reason |
The reasoning behind the 412 case is the one to internalise: a blind retry there would overwrite the edit someone just made in Uku. Reads are different — they change nothing, so the CLI may retry one when the connection itself failed.
How is your API key protected?
Section titled “How is your API key protected?”An API key opens your firm’s live data, so the CLI is built to keep it out of the places credentials usually leak from.
- The key is not on the process list. Authentication headers are set inside the program rather than passed as arguments, so no
psoutput carries the key while a request is in flight. - The key is masked in output. Status messages and errors show only a fragment of the key. The single exception is the command whose whole purpose is to print the credential for use with another tool. The command warns on the error stream every time it runs.
- Connections are TLS 1.2 or better. A plain
http://address is refused before anything is sent, unless the host is your own machine. The exemption covers the loopback addresses and nothing wider, so a key cannot leave in the clear because a base URL was mistyped. - A non-default host announces itself. If the CLI is ever pointed at somewhere other than Uku’s own API, it prints one line. The line names the host your credentials are about to travel to. The quiet flag does not suppress that line. Where your key went is not chatter — it is the line a person supervising an agent needs to see.
How do you teach a coding agent to use it?
Section titled “How do you teach a coding agent to use it?”Coding agents learn the CLI from a file the CLI writes for them. Running uku setup agents installs a skill file for Claude Code, Cursor and Codex, plus a block in the project’s AGENTS.md. An agent then picks up the commands, the exit-code model and, most importantly, the safety rules, without anyone pasting instructions into a chat.
There is a second, live channel for the same job: adding --help --agent to any command returns a machine-readable card describing that command. The cards are generated from the CLI’s own command surface rather than written by hand, which is the point. They cannot describe a command that does not exist, and they cannot fall behind one that changed.
Both channels lean on the negative knowledge, the “this does not work the way you would assume” kind, which is what stops an agent guessing. What an agent may do with any of it is still bounded by the key you gave it.
What if there is no command for the thing I need?
Section titled “What if there is no command for the thing I need?”Most of the API’s operations have no command of their own here, and that is a decision rather than a gap. Things nobody scripts stay where a person does them: setting up the company, authoring a workflow template, sending client e-mail. The CLI says so plainly rather than leaving you to wonder. Instead, uku api <METHOD> <path> reaches every one of those operations, using the credentials and the write confirmation you have already set up. A missing command never blocks you this way.
How does this relate to the API and the AI assistant?
Section titled “How does this relate to the API and the AI assistant?”The command line, the public API and the AI assistant are three doors into one API, not three systems. Permissions, rate limits and the financial gate are enforced in one place behind all of them, and all three are part of the Elite plan.
Choosing between them is mostly a question of who is holding the tool. A person asking a question in plain language wants the assistant. Software running on a schedule wants the API. A developer or a coding agent working through a list of changes wants the command line. Uku for AI agents and developers compares them side by side. Your data and AI assistants covers what Uku records and what travels to an AI provider when an assistant is involved.
Troubleshooting
Section titled “Troubleshooting”Why does my terminal say uku is not found after installing it?
Section titled “Why does my terminal say uku is not found after installing it?”The program installed, but your shell has not picked up the folder it went into. Open a new terminal window and try again. If it is still not found, look for the PATH line the installer added to your shell configuration file. Run that line yourself. uku doctor reports what it can see on your PATH.
Why does the installer say this platform is not supported?
Section titled “Why does the installer say this platform is not supported?”The one-line installer covers macOS and Linux on Intel and on Apple silicon or ARM. On Windows it stops rather than half-installing — download the Windows program by hand from the releases page, as described above. On anything else, build it from source.
The install stopped with a signature or fingerprint error. Should I try again?
Section titled “The install stopped with a signature or fingerprint error. Should I try again?”No. Do not re-run it, and do not work around the check. A failed signature, or a fingerprint that does not match the signed list, is exactly what a tampered download looks like. The installer stopping means nothing was installed. Report it to Uku with the message it printed.
Why was my write refused in a script or CI job?
Section titled “Why was my write refused in a script or CI job?”A write with no person present needs --yes. Without a terminal to prompt in, the CLI refuses rather than acting unattended. Add --yes to the command, or run it interactively and confirm at the prompt.
Why did re-running a command create two records?
Section titled “Why did re-running a command create two records?”Because you asked twice. Every write carries an idempotency key, but the CLI mints a fresh one on each run, so a second run is a genuinely new request. Pass --idempotency-key with a value you choose and reuse it on the retry, or use --batch with --resume for a run of many changes.