Lotics CLI
Command-line interface for AI agents to interact with Lotics — a system of record with structured data, document generation, workflow automation, and a built-in web UI.
Through this CLI your agent can:
- Tables & Records — Create tables with typed fields (text, number, date, select, record links, formulas, files). Write, query, update, and aggregate records. Users see and edit the same data in a spreadsheet-like web UI with views, filters, and sorting.
- Document generation — Excel, Word, and PDF templates with variables. Call
generate_documentwith data and get the filled file. - Automations — Event-driven workflows: when a record is created, when a field changes, on a schedule. Chain steps: update records, send emails, call webhooks, run AI. Set up via CLI — they run without the agent being online.
- Files — Upload, attach to records, download. PDFs, images, spreadsheets.
- Apps — Build dedicated data interfaces with configured views, filters, and actions. No frontend code.
- Knowledge — Long-form reference documents the agent can search and read.
- Admin — Members, groups, role-based permissions, audit logs.
Five minutes, from nothing
Install the CLI — one command, nothing else required:
curl -fsSL https://lotics.ai/install.sh | bash
Then one more command creates the account, applies your model to the workspace — its tables, first rows and apps — and prints a one-time sign-in link:
lotics setup model.json --email you@company.com
Add --json and it prints a single object instead of progress — the organization, the workspace,
the app ids and the sign-in link — which is what you want when an agent is reading the output
rather than a person.
Or let your agent work it out
Paste this one line into your coding agent — Claude Code, Cursor, Codex, whichever you use. Copy the line from the setup section; the assistant fetches the instructions itself. It asks what you manage, reads the example model for your trade, models your own tables from what you said, and ends at a browser you are already signed in to.
Set me up on Lotics: fetch https://lotics.ai/docs/prompt.md and follow it.
Everything the model path needs before signup answers with no account, so the model is written
and checked before anything is created. --email is only
how a brand-new account gets made: passing it while already signed in is refused rather than quietly
making a second one, and re-running auth signup with an address this machine already holds tells
you so instead of failing.
What you end up with is yours: ordinary tables and ordinary apps, live in your workspace — your agent
edits them from there, and so can you. lotics model pull writes the workspace’s model, apps
included, for your agent to change and apply again, and lotics docs building_an_app is the
sequence for everything after.
Install
macOS, Linux and WSL:
curl -fsSL https://lotics.ai/install.sh | bash
Windows, in PowerShell:
irm https://lotics.ai/install.ps1 | iex
Either one downloads a single compiled executable and checks it against a published checksum. There is no Node.js, no npm and no package manager involved, nothing is installed system-wide, and deleting the file removes it.
Running inside an agent sandbox or behind a corporate proxy? Three hosts have to be
reachable, and they are three different steps — lotics.ai serves the installer,
downloads.lotics.ai serves the executable it fetches, and api.lotics.ai is what the CLI
talks to afterwards. Allowing only the first gets you a download that stops halfway. Those
three cover applying a model as well, because its apps are built and deployed on Lotics —
registry.npmjs.org is needed only for a custom-code app you build on this machine.
Confirm it worked — this prints a version number:
lotics --version
lotics upgrade updates it in place — it runs whichever installer this copy came from, so
you do not have to remember. Re-running the installer directly does the same thing, and
either is a no-op when you are already current. The CLI says when there is a newer version.
Applying a model needs nothing more either: Lotics deploys every app it declares, and nothing lands
on your disk. Node 18+ comes in only for a custom-code app built on this machine —
lotics app create --custom, lotics app pull and lotics app deploy are what need it. Everything
else — signing in, applying a model, working with tables and documents — runs
off the executable alone.
Authentication
Create a new account
lotics auth signup # interactive prompts
lotics auth signup agent@co.com --name "My Agent" # non-interactive
Signup flags:
--name <name>— display name (defaults to email prefix)--timezone <tz>— workspace timezone (defaults to this machine’s, e.g.Asia/Ho_Chi_Minh)
Signup creates an account, organization, workspace, and API key in one step. A magic link email is sent so you can access the web app — no password needed.
Sign in an account you already have
lotics auth login you@co.com # prints a link and a code, then exits
lotics auth login you@co.com --wait # stays open until you press Confirm
lotics auth login you@co.com --local # pins this directory to that org, and waits
Use this on a new machine, or to add another organization to one that already holds a key — the organization you pick on the page becomes the active one. The command prints a link — also emailed to you — and a four-character code, then exits. Open the link, sign in, check that the page is showing that same code, and press Confirm. If the page says the request is for another account, log out there and sign in with the email you gave the command; then run the command you wanted and this machine picks the key up. The link and the code are good for fifteen minutes — after that, run the command again for a new pair. Nothing to find in Settings and nothing to paste. lotics setup does the same by itself when the email you gave it already has an account.
Access the web app
lotics auth web
Sends a magic link email to your account’s email address. Click the link to access the web app. Requires a prior signup or setup.
Use an existing API key
lotics auth api-key # interactive prompt
lotics auth api-key ltk_... # registers the key's org as a profile
API keys are created in the Lotics web app under Settings → API Keys. A key belongs to one organization, so this registers that org as a named profile — run it once per org. Registering another key adds a profile; it never overwrites an existing one.
Switch between organizations
Each saved key is a profile. Switch the active org with no re-pasting:
lotics org # list saved orgs (marks the active one)
lotics org use acme # switch active org by name (or org id)
To work in several orgs at once, pin a directory (e.g. a git worktree) to its own org so a switch elsewhere never disturbs it — the key still comes from the global store:
lotics org use acme --local # writes ./.lotics/config.json (a pointer, no key)
lotics workspace select wks_... # records the workspace in that pin
Auth management
lotics auth login <email> # sign in an existing account — open the link, press Confirm
lotics auth web # send magic link email for web app access
lotics auth whoami # show active account, org, workspace, and source
lotics auth logout [<name|id>] # remove a profile (default: active), or unpin a directory
lotics auth logout --all # remove every saved credential
Keys are stored once per org as profiles in ~/.lotics/config.json. A directory’s .lotics/config.json is a keyless pin — a pointer to an org whose key comes from the global store. For ephemeral or CI use, set LOTICS_API_KEY instead of saving anything.
Resolution precedence (highest first): --api-key flag > LOTICS_API_KEY env > LOTICS_ORG env > local .lotics/config.json > global active profile. LOTICS_WORKSPACE (or --workspace) overrides the workspace.
Workflow
1. lotics auth signup — create account or authenticate
2. lotics workspace — list workspaces (select one if multiple)
3. lotics tools — list available tools by category
4. lotics tools <name> — show tool description + full input schema
5. lotics run <tool> '<json>' — execute a tool with JSON arguments
Always inspect the schema (step 4) before calling a tool. Query tools return IDs (table IDs, record IDs, file IDs) used as arguments to other tools.
Commands
lotics tools List all available tools
lotics tools <name> Show tool description and input schema
lotics run <tool> '<json>' Execute a tool
lotics setup <model.json> First run, one command: account + workspace + sign-in link
lotics model apply <model.json> Apply a model here: checked first, then additive, never deletes a table
lotics model check <model.json> What applying it would change, writing nothing
lotics model pull [-o <model.json>] This workspace's model — its tables and apps
lotics docs List this CLI's reference docs
lotics docs model The model file reference — offline, before an account exists
lotics docs <area> Print one, capped at a page (e.g. lotics docs model)
lotics docs <area>/<section> One section, or one row of a table doc
lotics docs [<area>] --grep <text> Search the references on the server
lotics org List saved orgs (marks active)
lotics org use <name|id> [--local] Switch active org (--local pins this directory)
lotics workspace List workspaces in the active org (marks current)
lotics workspace select <id> Switch active workspace
lotics workspace create <name> Create a new workspace (admin only)
lotics workspace settings Change its name, currency or timezone (admin only)
lotics app <subcommand> Create a custom-code app, and build and deploy it
lotics knowledge <subcommand> Create, read, label and update reference documents
lotics file upload <file|dir...> Upload files (alias: lotics upload)
lotics file download <file_id> Download a file by ID (alias: lotics download)
lotics file list What is in the file store, newest first — one page at a time
lotics file delete <file_id> Archive a file; refused while anything still references it
lotics report '<json>' Tell us what got in your way
lotics --help prints this list with every subcommand and flag, rendered by the binary you have
installed — so it is never behind the version you are running.
Reference docs, matched to your version
This page describes what the CLI is for. The exact contract ships inside the CLI,
and lotics docs prints it:
lotics docs # the references this CLI carries
lotics docs model # one reference
lotics docs model/apps # one section, or one row of a reference that is a table
Every answer is one page at most. A reference longer than that prints its opening and the addresses that reach into it, so the next command is smaller than the last.
A page newer than your CLI — one an error from Lotics names — is read from Lotics, and so is a search:
lotics docs --grep currency # every reference that says it
lotics docs model --grep currency # within one reference
An error names a page in the form your CLI opens: lotics docs <path>, or, on an older CLI,
lotics run docs '{"path":"<path>"}'.
This page has one live copy and no version, which is right for describing a product and wrong for describing a contract: your project pins a version, and a hosted copy would answer for a different one.
A custom-code app’s SDK reference ships inside @lotics/app-sdk, at
node_modules/@lotics/app-sdk/AGENTS.md in the app.
Building apps
An app is one of two kinds. A JSON app is stated in the model file’s apps and built on Lotics
by lotics model apply. A custom-code app is a Vite + React + TypeScript project built on your
machine: lotics app create <name> --custom scaffolds one against @lotics/app-sdk and
lotics app deploy builds and ships it. lotics app pull brings the project up to date with the live
version after someone else deployed, and lotics app pull <app_id> <folder> fetches it into a new
folder on another machine. A project with edits of its own is never overwritten: the pull lists the
files you changed.
What an app reads and does is declared on the app itself, live: lotics run set_app_queries,
set_app_workflow and set_app_agent each make a new version of the app, and so does every apply
and deploy. lotics run query_app_versions lists them and lotics run rollback_app returns the app
to an earlier one — the tables and the records the app wrote meanwhile stay as they are.
Start with lotics docs building_an_app, which is the sequence and the reasoning behind its order.
A workspace from a model
The tables are described in a file and created from it. lotics docs model prints the model file
reference — offline, before an account exists.
lotics setup model.json --email you@company.com then checks the file, creates the account, the
organization, the workspace and the API key, and applies the model into it.
Afterwards lotics model apply model.json re-runs it into the current workspace. It checks the
whole file first and lists every finding at once; then it creates what is new, adopts a table that
already carries that label, and never renames anything or deletes a table, a field, an option or an
app — so a second run does nothing, and a model with more tables in it adds them. Once the file has
been pulled or applied in this workspace, the apply sends only what the file changed since then, so
what changed in the workspace meanwhile and the file does not touch stays. What the file takes out
goes where an apply writes it as the file states it — an app’s acts and columns, a write rule, a
field’s default — and is refused where the apply would leave it standing: a table, a field, an option
or an app, naming the tool that deletes it, or a setting such as a table’s row rule. An act the
file moves among an app’s acts is sent as that move; a table’s fields and options keep the order the
workspace holds, and the apply says so. An edit inside one app — its columns, its sections, its acts —
leaves the tables as they are and rebuilds that app, and any other app that reads what changed.
Before it writes anything, the apply also refuses an app that leaves out a treatment its tables call for (lotics docs design), until the app adopts the
patch the refusal prints or states why not under the declines key it names. lotics model check model.json says what the
apply would change, prints those patches, and writes nothing — a key that only reads can run it (schema:read, and data:read when the file states an app or is sent as its changes). lotics model pull -o model.json writes
the model this workspace holds now, so the file can be brought back to what is in use before anyone
builds on it.
Renaming is a separate act: lotics run update_table renames a table or a field, and the next
model pull carries the new label.
Presets
A preset is a complete example model.json for one industry. They are listed at
https://lotics.ai/presets/index.json, each at
https://lotics.ai/presets/<slug>.json; your agent reads the closest one as a worked example and
writes a model of your own, in your words. Nothing is installed, and what you end up with is a model
you own from the first minute.
Telling us what got in your way
lotics report is the channel for the things nothing else records: a capability that does not
exist, a command that succeeded and did the wrong thing, an error whose message did not say how to
fix it. It takes a small frame rather than a paragraph — what you were trying to do, and what
happened instead — because what you were trying to do is the one thing no log can reconstruct.
Run it with no arguments to see the frame.
Tool categories
| Category | What it covers |
|---|---|
| Tables | Query, create, update, delete, clone tables. Add fields with types (text, number, date, select, linked records, formulas). Add validations |
| Records | Query with filters, create, update, delete records. Aggregate (count, sum, avg). Lock/unlock. Restore deleted |
| Views | Saved perspectives: filters, sorts, field visibility, color rules |
| Files | Delete a file nothing references any more — upload, download and listing are the lotics file commands |
| Templates | List, inspect, and delete templates of any type (Excel, Word, PDF) |
| Excel Templates | Create Excel templates with named placeholders in the cells, inject data, generate filled .xlsx files |
| Word Templates | Create Word templates with variables, loops ({%for%}), conditionals. Generate filled .docx |
| PDF Templates | Create HTML/CSS or fillable PDF templates. Generate filled PDFs. Analyze PDF structure |
| Automations | Create event-driven workflows: triggers (record created, field changed, schedule, webhook) + steps (update records, send email, AI actions) |
| Apps | Create dedicated data interfaces with configured views and action buttons |
| Knowledge | Create, update, search, and read reference documents for workspace context |
| Admin | Query members, groups, audit logs |
Flags
| Flag | Description |
|---|---|
--json |
Full JSON output (default is human-readable text) |
--timeout <ms> |
Timeout for tool execution (default: 60000) |
-o <path> |
On download, the directory to save into. On model pull and knowledge get, the file to write |
--as <name> |
Override upload filename |
--api-key <key> |
API key (overrides saved config and LOTICS_API_KEY env) |
--workspace <id> |
Workspace override for one command (alias: -w) |
--version |
Show CLI version |
Output
Status messages (auth, download confirmations, errors) go to stderr. Tool output goes to stdout. This enables clean piping:
lotics run query_records '{"table_id":"tbl_..."}' --json | jq '.records[].name'
Errors print to stderr and exit with code 1.
Files
Some tools generate files and return { file_id, url, filename }. Download with:
lotics run generate_document '{"..."}' --json
lotics download <file_id> ./bao_cao.xlsx # the file to write
lotics download <file_id> -o ./output/ # the directory to save into, under the stored name
The path argument is the file, -o is the directory — the same split cp and curl -o use.
Name one or the other, not both. The written path goes to stdout, so a download pipes into
whatever opens it next.
Upload files before referencing them in tool args:
lotics upload ./data.csv ./report.pdf ./documents/
lotics run create_records '{"table_id":"tbl_...","records":[{"fld_file":["fil_..."]}]}'
Stdin and files
Pipe JSON arguments via stdin instead of inline, or pass a file with a leading @. A trailing -
is what asks for stdin — without it the tool runs with no arguments and answers at once, which is
what a tool taking none should do:
echo '{"table_id":"tbl_..."}' | lotics run query_records -
lotics run query_records @args.json
In PowerShell, use the file form. Quotes inside an inline argument are consumed by the shell
before lotics sees them, and the CLI then reports the JSON it received with its quotes gone.
CI / non-interactive
export LOTICS_API_KEY=ltk_...
lotics run query_tables '{}'
# Or target a saved org/workspace without changing the active one:
LOTICS_ORG=acme LOTICS_WORKSPACE=wks_... lotics run query_tables '{}'
SDK (Node.js)
import { LoticsClient } from "@lotics/cli";
const client = new LoticsClient({ apiKey: "ltk_..." });
// Discover tools
const { categories } = await client.listTools();
const info = await client.getTool("query_records");
// Execute tools
const { result } = await client.execute("query_tables", {});
// File operations
const upload = await client.uploadFiles(["./report.pdf", "./data.csv"]);
await client.downloadFile(url, "./output.xlsx");
await client.downloadFileById(fileId, "./downloads/");
What a session looks like
Everything past authentication is the same three moves: inspect a schema, run a tool, use the IDs it hands back.
# 1. Authenticate once — the key is saved per org
lotics auth signup agent@company.com --name "Ops Agent"
# 2. Inspect before calling. This prints the schema for the version you have
# installed, generated from the code — never guess argument names from a page
# like this one.
lotics tools create_table
# 3. Create a table. Field properties sit FLAT on the field object.
lotics run create_table '{
"name": "Invoices",
"add_fields": [
{"name": "Customer", "type": "text"},
{"name": "Amount", "type": "number", "notation": {"style": "currency", "currency": "USD"}},
{"name": "Status", "type": "select", "options": [{"name": "Draft"}, {"name": "Sent"}]},
{"name": "Due Date", "type": "date"}
]
}'
# 4. Read back the generated keys — fld_… per field, opt_… per select option
lotics run get_table '{"table_id": "tbl_..."}'
# 5. Write, addressing fields by those keys. A select value is an array of option keys.
lotics run create_records '{
"table_id": "tbl_...",
"records": [{"fld_...": "Acme Corp", "fld_...": ["opt_..."]}]
}'
Documents, automations, apps and files follow the same loop with different tools. The argument
schemas are deliberately not reproduced on this page — lotics tools <name> prints the exact
one for the version you installed, and a copy here would describe some other version to whoever
read it next.