@lotics/cli 0.315.18 → 0.316.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,228 +1,109 @@
1
1
  # Knowledge Docs
2
2
 
3
- Knowledge docs are the AI's **rulebook layer** — the workspace-specific facts and rules an
4
- agent can't know on its own: your price list, your product codes, your SOPs, your shipping
5
- tariffs, your glossary of in-house terms. You write them once; the agent **searches and reads
6
- them on demand** while it works, pulling in only the lines it needs.
3
+ Knowledge docs are the workspace's **rulebook layer** — the facts and rules an agent can't know on its own: a
4
+ procedure, a policy, a glossary of in-house terms, a tariff book. You write them once; the agent **searches and reads
5
+ them on demand** while it works, pulling in only the lines it needs. They are not injected wholesale, so a 10,000-line
6
+ tariff costs nothing until a question touches it.
7
7
 
8
- They are deliberately **not** injected into the agent wholesale. Instead the agent retrieves
9
- from them line by line — grep, then read — so a 10,000-line tariff book costs nothing until a
10
- question actually touches it, and a 10MB one is no different.
11
-
12
- This is a **capability + usage** guide. For the exact input schema of any tool named here, run
13
- `lotics tools <tool_name>`.
8
+ A menu with its prices, the customer list and the open orders are not knowledge: they are rows of tables, so apps, queries and documents
9
+ can use them.
14
10
 
15
11
  ## Rulebook, not methodology
16
12
 
17
- Put in a knowledge doc the things the model **cannot guess**: your specific numbers, codes,
18
- names, exceptions, and policies. Do **not** put in it general skills the model already has
19
- ("how to write a polite email", "how to summarize"). If the agent would get it right without
20
- the doc, the doc is noise.
21
-
22
- ## Creating a doc — `lotics knowledge create`
13
+ Put in a knowledge doc the things the model **cannot guess**: your specific numbers, codes, names, exceptions and
14
+ policies. Do **not** put in it general skills the model already has ("how to write a polite email"). If the agent would
15
+ get it right without the doc, the doc is noise.
23
16
 
24
- ```bash
25
- lotics knowledge create --name "Shipping tariffs" \
26
- --description "HS-coded rates; searchable by lane and code" \
27
- --tags "HS,nhập khẩu" \ # file it as you make it — see Classifying, below
28
- --from ./tariffs.md # the body is a Markdown file; or --content '<inline>'
29
- ```
17
+ ## Writing a doc — `set_knowledge`
30
18
 
31
- This reads the body from your filesystem and creates the doc through `create_knowledge`
32
- (prints the new id). A raw `lotics run create_knowledge @doc.json` works too — read a large
33
- `content` from a file or stdin. `create_knowledge` takes five fields, three of them required:
19
+ `set_knowledge` creates a doc when it is given no `knowledge_doc_id` and changes the named one when it is given one:
34
20
 
35
- - `name` — what it is. Just the name: **grouping belongs in `tags`, not in a prefix baked into
36
- every title.**
37
- - `description` — what the doc is **and what to grep it for**: its vocabulary and the synonyms
38
- an ambiguous query would use. Surfaced in the tree before any body is read, and truncated at
39
- 200 characters. See *Write for grep* below.
21
+ - `name` — what it is. Just the name: **grouping belongs in `tags`, not in a prefix baked into every title.**
22
+ - `description` — what the doc is **and what to grep it for**: its vocabulary and the synonyms an ambiguous query would
23
+ use. Surfaced in the listing before any body is read, and truncated at 200 characters.
40
24
  - `content` — Markdown.
41
- - `tags` *(optional)* — the labels someone would filter by, e.g. `["Hồ sơ NOXH", "Khoản 13"]`.
42
- Give **every** one that is true of the doc, not just the main one — a corpus is narrowed by
43
- intersecting tags, so a doc carrying one label can only ever be found down one path. On
44
- `update_knowledge` the array **replaces** what is stored, so resend the labels it should keep.
45
- - `files` *(optional)* — file ids of the source `.docx`/`.pdf`/`.xlsx` the doc was built from,
46
- stored alongside it so a reader can open the original. The body stays the searchable text.
47
-
48
- A new doc is created **owned by you, active in your own agent context, and private** — no one
49
- else can see it yet. Changing a doc's default-active state is done through the web app / REST
50
- surface, not this tool.
51
-
52
- ## Access
25
+ - `tags` *(optional)* — the labels someone would filter by, e.g. `["Hồ sơ NOXH", "Khoản 13"]`. Give **every** one that is
26
+ true of the doc: a corpus is narrowed by intersecting tags, so a doc carrying one label is found down one path only.
27
+ On a change the array **replaces** what is stored, so resend the labels it should keep.
28
+ - `files` *(optional)* — file ids of the source `.docx`/`.pdf`/`.xlsx`, stored alongside so a reader can open the original.
53
29
 
