@lotics/cli

中文文档
0.318.28发布于 2026/11/02MITES Module零依赖

Lotics SDK and CLI for AI agents

原始使用文档
文档目录16 节
  1. Capability guides
  2. Start in two commands
  3. Describe your workspace
  4. Install
  5. Update
  6. Authentication
  7. Organizations
  8. Working in parallel (worktrees)
  9. Resolution precedence
  10. Diagnostics
  11. Reporting a problem
  12. Workspaces
  13. CLI
  14. Knowledge docs
  15. Custom-code apps
  16. SDK

@lotics/cli

CLI and SDK for AI agents to interact with Lotics.

Lotics is an AI-powered operations platform. Through this CLI you can:

  • Manage tables, records, and views (structured data with typed fields)
  • Generate documents from templates (Excel, Word, PDF, Email)
  • Build and run automations — schedules, webhooks, app workflows; inspect execution and version history
  • Administer the workspace — invite members, manage groups, share resources, transfer ownership, browse connected accounts (OAuth attach is web-only)
  • Create and manage apps, knowledge docs, and files

Capability guides

lotics docs lists this CLI's references, carried inside it — the model reference and every doc below — so a doc always describes the binary answering. lotics docs <area> prints one (lotics docs reference). Every answer is capped at a page, so a long doc hands back its section list and lotics docs <area>/<section>. A page the CLI's copy lacks — one the server added since, which an error can cite — is read from the server, and lotics docs [<area>] --grep <text> searches the references the server serves; both use this machine's credential. A custom-code app's SDK reference ships inside @lotics/app-sdk, in the app's own node_modules.

Driving this CLI from an agent? Start at AGENTS.md (node_modules/@lotics/cli/AGENTS.md) — which surface answers which question, the conventions that hold across every command, and the traps. Per-command contracts, flags, exit codes and gotchas are in docs/cli_reference.md; lotics --help is the always-current verb list.

The platform's primary surfaces have dedicated usage guides that ship inside this package (reachable at node_modules/@lotics/cli/docs/*.md once installed):

  • docs/getting_started.md — what a workspace holds and the one page to open for each job.
  • docs/first_build.md — a whole workspace built call by call: which apps, a treatment per kind of row, what the check refuses.
  • docs/building_an_app.md — building an app end to end: an app stated as a tree and written with set_app, or a custom-code app on @lotics/app-sdk. Read it once before starting an app.
  • docs/document_templates.md — generate finished documents (PDF, Excel, Word, email) by filling reusable templates: the five template types, the create → generate → chain lifecycle, and the marker capabilities.
  • docs/migration.md — what to do when a release changes what the CLI once wrote to disk; read once, when something on disk no longer matches what the CLI does.
  • docs/knowledge_docs.md — the AI's rulebook layer: authoring the procedures and policies an agent can't guess, who can read a doc, and the search-then-read retrieval agents use to pull only the lines they need.
  • docs/app_architecture.md — one factory's split into apps, and docs/working_in_a_workspace.md — the means for each job once they exist.

Start in two commands

Install the CLI and create an account; the account's workspace is then built with the tools:

curl -fsSL https://lotics.ai/install.sh | bash
lotics auth signup [email protected]

The installer downloads one compiled executable — no Node.js, no npm: every app is deployed on Lotics. Node 18+ comes in only for a custom-code app, which is built on this machine to deploy.

Describe your workspace

Tables and apps are written by two tools, the same on the CLI and over MCP. set_tables takes { "tables": [...] } — always a list, all or nothing — each table a document keyed by alias: its fields (keyed by alias), options, links, views and how a row is recognised. A link names its table by id, or by the ref of another table of the same call, and states multi; a two-way link states pair on both tables. A table is edited by an RFC 7396 merge patch of its document, where null deletes. set_app takes one app per call: { "body": <the App tree> } to create, the tree stating the app's name; { "app_id": …, "nodes": { "<address>": <patch> } } to change one node (the App's own props change through body). Both create when given no id and edit when given one, and dry_run checks without writing. Every answer states the permissions the write granted and removed.

