CLI
The same operations, from a terminal or a CI job.
Install
The CLI is not published to npm yet. Do not run npx duvapps: that would download whatever package happens to hold that name, which is not ours. Until it is published, it is built from the platform repository:
cd duvapps-platform
npm ci
npm run build:cli
alias duvapps="node $PWD/packages/cli/dist/duvapps.js"
duvapps --helpSign in
duvapps auth login # the Studio, in your browser
duvapps auth login --target https://acme.gtable.app/crm # one app
duvapps auth login --device # no browser on this machine
duvapps auth statusIn CI, skip the login: set DUVAPPS_TOKEN to one of your API keys andDUVAPPS_URL to the Studio or the app it is for.
Everyday commands
Every operation of the API is a command, named after it: records.list isduvapps records list. Path parameters come first, in order; everything else is a flag, or --body with the whole request as JSON.
duvapps records list tbl_8fj3kq2wmv5d --view-id viw_e4ks9mz2bh7w
duvapps records get tbl_8fj3kq2wmv5d rec_4nqw8e2hzk7s
duvapps records create tbl_8fj3kq2wmv5d --records '[{"Name":"New deal","Amount":1000}]'
duvapps files upload tbl_8fj3kq2wmv5d --file ./contract.pdf --record-id rec_4nqw8e2hzk7s
duvapps pages code set app_5mg8rw2kx4tn pag_t3w9hy6kd2cn --source "$(cat Dashboard.tsx)" --note "New chart"
duvapps rules simulate app_5mg8rw2kx4tn --groups grp_v6nh3ta8rk2e --table-id tbl_8fj3kq2wmv5d --op readOutput is JSON whenever it is not going to a terminal, and the exit code says what kind of failure it was, so a script never has to read prose.
Deleting
A deletion that cannot be undone asks for the thing's name, the same proof the Studio asks you to type:
duvapps tables delete app_5mg8rw2kx4tn tbl_x2c7nw4hq9fk --confirm "Old deals"Versions
The CLI says which version it is in its user agent. When the server expects a newer one it says so on stderr; update then, because older versions sent some request bodies incompletely.
Why the CLI has more than MCP
Two things: uploading files, because a terminal can send bytes and a model cannot, and walking every page of a list, because a script can loop. Everything else is at parity by construction: the commands are generated from the same definition as the API and the tools, so a new endpoint is a new command the day it ships.