54
- A knowledge doc reaches an agent only when the member can `use` the doc. New docs are private
55
- to the owner; share them with other members or groups using the IAM tool `share_resource` on the CLI or in chat
56
- (category **Admin**; `unshare_resource` to revoke). An organization admin who is a person is no
57
- exception: they read a doc only once it is shared with them, or once they share it with
58
- themselves, which the audit log records. An API key acting as itself keeps the access set on the
59
- key.
30
+ A change sends only the fields it changes. `edits` (anchored replace, insert, append) makes a surgical change to the
31
+ body. Refine structure as you learn what users ask: add the synonym that failed to match, split a line that was too
32
+ coarse, restate a term the heading was carrying.
60
33
 
61
- ## How an agent uses a doc — ls, grep, cat
34
+ A new doc is **owned by you and private**. `set_access` shares it: `resources[]` with `resource_type` `knowledge_doc`, and `principals[]` (a
35
+ member, a member group, or `organization` for everyone), each with a `role` of `user` or `manager`; a principal without a `role` has
36
+ its access taken away. A doc reaches an agent only when the member can `use` it, an organization admin included.
62
37
 
63
- Docs are not injected wholesale. The agent works the corpus like a filesystem, and all three
64
- verbs respect access, so only docs the caller may use ever surface.
38
+ ## How an agent uses a doc
65
39
 
66
- 1. **`list_knowledge`** — `ls`. The corpus as a flat list: id, name, tags, and a truncated
67
- description; `tag` narrows it. No bodies.
68
- 2. **`grep_knowledge`** — `grep -rn`. Match across every readable doc (or one doc, or one
69
- tag), returning **doc, line number, and the matching line**. It runs inside Postgres,
70
- so only matching lines cross the wire.
71
- 3. **`read_knowledge`** — `cat` / `sed -n 'X,Yp'`. Read a doc whole or by line range, to see
72
- the context around a hit.
40
+ Retrieval works like a filesystem, and respects access: only docs the caller may use ever surface.
73
41
 
74
- Matching is **not ranked** — there is no index and no tokenizer, which is why a corpus in any
75
- script works and why nothing goes stale. The consequence is that the *agent* does the
76
- narrowing: a distinctive phrase is sharply selective, a whole question matches everything.
77
- `grep_knowledge` always reports `total_matches`, so "too broad" is visible and cheap to fix.
42
+ 1. **List and search** — `get_workspace` kind `knowledge` lists the corpus (id, name, tags, a truncated
43
+ description); a search term matches a doc's name, description and tags. `get_workspace` with `search` finds where something is said: it
44
+ matches across every readable doc and returns the **doc, line number and matching line**;
45
+ `knowledge_doc_id` or `tag` confines the lines to one doc or to the docs carrying that tag.
46
+ 2. **Read** — `read_knowledge`, a doc whole or by line range, to see the context around a hit.
78
47
 
79
- ### Literal by default, expression on request
48
+ Matching is **not ranked**: the *agent* does the narrowing. A distinctive phrase is sharply selective, a whole question
49
+ matches everything. A search always reports `total_matches`, so "too broad" is visible and cheap to fix.
80
50
 
81
- `pattern` is **literal text** — every character matches itself. Set `regex: true` to read it as
82
- a POSIX regular expression instead.
51
+ The `search` is **literal text** — every character matches itself. Set `regex: true` to read it as a POSIX regular
52
+ expression (a word boundary is `\y`, not `\b`):
83
53
 
84
54
  ```
85
- grep_knowledge({ pattern: "C/O (Form E)" })
86
- grep_knowledge({ pattern: "\\yNK\\y", regex: true, case_sensitive: true })
55
+ { "search": "C/O (Form E)", "kind": "knowledge" }
56
+ { "search": "\\yNK\\y", "kind": "knowledge", "regex": true, "case_sensitive": true }
87
57
  ```