A new workspace: one set_tables call with the tables (at most 50, 200 first rows each, a call), then every set_app call, then fixes.

lotics docs reference                          # the keys, with a worked example
lotics run set_tables @tables.json          # every table of the workspace, in one call
lotics app apply orders.app.json --check   # set_app as a dry run: everything wrong, nothing written
lotics app apply orders.app.json           # set_app: creates the app, or edits the one the file records

The answer notes the treatments an app leaves unstated that its rows call for; nothing is written into the tree for you. Change the file and apply it again; applying an earlier tree again is the undo — table changes and data writes stay.

The other direction: lotics app pull <app_id> writes an app's tree as a file.

Install

curl -fsSL https://lotics.ai/install.sh | bash    # macOS, Linux, WSL — no Node.js needed
npm install -g @lotics/cli                        # or, if you already have Node 18+
irm https://lotics.ai/install.ps1 | iex           # Windows PowerShell — no Node.js needed

Update

lotics upgrade updates this CLI in place, running whichever installer this copy came from. By hand: re-run whichever installer you used; npm install -g @lotics/cli@latest updates an npm install.

The CLI checks for updates once per day and prints a note on stderr, naming the right installer, when a new version is available.

Authentication

Two kinds of credential, and which you hold decides what logout does. auth signup / auth login give this machine a sign-in — it acts as you, carries whatever role you have, and is yours to see and revoke at Settings → Security → Keys and terminals; it lapses after 90 days of disuse, and each use pushes that out. auth api-key saves an API key an admin issued. A key an admin creates in Settings has its own name and its own access, reaching either every app and table or only the ones chosen on the key; a key created FOR a person carries that person's access and stops working when that person is removed. Either kind often lives on a server and on other people's machines too, and only an admin revokes it. lotics auth whoami prints which kind this machine holds — from the saved profile, or from the server when the profile does not say.

When a credential stops working the refusal says which of the three ways it is dead — "… was revoked." / "… expired." / "… belongs to a member who is no longer active in this organization." — and its hint names the remedy: lotics auth login <email> for a terminal sign-in, ask an admin for a new key for an API key. A credential whose record does not say which of the two it is gets both. A key the server does not recognize at all gets one generic answer, deliberately: an unrecognized key learns nothing from being refused.

lotics auth signup — Creates a new Lotics account, organization, workspace, and API key in one step. Sends a magic link email so you can access the web app.

lotics auth signup                                   # interactive prompts
lotics auth signup [email protected] --name "Agent"            # non-interactive

lotics auth login — Signs in an account that already exists, on a new machine or to add another organization to one that holds a key (the one you pick becomes active). It does not wait for you. It prints the page to open (also mailed to you) and the code that page must show, then exits. Sign in there if asked, check the code, press Confirm — and run whatever you wanted to run: the next command that needs a credential collects the key before doing its own work.

lotics auth login [email protected]            # prints the page + code, exits — nothing to keep open
# …press Confirm in the browser…
lotics auth whoami                   # picks up the key, then answers

lotics auth login [email protected] --wait     # one command instead: holds the terminal until Confirm
lotics auth login [email protected] --local    # pins this directory to that org (implies --wait)

A command run before you press Confirm names the page and the code again and exits 1; the request is good for 15 minutes, after which the next command says to ask again. Re-running auth login is always safe — it replaces the request, so only the newest code is the live one.

lotics auth web — Send a magic link email to access the web app (requires prior signup). If the account's email address was never confirmed and it holds a password, signing in with the link removes that password; the command says so and names where Forgot password sets a new one.

lotics auth web

lotics auth api-key — Saves an API key (e.g. one created in the Lotics web app). The key belongs to one org, so this registers that org as a profile — run it once per org. Registering a second key adds a profile; it does not overwrite the first.

lotics auth api-key                  # interactive prompt
lotics auth api-key ltk_...          # registers the key's org as a profile (now active)