88
58
 
89
- The default is the safe one rather than the conventional one, and the asymmetry is worth
90
- knowing. As an expression, `C/O (Form E)` searches for `C/O Form E` — not in the document — and
91
- returns a confident zero; `[CŨ]` becomes a one-character class and matches every `C` in the
92
- corpus. Both look like ordinary answers. A literal search has no such failure: the worst case
93
- is an expression sent without the flag, which finds nothing and says so, naming the search that
94
- ran and what to pass instead. That last part is **measured, not guessed** — an empty result tells
95
- you whether reading the pattern as an expression would have matched, so an alternation sent without
96
- the flag (`phrase A|phrase B`) comes back naming `regex: true` rather than advising you to shorten a
97
- pattern that was never too broad.
98
-
99
- ### Matching options
100
-
101
- - **Tone marks match exactly by default.** `diacritic_insensitive: true` folds them, so `ca phe`
102
- matches `cà phê` — reach for it when the pattern was typed without them, not by habit: folding
103
- strips the pattern to ASCII, where a short Vietnamese word matches inside unrelated words
104
- (`mã` finds `manifest`). An empty result tells you when folding would have matched.
105
- - **Case folds by default**, independently of diacritics. `case_sensitive: true` matches case
106
- exactly — useful for an acronym (`NK` vs `nk`) that a folded search would blur.
107
- - **Whitespace is normalized on both sides.** A body converted from PDF, Word or Excel carries
108
- non-breaking spaces, soft hyphens, zero-width marks and padded runs that nobody types into a
109
- query; those fold to ordinary single spaces before matching, so a correct search does not return
110
- a silent zero on text that is present. A literal pattern is normalized the same way; an
111
- expression is left byte-exact, since collapsing its whitespace would rewrite it.
112
- - **What `regex: true` supports**: quantifiers, character classes, alternation, anchors,
113
- backreferences, non-greedy forms, `(?i)`, and both lookahead and lookbehind. A word boundary
114
- is **`\y`**, not `\b` — Postgres spells it differently, and `\b` is rewritten for you rather
115
- than silently matching nothing. Named groups and `\p{…}` are likewise rewritten to their POSIX
116
- equivalents. A `\p{…}` with no POSIX equivalent, and a malformed expression, are both refused
117
- with the reason.
118
-
119
- Where an expression cannot express the question at all — a value that must be computed, a
120
- layout matching cannot address — stage the doc into a code run instead (`code_exec`, in chat or an app agent, with
121
- `knowledge_doc_ids` puts it at `inputs/knowledge/<id>.md` as a real file).
122
-
123
- ### What a result is bounded by
124
-
125
- A result carries at most 40.000 characters. Matched lines are admitted first and context fills
126
- what remains, so an answer is never dropped to make room for a neighbouring line. Anything the
127
- budget cut is REPORTED — `chars_elided_matches` (an answer was dropped) and
128
- `context_omitted_matches` (an answer was kept without the context you asked for) mean different
129
- things and call for different fixes: narrow the pattern, or ask for fewer `context_lines`.
130
- Individual lines longer than 600 characters are clipped and marked, with `read_knowledge` giving
131
- the rest.
132
-
133
- `total_matches` is always the true total, even when fewer are shown.
134
-
135
- ## Write for grep — the rules that decide whether an answer is findable
136
-
137
- Retrieval addresses **lines**. Every rule below follows from that one fact.
138
-
139
- - **One self-contained fact per line.** A grep hit returns *that line*. For dense or tabular
140
- data — a price row, a tariff code, a charge entry — put the whole record on one line.
141
- - **Repeat the searchable terms on every line; headings do not carry down.** A line reading
142
- `Rate: 15%` under a heading `Roasted coffee` will never match a search for `coffee`. Restate
143
- the identifying terms inline, even when it reads redundantly to a human. This is the single
144
- rule most often got wrong.
145
- - **Keep a line under ~600 characters.** Past that the line is truncated in the agent's view
146
- and marked as cut; the agent can still `read_knowledge` for the rest, but it costs a round
147
- trip. Put the identifying terms early and the long tail late.
148
- - **Put synonyms and translations on the line itself.** A bilingual row (`Cà phê, đã rang /
149
- Coffee, roasted`) matches queries in either language for free. The same trick carries
150
- colloquial terms next to official ones.
151
- - **For prose, keep a rule and its exception close.** A hit returns one line, so a rule on line
152
- 40 and its exception on line 90 can be retrieved apart. Use `context_lines` when reading, and
153
- keep related clauses adjacent when writing.
154
-
155
- Markdown headings are ordinary text — useful for a human (a doc's `##` headings outside its
156
- blocks, two or more, are listed on its page as its sections) and for orienting a
157
- `read_knowledge`, but they carry no retrieval weight of their own.
158
-
159
- **The description is the discovery hint.** It is what the agent sees in the tree before it has
160
- read a byte of the body, so it is the only clue for *what term to grep for*. Write it to name
161
- the doc's vocabulary — the words that actually appear inside it. Keep it to a sentence: it is
162
- truncated at 200 characters, and a keyword-stuffed description is cut, not rewarded.
163
-
164
- ## Updating a doc — `lotics knowledge update`
165
-
166
- ```bash
167
- lotics knowledge update kdc_... --from ./tariffs.md # replace the body (--name / --description too)
168
- ```
59
+ As an expression `C/O (Form E)` would search for `C/O Form E`, which is not in the document, and return a confident
60
+ zero; the literal default has no such failure. With `regex` omitted, a literal search that finds nothing while the
61
+ pattern, read as an expression, matches (`a|b`, the commonest) returns those lines under a note saying how they were
62
+ read. `regex: false` keeps the literal zero; a search that finds nothing either
63
+ way says so.
169
64
 
170
- Send only the fields you're changing. `--from` / `--content` replaces the body; `--name` /
171
- `--description` / `--tags` change metadata. `update_knowledge` resolves concurrency **internally** — it
172
- re-reads the current content pointer and version-chains the new body — so there is no version
173
- token to pass from the CLI. (The chat agent may instead send an `edits` array — anchored
174
- replace / insert / append — for a surgical change; see `lotics tools update_knowledge`.) Refine
175
- structure as you learn what users actually ask: add the synonym that failed to match, split a
176
- line that was too coarse, restate a term the heading was carrying.
65
+ - **Tone marks match exactly by default.** `diacritic_insensitive: true` folds them (`ca phe` matches `cà phê`); use it
66
+ when the pattern was typed without them, since folding lets a short word match inside unrelated ones.
67
+ - **Case folds by default.** `case_sensitive: true` matches exactly, for an acronym (`NK` vs `nk`).
68
+ - **Whitespace is normalized on both sides.** Non-breaking spaces, soft hyphens and padded runs from PDF, Word or Excel
69
+ bodies fold to single spaces before matching.
177
70
 
178
- ## Classifying a corpus — tags
71
+ A search shows at most 16,000 characters, shared by what it finds in knowledge, in structure and in records. Matched
72
+ lines are admitted first and context fills what remains; anything cut is reported, with the true number of matching
73
+ lines. Lines longer than 600 characters are clipped and marked; `read_knowledge` gives the rest.
179
74
 
180
- A doc carries a SET of labels, not a folder. Order does not matter, a doc can wear several, and
181
- the vocabulary is whatever the docs themselves use — a tag stops existing the moment nothing
182
- carries it.
75
+ ## Write for grep
183
76
 
184
- ```bash
185
- lotics knowledge update kdc_... --tags "HS,nhập khẩu" # ONE doc: state its complete set
186
- lotics knowledge tag kdc_a kdc_b --add HS --remove draft # MANY docs: a diff applied to each
187
- ```
77
+ Retrieval addresses **lines**. Every rule follows from that one fact.
188
78
 