Run lotics auth logout [<name|id>] to remove a profile (default: the active org), or lotics auth logout --all to wipe the store. Inside a pinned directory the bare form removes the pin, not a profile — name the org to remove its credential. A profile saved by auth login / auth signup is a sign-in, and logging out revokes it server-side too. One saved by auth api-key is an admin-issued key that other machines may also hold, so it is only removed from this machine and stays active until an admin revokes it under Settings → API keys. A profile saved before the kind was recorded states nothing, so the server is asked and the credential is revoked only if the answer is a sign-in.

Organizations

Each saved API key belongs to one org. Register a key per org once, then switch freely — no re-pasting:

lotics org                          # list saved orgs (marks the active one)
lotics org use acme                 # switch active org by name (or org id)
lotics org use "Acme Corp"          # names are case-insensitive

The org id is the identity; the name is the label the key was saved under, and it is yours — renaming the org in the app never moves it, so the scripts scoping by it keep running. lotics auth whoami learns the new name and records it beside the label; both resolve, and lotics org prints label (server: name) while they differ. A name matching two saved orgs is refused rather than guessed; use the id.

Working in parallel (worktrees)

Pin a directory to its own org/workspace so a global org use elsewhere never disturbs it. The pin is a pointer — the key still comes from the global store, so there's nothing to paste:

cd my-worktree
lotics org use acme --local         # writes ./.lotics/config.json { active_org }
lotics workspace select wks_...     # records the workspace in the local pin

Each worktree resolves independently; switching the global default in another shell leaves pinned worktrees untouched. .lotics/ should be gitignored.

Every command that resolves a workspace names its target before it acts — lotics → Starters / Equipment & Projects on stderr, so stdout stays clean for piping. Both halves are NAMES, since the line exists to be read before a destructive write; the workspace's name is cached beside its id the first time any command lists it, and until then the line prints the id and says the name is not known yet. When nothing in the directory or environment chose the org and it came from the machine-wide default, the line says so and prints the --local command to pin — that default is the one another shell can move between two of your commands. lotics auth whoami reports the same resolution on demand, including which source won.

Resolution precedence

--api-key flag  >  LOTICS_API_KEY env  >  LOTICS_ORG env (name|id)
  >  local .lotics/config.json  >  app manifest workspace → its saved profile
  >  global active profile

LOTICS_WORKSPACE (or --workspace <id> / -w) overrides the workspace at any level. For ephemeral or CI use, set LOTICS_API_KEY instead of saving anything.

LOTICS_ORG is resolved once, before any command runs. A value matching no saved credential refuses every verb with one sentence — a read, a write, and a check that needs no credential alike — and the refusal lists the orgs this machine does hold, so it is answerable without another command. It refuses even when a key arrives another way: a variable that scopes the command must not go unread while LOTICS_API_KEY sends the write somewhere else. When the variable resolves AND a key is supplied, the key decides the org and the command says so. An org keeps the name it was saved under: a server-side rename never moves it, the new name resolves as well, and lotics org prints both when they differ.

In a custom-code app's directory, lotics app deploy derives the credential from the directory when nothing explicit chose one: the manifest names the app's workspace, and when exactly one saved profile owns that workspace, that profile is used — the machine-wide default is never consulted. An explicit flag, env var, or directory pin still wins, and an org whose profile remembers a different workspace simply falls through to the announced default.

Diagnostics

Every request identifies the CLI (user-agent: lotics-cli/<version> node/<v> <platform>) and names the command that made it (x-lotics-cli-command: app.apply), so a failure in the server's logs can be traced to the verb and version that produced it. Neither header carries arguments: the command chain stops before any id, path, @file, or JSON payload. It also names what it can do that an older CLI cannot (x-lotics-cli-capabilities: docs-fallback), so the server answers in a form it reads: an error names a page as lotics docs <path> to a CLI that declares docs-fallback, and as lotics run docs '{"path":"<path>"}' to any other.

LOTICS_TELEMETRY=1 additionally records the session. Off by default. Set it in your shell profile rather than per command — each invocation is its own process. When set:

  • Requests carry a session id shared by every command in the sitting — under an agent harness it adopts the harness's own session id, otherwise it rolls over after 30 minutes idle (~/.lotics/session.json).
  • Each invocation appends one record to ~/.lotics/telemetry-<host>.ndjson — the command, its exit code, how long it took, and, on a failure, the message that was printed. One spool per Lotics the CLI talks to, so a record made against one instance is only ever sent to that instance. Batches are sent on a later run against the same host; a failed send is retried, never dropped silently.

Arguments contribute a hash and a shape (records[].data.name:string) and nothing else — no values, no file contents, no record data. The hash is the point: two failures in a row with the same hash mean the error message did not tell you enough to fix the call.

Unset, nothing is stored, nothing is sent, and no spool file is created.

Reporting a problem

lotics report '{"goal":"rename a view","actual":"no command does it","wanted":"lotics run set_tables"}'
lotics report @report.json       # a long one, from a file
cat report.json | lotics report -   # or from stdin — `-` is required, see below
lotics report                    # the frame, and what is worth reporting

This is the channel for what the records above cannot show. Everything they capture hangs off a command that failed, which leaves out the two things worth the most: a capability that does not exist (no command ran, so nothing was recorded) and a command that exited 0 having done the wrong thing. Also worth sending: an error whose message did not tell you how to fix it, and anything that made authoring slower than it should have been.

A report is a frame, not a paragraph. A log can reconstruct what you ran; nothing can reconstruct what you wanted, and the gap between the two is the report.

Field
goalrequiredwhat you were trying to accomplish
actualrequiredwhat happened instead
expectedwhat you expected — the gap between this and actual is the defect
triedwhat you already tried, and what it said
wantedwhat would have unblocked you

There is no severity or category to pick.

Reading from stdin needs an explicit -. With - the bare form always prints the frame and a piped one waits as long as it takes.

If LOTICS_TELEMETRY=1 is set, the commands from your session attach themselves — don't retype them. It runs whether or not telemetry is on (invoking it is the consent that passive recording needs an opt-in for), posts immediately, and tells you if it did not land.

Do not paste records, file contents, or credentials.

Workspaces

Workspaces live inside the active org. If the org has more than one, select before running tools:

lotics workspace                    # list workspaces in the active org (marks current)
lotics workspace select wks_...     # set the workspace for the active scope (pin or profile)
lotics workspace create "Sales" --timezone America/New_York --currency USD
                                    # create a new workspace (admin only); without the flags it
                                    # takes the org's oldest workspace's zone and currency
lotics workspace settings --currency USD --timezone America/New_York
                                    # change the current workspace's name/currency/zone
lotics workspace delete wks_... --yes  # delete a workspace (admin only; soft delete, recoverable)

Single-workspace organizations auto-select on first use. The selection is remembered per org, so switching back lands where you left off.

CLI

# Discover tools
lotics tools                    # list tools by category with descriptions
lotics tools query_records      # show full description + input schema

# Execute
lotics run get_workspace '{"kind":"tables"}'
lotics run query_records '{"table_id":"tbl_...","field_keys":["name"]}'

# Large args (a knowledge-doc `content`, a bulk update) exceed the OS arg limit —
# read them from a file or stdin instead of an inline arg:
lotics run set_knowledge @args.json
cat args.json | lotics run set_knowledge -          # the trailing - reads stdin
echo '{"table_id":"tbl_..."}' | lotics run query_records -

# Upload files (multiple files and directories supported)
lotics upload ./report.pdf ./data.csv ./documents/

# Generate a file, then download it
lotics run generate_document '{"..."}'
lotics download <file_id> -o ./reports/

# What is in the store, newest first — one page, with the command for the next one
lotics file list --limit 50

# CI / non-interactive (key inline)
LOTICS_API_KEY=ltk_... lotics run get_workspace '{}'