189
- The split is deliberate. Looking at one doc you know what it should carry, so `--tags` replaces.
190
- Across a set you do not — the docs carry different labels — so `tag` adds and removes against
191
- each doc's own set, and never states one classification for all of them. Removal ignores case;
192
- adding a label a doc already carries changes nothing.
79
+ - **One self-contained fact per line.** A hit returns *that line*. For dense or tabular data — a price row, a tariff
80
+ code — put the whole record on one line.
81
+ - **Repeat the searchable terms on every line; headings do not carry down.** A line reading `Rate: 15%` under a heading
82
+ `Roasted coffee` will never match a search for `coffee`. Restate the identifying terms inline, even when it reads
83
+ redundantly to a human. This is the rule most often got wrong.
84
+ - **Keep a line under ~600 characters,** the identifying terms early and the long tail late.
85
+ - **Put synonyms and translations on the line itself.** A bilingual row (`Cà phê, đã rang / Coffee, roasted`) matches
86
+ queries in either language.
87
+ - **For prose, keep a rule and its exception close.** A rule on line 40 and its exception on line 90 can be retrieved apart.
193
88
 
194
- An agent narrows by tag rather than reading the whole corpus:
89
+ Markdown headings carry no retrieval weight of their own; a doc's `##` headings outside its blocks, two or more, are
90
+ listed on its page as its sections.
195
91
 
196
- ```bash
197
- lotics tools list_knowledge # takes an optional tag
198
- lotics tools grep_knowledge # same
199
- ```
92
+ The **description is the discovery hint**: it is the only clue for *what term to grep for* before a body is read. Name
93
+ the doc's vocabulary in a sentence.
200
94
 
201
- ## Taking a doc out of circulation — `hide`
202
-
203
- ```bash
204
- lotics knowledge hide kdc_... # superseded, draft, source material
205
- lotics knowledge list --include-hidden # find it again
206
- lotics knowledge unhide kdc_... # put it back
207
- ```
208
-
209
- A hidden doc is out of every **listing**: it is gone from the Library's list, from
210
- `list_knowledge`, and from the corpus `grep_knowledge` searches, so nothing finds it by browsing.
211
- It is not deleted, not unshared, and still **reads when addressed by id** — `read_knowledge` with
212
- its id, a code run staging it, an app agent that declares it. That is the point: hiding is a
213
- statement about discovery, so it cannot silently break an app that depends on a doc by name.
95
+ ## Classifying a corpus — tags
214
96
 
215
- Reach for it instead of `rm` whenever the material still matters: last year's tariff schedule, a
216
- handbook a newer one replaced, the raw source a curated doc was written from.
97
+ A doc carries a SET of labels, not a folder. Order does not matter, a doc can wear several, and the vocabulary is
98
+ whatever the docs themselves use. `tags` on `set_knowledge` states one doc's complete set.
217
99
 
218
100
  ## Deleting and restoring
219
101
 
220
- `lotics knowledge rm <id...>` deletes docs: they leave every listing, search and read. **Their sharing
221
- and version history are kept**, so a deleted doc is recoverable. `lotics knowledge list --deleted`
222
- shows the deleted docs you manage, and `lotics knowledge restore <id...>` brings them back with the
223
- access they had (`restore_knowledge` in chat). A restore is all or none: every id must be a deleted
224
- doc you manage, or nothing changes. A doc with no owner is restored only by an admin, who becomes its
225
- owner. A doc that an app or workflow still names cannot be deleted.
102
+ `delete_knowledge` deletes docs: they leave every listing, search and read. **Their sharing and version history are
103
+ kept**, so a deleted doc is recoverable. `get_workspace` kind `knowledge` with `include_archived: true` lists the deleted
104
+ docs you manage, and `restore_knowledge` brings them back with the access they had. Both take many ids and are all or
105
+ none: every id must be a doc you manage, or nothing changes. A doc with no owner is restored only by an admin, who
106
+ becomes its owner. A doc that an app or workflow still names cannot be deleted.
226
107
 
227
108
  ## Formatting — what a doc draws
228
109
 
@@ -242,20 +123,3 @@ A doc is markdown with GFM tables. Beyond that it draws a few blocks, each in sy
242
123
  Each tag stands on a line of its own, and a tag line inside a fenced code block is code. Attributes are text in double quotes or a number in braces; nothing in a tag runs. A write that adds a tag that does not close, nests wrongly, carries an attribute the tag does not take, or names a component this list lacks (`<Frame>`, `<CodeGroup>`) is refused with the lines to fix; lowercase HTML (`<br>`) stays text.
243
124
 
244
125
  A chart's numbers live in its mermaid source, which agents read and grep like any text: write them there once, not again in a table.