# One-off against a saved org/workspace, no switching
LOTICS_ORG=acme LOTICS_WORKSPACE=wks_... lotics run get_workspace '{}'

Knowledge docs

A file-native surface over the workspace's knowledge docs — the AI's rulebook layer. The body is a Markdown file: create/update read it from your filesystem, get writes it back. See docs/knowledge_docs.md for the model.

lotics knowledge list                                         # catalog: id, name, description (--json)
lotics knowledge create --name "Shipping tariffs" \
  --description "HS-coded rates; searchable by lane and code" \
  --from ./tariffs.md                                         # or --content '<inline>'; prints the new id
lotics knowledge get kdc_... -o ./tariffs.md                  # body → file (omit -o for stdout; --json = full doc)
lotics knowledge update kdc_... --from ./tariffs.md           # send only what changed (--name / --description too)
lotics knowledge rm kdc_... [kdc_...]                         # delete; sharing and history are kept
lotics knowledge list --deleted                               # deleted docs you can restore
lotics knowledge restore kdc_... [kdc_...]                    # bring them back, all or none

create / update are the tool set_knowledge (no knowledge_doc_id makes a doc, one patches it) and send the body inline; the server mints and version-chains the content file (and update diffs + resolves concurrency internally — no token to pass). get is the one content-read path, hydrating the body server-side.

Custom-code apps

# Your own project depending on @lotics/app-sdk (React 19); `npm run build` writes a static dist/ with index.html
lotics app create "Sales Desk" --custom .  # registers the app, links this directory by package.json#lotics
lotics app deploy -m "Add quote drawer"    # build + upload a new version of the live app
lotics app pull                            # in the project: bring it up to the live version (refused while it has edits)

# What the app reads and writes is bound on the app, and each change mints a version:
lotics run set_app_queries '{"app_id":"app_...","queries":{"openInvoices":{...}}}'
lotics run set_workflow '{"source":"on({ type: \"app\", app_id: \"app_...\", alias: \"issueInvoice\" });\n..."}'

# Running an app's alias is a TOOL call, like every other tool. Exits non-zero
# when the RUN failed, not only when the call did.
lotics run run_app_query '{"app_id":"app_abc","alias":"openInvoices","params":{}}'
lotics run run_app_workflow '{"app_id":"app_abc","alias":"issueInvoice","inputs":{...}}'
lotics run run_app_workflow '{...}' --print-created   # the records it created + a cleanup plan

The app's SDK reference is node_modules/@lotics/app-sdk/AGENTS.md once the project installs it. lotics tools <name> prints any tool's input.

SDK

import { LoticsClient } from "@lotics/cli";

const client = new LoticsClient({ apiKey: "ltk_..." });

const { result } = await client.execute("get_workspace", {});
const upload = await client.uploadFiles(["./report.pdf", "./data.csv"]);
await client.downloadFile(url, "./output.xlsx");
const { tools, categories } = await client.listTools();
const info = await client.getTool("query_records");

版本与发布记录

@lotics/cli 共发布 451 个版本,首次发布于 2026/03/27;过去 12 个月发布了 451 个版本。

版本发布日期距今
0.318.28latest2026/11/021 天前
0.318.272026/11/021 天前
0.318.262026/11/011 天前
0.318.252026/10/313 天前
0.318.242026/10/313 天前
0.318.232026/10/304 天前

关于 @lotics/cli 的常见问题

@lotics/cli 是什么?

用于AI代理的Lotics SDK和CLI

如何安装 @lotics/cli?

在项目目录运行 npm install @lotics/cli,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 lotics,可以用 npx lotics 直接运行。

@lotics/cli 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/lotics__cli 是否存在。

@lotics/cli 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@lotics/cli 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@lotics/cli 可以商用吗?

@lotics/cli 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@lotics/cli 还在维护吗?

最新版本 0.318.28 发布于 2026/11/02(1 天前);至今共发布 451 个版本,其中过去 12 个月发布了 451 个;首次发布于 2026/03/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。