245
-
246
- ## Reaching the tools
247
-
248
- ```bash
249
- lotics knowledge list # catalog: id, name, tags, description
250
- lotics knowledge get kdc_... -o doc.md # read a body to a file (omit -o for stdout)
251
- lotics tools update_knowledge # full input schema for any knowledge tool
252
- ```
253
-
254
- The Knowledge category covers `list_knowledge`, `create_knowledge`, `update_knowledge`,
255
- `delete_knowledge` and `restore_knowledge` — fronted by the `lotics knowledge list | create | get |
256
- update | tag | hide | unhide | rm | restore` commands, and all but `delete_knowledge` and
257
- `restore_knowledge` reachable over MCP as well, so a corpus can be
258
- authored from whichever surface you already work in. `list` (without `--deleted`), `tag`, `hide` and `unhide` go over REST rather than a tool, because
259
- they are a person's view of the corpus: the tools answer what the ASSISTANT may browse, and a
260
- hidden doc is out of that set by definition. Sharing a doc to other members is `share_resource` / `unshare_resource` on the
261
- CLI or in chat (category **Admin**).
package/docs/migration.md CHANGED
@@ -6,54 +6,50 @@ already on disk no longer matches what the CLI does.
6
6
 
7
7
  ## Local app projects are gone
8
8
 
9
- An app built from a model no longer lives in a directory. The live app is the only edit surface:
10
- each change mints a new version of it, and rolling back to an earlier version is the undo. What
9
+ An app stated as a tree no longer lives in a directory. The live app is the only edit surface:
10
+ each change mints a new version of it, and applying the earlier tree again is the undo. What
11
11
  the app is — its screens (`app.json`), its queries, workflows, agents and capabilities, and the
12
- model body it was compiled from — is held by that version, and the model's tables, fields, options,
13
- templates and roles are the workspace's own.
12
+ tree it was compiled from — is held by that version, and the tables, fields, options, templates and
13
+ roles are the workspace's own.
14
14
 
15
15
  | What you ran | What replaces it |
16
16
  |---|---|
17
- | `lotics scaffold check` + `scaffold apply` | `lotics model apply <model.json>` — checks the file, applies the tables and rows, then mints a version of every app it declares |
18
- | `lotics workspace build <model.json>` | `lotics model apply <model.json>` |
19
- | `lotics app create --from <model.json>#<app>` | `lotics model apply <model.json> --app <app>` |
20
- | `lotics app regenerate` | change the model file, then `lotics model apply` |
21
- | `lotics scaffold diff` | `lotics model check <model.json>` — what the apply would change, writing nothing |
22
- | `lotics scaffold export` | `lotics model pull [-o <model.json>]` — the workspace's model, rebuilt from what owns each part |
17
+ | `lotics scaffold check` + `scaffold apply`, `lotics workspace build <model.json>`, `lotics setup <file>` | `lotics run set_tables` with the tables of the workspace in one list (at most 50 a call), then `set_app` for each app (`lotics app apply <file>`); `dry_run` checks and writes nothing |
18
+ | `lotics app create --from <model.json>#<app>` | `lotics app apply <file>` — `set_app` creates the app from its tree |
19
+ | `lotics app regenerate` | change the tree, then `lotics app apply <file>` |
20
+ | `lotics scaffold diff` | `lotics app apply <file> --check` — what would refuse the tree, writing nothing |
21
+ | `lotics scaffold export` | `lotics app pull <app_id> [path]` — the app's tree as JSON, one app at a time |
23
22
  | `lotics app codegen`, `app check`, `app dev`, `app preview` | nothing local: read an app with `lotics run get_app`, and change it through its tools |
24
- | `lotics app workflow set` / `app query set` / `app agent set` | `lotics run set_app_workflow` / `set_app_queries` / `set_app_agent` — each mints a version |
25
- | `lotics app versions` + a redeploy of an old tree | `lotics run query_app_versions`, then `lotics run rollback_app` — restores the app's earlier version; table changes and data writes stay |
26
- | `lotics app rename`, `app subdomain`, `package.json#lotics.capabilities` | `lotics run update_app` (`name`, `public_subdomain`, `capabilities`) |
23
+ | `lotics app workflow set` / `app query set` | `lotics run set_app_workflow` / `set_app_queries` — each mints a version |
24
+ | `lotics app versions` + a redeploy of an old tree | apply the earlier tree again (`lotics app apply <file>`), or deploy the earlier source; table changes and data writes stay |
25
+ | `lotics app rename`, `app subdomain`, `package.json#lotics.capabilities` | `lotics run set_app` with the app's id (`public_subdomain`, `capabilities`; its name is the tree's `name`) |
27
26
  | `lotics app api publish` / `unpublish` | `lotics run publish_app_api` / `unpublish_app_api` |
28
- | `lotics field rename` | `lotics run update_table`, then the same label in the model file |
27
+ | `lotics field rename` | `lotics run set_tables` with a merge patch of the table's document |
29
28
  | `lotics app kit` | nothing: a custom-code app depends on `@lotics/app-sdk` (below) |
30
29
  | `@lotics/xlsx` / `@lotics/docx` to build a template's file | any `.xlsx` / `.docx` library, then `lotics upload` (`lotics docs document_templates`) |
31
30
  | `lotics file preview` | `lotics file download <fil_id>`, then open it |
32
- | `model.json#apply` (`[{package, bind}]`) | state the tables under `entities` — a model carrying `apply` is refused |
33
- | `lotics library list` / `library show <slug>`, `lotics preset list` / `preset show <slug>` | the example models at `https://lotics.ai/presets/index.json`, each a complete `model.json` to adapt |
34
- | `model.json#from` (with `variants`, `rename`) | state every table under `entities` — a model carrying `from` is refused |
35
- | `lotics library init <apg_id>`, `lotics setup <apg_id>`, `lotics app upgrade`, `lotics library fixtures` | nothing copies a package any more: write a `model.json` (`lotics docs model`), then `lotics setup model.json` or `lotics model apply model.json` |
31
+ | `lotics library list` / `library show <slug>`, `lotics preset list` / `preset show <slug>` | the example files at `https://lotics.ai/presets/index.json`, each read and its tables passed to `set_tables` |
32
+ | `lotics library init <apg_id>`, `lotics app upgrade`, `lotics library fixtures` | nothing copies a package any more: state the tables (`lotics docs model`) and pass them to `set_tables` |
36
33
 
37
34
  `lotics tools` lists every tool, and `lotics tools <name>` prints its input.
38
35
 
39
- **An existing JSON app moves on the first `lotics model apply`** of the model it came from: that
40
- apply binds each app alias to the app it already became and mints its next version from the file.
41
- A directory an earlier CLI wrote (`app.json`, `src/workflows/`, `.lotics/`, `package.json#lotics`
42
- with `plan`, `queries` or `workflows`) is no longer read by anything; keep the model file, delete the
36
+ **An existing JSON app moves with `lotics app pull <app_id>`**: it writes the app's tree, and
37
+ `lotics app apply` of that file edits the app and mints its next version. A directory an earlier CLI wrote (`app.json`, `src/workflows/`, `.lotics/`, `package.json#lotics`
38
+ with `plan`, `queries` or `workflows`) is no longer read by anything; keep the pulled tree, delete the
43
39
  rest.
44
40
 
45
41
  **Authored workflow bodies** an act names (`workflow` on an act) are the live workflow's own body:
46
- the apply keeps it, and `lotics run set_app_workflow` changes it.
42
+ `lotics run set_app_workflow` changes it.
47
43
 
48
- **A model written before `party`** draws its people and organisations as things — a row with no
49
- picture shows no initials: state `party` (`person` or `organization`) on those entities' `records`.
44
+ **A table written before `party`** draws its people and organisations as things — a row with no
45
+ picture shows no initials: state `party` (`person` or `organization`) in that table's `records`.
50
46
 
51
47
  ## Custom-code apps use `@lotics/app-sdk`
52
48
 
53
49
  A hand-written app depends on `@lotics/app-sdk` alone — the hooks (`useQuery`, `useWorkflow`, …),
54
50
  `mount`, and `AppRouter` from `@lotics/app-sdk/router` — and draws with its own React.
55
51
  `@lotics/app-runtime` and `@lotics/ui` are no longer published: the runtime is what the platform
56
- draws a model's app with, and it ships with the platform.
52
+ draws an app with, and it ships with the platform.
57
53
 
58
54
  An app that listed `@lotics/app-runtime`:
59
55