@lotics/cli 0.87.0 → 0.88.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.
package/README.md CHANGED
@@ -10,6 +10,20 @@ Lotics is an AI-powered operations platform. Through this CLI you can:
10
10
  - Administer the workspace — invite members, manage groups, share resources, transfer ownership, browse connected accounts (OAuth attach is web-only)
11
11
  - Create and manage apps, knowledge docs, and files
12
12
 
13
+ ## Capability guides
14
+
15
+ Two of the platform's primary surfaces have dedicated usage guides that ship inside this
16
+ package (reachable at `node_modules/@lotics/cli/docs/*.md` once installed):
17
+
18
+ - [`docs/document_templates.md`](docs/document_templates.md) — generate finished documents
19
+ (PDF, Excel, Word, email) by filling reusable templates: the five template types, the
20
+ create → generate → chain lifecycle, and the marker capabilities.
21
+ - [`docs/knowledge_docs.md`](docs/knowledge_docs.md) — the AI's rulebook layer: authoring the
22
+ workspace facts an agent can't guess, the access-vs-activation model, and the
23
+ search → grep → read retrieval funnel agents use to pull only the lines they need.
24
+
25
+ Both point to `lotics tools <name>` for exact input schemas.
26
+
13
27
  ## Install
14
28
 
15
29
  ```bash
@@ -58303,11 +58303,10 @@ ${e.toString()}`);
58303
58303
  return val && typeof val === "object" ? val : {};
58304
58304
  }
58305
58305
 
58306
- // ../xlsx/src/biff8_reader.ts
58306
+ // ../shared/src/ole.ts
58307
58307
  var OLE2_MAGIC2 = [208, 207, 17, 224, 161, 177, 26, 225];
58308
58308
  var ENDOFCHAIN = 4294967294;
58309
58309
  var FREESECT = 4294967295;
58310
- var DEFAULT_MAX_ROWS = 1e4;
58311
58310
  function isOle2(bytes) {
58312
58311
  return bytes.length >= 8 && OLE2_MAGIC2.every((b, i3) => bytes[i3] === b);
58313
58312
  }
@@ -58322,7 +58321,7 @@ ${e.toString()}`);
58322
58321
  const firstMiniFatSector = u32(60);
58323
58322
  const firstDifatSector = u32(68);
58324
58323
  if (sectorSize < 512 || sectorSize > 1 << 20) {
58325
- throw new Error("Unsupported .xls: invalid OLE2 sector size");
58324
+ throw new Error("Unsupported OLE2 file: invalid sector size");
58326
58325
  }
58327
58326
  const sectorOffset = (n) => sectorSize * (n + 1);
58328
58327
  const maxSectors = Math.ceil(bytes.length / sectorSize) + 1;
@@ -58384,6 +58383,25 @@ ${e.toString()}`);
58384
58383
  const readStream = (e) => e.size >= miniCutoff ? readBig(e.start, e.size) : readMini(e.start, e.size);
58385
58384
  return dir.filter((e) => e.type === 2).map((e) => ({ name: e.name, bytes: readStream(e) }));
58386
58385
  }
58386
+ function utf16le(b) {
58387
+ let s = "";
58388
+ for (let i3 = 0; i3 + 1 < b.length; i3 += 2) s += String.fromCharCode(b[i3] | b[i3 + 1] << 8);
58389
+ return s;
58390
+ }
58391
+ function concat(parts) {
58392
+ let total = 0;
58393
+ for (const p of parts) total += p.length;
58394
+ const out = new Uint8Array(total);
58395
+ let o = 0;
58396
+ for (const p of parts) {
58397
+ out.set(p, o);
58398
+ o += p.length;
58399
+ }
58400
+ return out;
58401
+ }
58402
+
58403
+ // ../xlsx/src/biff8_reader.ts
58404
+ var DEFAULT_MAX_ROWS = 1e4;
58387
58405
  var REC = {
58388
58406
  FORMULA: 6,
58389
58407
  EOF: 10,
@@ -58682,22 +58700,6 @@ ${e.toString()}`);
58682
58700
  }
58683
58701
  return s;
58684
58702
  }
58685
- function utf16le(b) {
58686
- let s = "";
58687
- for (let i3 = 0; i3 + 1 < b.length; i3 += 2) s += String.fromCharCode(b[i3] | b[i3 + 1] << 8);
58688
- return s;
58689
- }
58690
- function concat(parts) {
58691
- let total = 0;
58692
- for (const p of parts) total += p.length;
58693
- const out = new Uint8Array(total);
58694
- let o = 0;
58695
- for (const p of parts) {
58696
- out.set(p, o);
58697
- o += p.length;
58698
- }
58699
- return out;
58700
- }
58701
58703
  function builtinFormat(id) {
58702
58704
  const DATES = {
58703
58705
  14: "m/d/yyyy",
package/dist/src/cli.js CHANGED
@@ -30830,12 +30830,12 @@ export default defineConfig({
30830
30830
  // default export the dev optimizer won't synthesize unbundled ("does not
30831
30831
  // provide an export named 'default'") \u2014 blanking the iframe the moment a
30832
30832
  // markdown component mounts. Pre-bundling react-markdown folds the whole
30833
- // subtree (incl. style-to-js) into one interop'd chunk; remark-gfm (imported
30834
- // alongside it) is pre-bundled for the same consistency. Both are regular
30835
- // deps of @lotics/ui (hoisted), so they need no package.json entry here.
30833
+ // subtree (incl. style-to-js) into one interop'd chunk. It is a regular dep
30834
+ // of @lotics/ui (hoisted), so it needs no package.json entry here. (The GFM
30835
+ // plugin @lotics/ui composes is pure ESM \u2014 no CJS interop to force.)
30836
30836
  include: [
30837
30837
  "react-native-svg",
30838
- "react-markdown", "remark-gfm",
30838
+ "react-markdown",
30839
30839
  "react-native-web", "@react-native/normalize-colors",
30840
30840
  "inline-style-prefixer/lib/createPrefixer",
30841
30841
  "inline-style-prefixer/lib/plugins/crossFade",
@@ -43352,11 +43352,10 @@ function ensureVmlArray(val) {
43352
43352
  return Array.isArray(val) ? val : [val];
43353
43353
  }
43354
43354
 
43355
- // ../xlsx/src/biff8_reader.ts
43355
+ // ../shared/src/ole.ts
43356
43356
  var OLE2_MAGIC2 = [208, 207, 17, 224, 161, 177, 26, 225];
43357
43357
  var ENDOFCHAIN = 4294967294;
43358
43358
  var FREESECT = 4294967295;
43359
- var DEFAULT_MAX_ROWS = 1e4;
43360
43359
  function isOle2(bytes) {
43361
43360
  return bytes.length >= 8 && OLE2_MAGIC2.every((b, i2) => bytes[i2] === b);
43362
43361
  }
@@ -43371,7 +43370,7 @@ function readCfbStreams(bytes) {
43371
43370
  const firstMiniFatSector = u32(60);
43372
43371
  const firstDifatSector = u32(68);
43373
43372
  if (sectorSize < 512 || sectorSize > 1 << 20) {
43374
- throw new Error("Unsupported .xls: invalid OLE2 sector size");
43373
+ throw new Error("Unsupported OLE2 file: invalid sector size");
43375
43374
  }
43376
43375
  const sectorOffset = (n) => sectorSize * (n + 1);
43377
43376
  const maxSectors = Math.ceil(bytes.length / sectorSize) + 1;
@@ -43433,6 +43432,25 @@ function readCfbStreams(bytes) {
43433
43432
  const readStream = (e) => e.size >= miniCutoff ? readBig(e.start, e.size) : readMini(e.start, e.size);
43434
43433
  return dir.filter((e) => e.type === 2).map((e) => ({ name: e.name, bytes: readStream(e) }));
43435
43434
  }
43435
+ function utf16le(b) {
43436
+ let s = "";
43437
+ for (let i2 = 0; i2 + 1 < b.length; i2 += 2) s += String.fromCharCode(b[i2] | b[i2 + 1] << 8);
43438
+ return s;
43439
+ }
43440
+ function concat(parts) {
43441
+ let total = 0;
43442
+ for (const p of parts) total += p.length;
43443
+ const out = new Uint8Array(total);
43444
+ let o = 0;
43445
+ for (const p of parts) {
43446
+ out.set(p, o);
43447
+ o += p.length;
43448
+ }
43449
+ return out;
43450
+ }
43451
+
43452
+ // ../xlsx/src/biff8_reader.ts
43453
+ var DEFAULT_MAX_ROWS = 1e4;
43436
43454
  var REC = {
43437
43455
  FORMULA: 6,
43438
43456
  EOF: 10,
@@ -43731,22 +43749,6 @@ function readUnicodeShort(b, offset, lenBytes) {
43731
43749
  }
43732
43750
  return s;
43733
43751
  }
43734
- function utf16le(b) {
43735
- let s = "";
43736
- for (let i2 = 0; i2 + 1 < b.length; i2 += 2) s += String.fromCharCode(b[i2] | b[i2 + 1] << 8);
43737
- return s;
43738
- }
43739
- function concat(parts) {
43740
- let total = 0;
43741
- for (const p of parts) total += p.length;
43742
- const out = new Uint8Array(total);
43743
- let o = 0;
43744
- for (const p of parts) {
43745
- out.set(p, o);
43746
- o += p.length;
43747
- }
43748
- return out;
43749
- }
43750
43752
  function builtinFormat(id) {
43751
43753
  const DATES = {
43752
43754
  14: "m/d/yyyy",
@@ -235,12 +235,12 @@ export default defineConfig({
235
235
  // default export the dev optimizer won't synthesize unbundled ("does not
236
236
  // provide an export named 'default'") — blanking the iframe the moment a
237
237
  // markdown component mounts. Pre-bundling react-markdown folds the whole
238
- // subtree (incl. style-to-js) into one interop'd chunk; remark-gfm (imported
239
- // alongside it) is pre-bundled for the same consistency. Both are regular
240
- // deps of @lotics/ui (hoisted), so they need no package.json entry here.
238
+ // subtree (incl. style-to-js) into one interop'd chunk. It is a regular dep
239
+ // of @lotics/ui (hoisted), so it needs no package.json entry here. (The GFM
240
+ // plugin @lotics/ui composes is pure ESM no CJS interop to force.)
241
241
  include: [
242
242
  "react-native-svg",
243
- "react-markdown", "remark-gfm",
243
+ "react-markdown",
244
244
  "react-native-web", "@react-native/normalize-colors",
245
245
  "inline-style-prefixer/lib/createPrefixer",
246
246
  "inline-style-prefixer/lib/plugins/crossFade",
@@ -0,0 +1,153 @@
1
+ # Document Templates
2
+
3
+ Turn workspace data into finished documents — invoices, contracts, reports, letters,
4
+ labels, emails — by filling a reusable template instead of writing a file from scratch.
5
+ You register a template once, then generate a filled file (or a rendered email) from it as
6
+ many times as you like, feeding it data from records, a workflow, or an agent run.
7
+
8
+ This is a **capability + usage** guide. For the exact input schema of any tool named here,
9
+ run `lotics tools <tool_name>` — that is always the source of truth for arguments.
10
+
11
+ ## The five template types
12
+
13
+ | Type | What it fills | Output | Create with |
14
+ |---|---|---|---|
15
+ | `pdf-form` | fields overlaid on an **uploaded PDF** at fixed positions | PDF | `create_pdf_template` (mode `form`) |
16
+ | `html` (a PDF) | an **HTML + Handlebars** layout you write from scratch | PDF | `create_pdf_template` (mode `html`) |
17
+ | `excel` | an **uploaded `.xlsx`** with `{{marker}}` cells | `.xlsx` | `create_excel_template` |
18
+ | `word` | an **uploaded `.docx`** with `{{marker}}`s | `.docx` | `create_word_template` |
19
+ | `email` | an **inline HTML + Handlebars** body, rendered when the email is sent | email | `create_email_template` |
20
+
21
+ Two shapes underneath: **file-backed** (`pdf-form`, `excel`, `word`) clone an uploaded
22
+ office file and mark it up; **inline** (`html`, `email`) store the markup you author directly.
23
+
24
+ ## The lifecycle: create → generate → chain
25
+
26
+ 1. **Create** a template — register the file (or inline markup) and declare a `variables`
27
+ map (the named slots the template fills). This returns a template id (`tpl_…`).
28
+ 2. **Generate** a filled file — call the matching `generate_*_from_template` with the
29
+ template id, a `filename` (no extension), and a `data` map keyed by your variable names.
30
+ It substitutes the markers and returns a **generated file** (with a `file_id`).
31
+ 3. **Chain** the result — generation only *produces* the file. Attaching it to a record,
32
+ sending it, or saving it locally is a separate step: inside a workflow, pass the returned
33
+ `file_id` to the next step; from the CLI, `lotics download <file_id>` fetches it.
34
+
35
+ Email is the exception: there is **no** `generate_email_from_template`. An email template is
36
+ rendered to a subject + body **at send time** from the template and the data the send step
37
+ supplies — so you author it with `create_email_template` and a workflow/app send step (or the
38
+ web composer) does the rendering and delivery. External agents send their own email directly.
39
+
40
+ ## Creating each type
41
+
42
+ ### PDF from HTML (`create_pdf_template`, mode `html`)
43
+
44
+ Write a full HTML document with inline CSS and `{{variable}}` placeholders; it renders to PDF
45
+ via a headless browser. Good for invoices, reports, letters, certificates — anything whose
46
+ layout you control. Declare `variables` (plain text, rich `html`, an auto-rendered `table`,
47
+ or a `list`), and optionally `format` (page size) and `orientation`. See
48
+ `lotics tools create_pdf_template` for the exact variable shapes.
49
+
50
+ ### PDF form (`create_pdf_template`, mode `form`)
51
+
52
+ For an existing PDF you must fill in place (a government form, a printed contract):
53
+
54
+ 1. `lotics upload ./form.pdf` → a `file_id`.
55
+ 2. `create_pdf_template` with mode `form` and that `file_id`.
56
+ 3. `analyze_pdf_template` — extracts the labels and their positions off the page.
57
+ 4. `update_pdf_template` — define the positioned fields (`text` / `checkbox` / `image`, each
58
+ with a page + x/y/size) in `variables`.
59
+
60
+ Form-mode data is scalar-only (text, numbers, checkboxes) — one value per positioned field.
61
+
62
+ ### Excel (`create_excel_template`)
63
+
64
+ 1. Build a `.xlsx` in Excel (or with `lotics xlsx`) and put `{{marker}}`s in the cells that
65
+ should be filled. `lotics upload ./template.xlsx` → a `file_id`.
66
+ 2. `create_excel_template` with that `template_file_id` and a `variables` map. Markers are
67
+ **validated at create time** — a structural error (mismatched loop, unknown helper, bad
68
+ placement) blocks the save, and declared variables with no matching marker come back in
69
+ `unmarked_variables` (skipped, not filled).
70
+
71
+ To inspect or add markers on the uploaded file without leaving the CLI: `excel_get_range` /
72
+ `excel_find_cells` to look, `excel_update_range` to write markers, `validate_excel_template`
73
+ to re-check. Pass raw numbers / ISO dates / booleans at generate time — the cell's number
74
+ format handles display.
75
+
76
+ ### Word (`create_word_template`)
77
+
78
+ 1. Build a `.docx` with `{{marker}}`s where values go. `lotics upload ./template.docx`.
79
+ 2. `create_word_template` with the `template_file_id` and `variables`. As with Excel, an
80
+ unmarked declared variable comes back in `unmarked_variables` and is skipped.
81
+
82
+ To add markers/loops/conditionals to the uploaded file from the CLI: `word_replace_text`,
83
+ `word_insert_loop`, `word_insert_conditional` (and their `remove_*` counterparts).
84
+
85
+ ### Email (`create_email_template`)
86
+
87
+ Inline HTML + Handlebars, no uploaded file. Declare `variables`, and optionally a default
88
+ `subject` (which itself supports `{{variable}}` expressions) and default to/cc/bcc. The body
89
+ and subject render from the data at send time.
90
+
91
+ ## Markers, at a usage level
92
+
93
+ Every type supports three shapes of substitution. The exact syntax differs per engine — read
94
+ the create-tool description for the reference; here is the capability:
95
+
96
+ - **Scalar** — a single value in one spot: `{{name}}`, `{{total}}`. Whole-cell scalars in
97
+ Excel preserve their type via the cell's number format.
98
+ - **Repeating rows / line items** — one template row rendered once per item in a list, for
99
+ invoice lines, order rows, tables. Excel and the HTML/email engines use a Handlebars-style
100
+ `{{#each items}}…{{/each}}`; Word uses `{{FOR item IN items}}…{{$item.field}}…{{END-FOR item}}`
101
+ (the `word_insert_loop` tool writes these command rows for you). The HTML and email types
102
+ also offer an auto-rendered `table` variable — declare its columns and pass an array, no
103
+ hand-written loop. (Excel always uses the `{{#each}}` marker rows — it has no auto-rendered
104
+ `table` type; its variable types are string/number/date/boolean/array.)
105
+ - **Conditional sections** — a block shown only when a condition holds (a "paid" stamp, an
106
+ optional notes block). Excel/HTML/email use `{{#if}}…{{else}}…{{/if}}`; Word uses
107
+ `word_insert_conditional`.
108
+
109
+ Run `lotics tools create_excel_template`, `create_word_template`, `create_pdf_template`, or
110
+ `create_email_template` for each engine's exact marker grammar and helper list — don't guess it.
111
+
112
+ ## Generating a filled file
113
+
114
+ ```bash
115
+ # See what a template expects, then fill it
116
+ lotics tools generate_excel_from_template
117
+ lotics run get_template '{"template_id":"tpl_..."}' # its declared variables
118
+ lotics run generate_excel_from_template '{"document_template_id":"tpl_...","filename":"invoice-1042","data":{"company_name":"Acme","total":1042,"items":[...]}}'
119
+ lotics download <file_id> -o ./out/
120
+ ```
121
+
122
+ - `data` is a map keyed by your variable names. Scalars for scalar/form fields; arrays for
123
+ `table`/`list`/loop variables. `filename` excludes the extension (the type sets it).
124
+ - Each `generate_*_from_template` returns a generated file object; take its `file_id` onward.
125
+ - In a workflow, a **generate step** calls the same tools and hands the `file_id` to the next
126
+ step (attach to a record, send as an attachment, etc.) — see `docs/workflow_engine.md` in
127
+ the platform docs.
128
+
129
+ ## Discovering and managing templates
130
+
131
+ Four unified tools work across all five types:
132
+
133
+ | Tool | Does |
134
+ |---|---|
135
+ | `query_templates` | list templates (optionally filter by type: excel/word/pdf/email) |
136
+ | `get_template` | one template's full definition, incl. the `variables` it expects |
137
+ | `clone_template` | copy a template to iterate on |
138
+ | `delete_template` | remove a template |
139
+
140
+ Call `get_template` before generating when you don't already know a template's variable names.
141
+
142
+ ## Reaching the tools
143
+
144
+ ```bash
145
+ lotics tools # all categories
146
+ lotics tools create_word_template # one tool: full description + input schema
147
+ lotics run <tool> '<json-args>' # execute (inline JSON, @file.json, or piped stdin)
148
+ ```
149
+
150
+ The template tools live in the categories **PDF Templates**, **Excel Templates**,
151
+ **Word Templates**, **Email Templates**, and **Templates** (the unified query/get/clone/delete).
152
+ Uploading the source file for a file-backed template is `lotics upload <file>`; fetching a
153
+ generated file is `lotics download <file_id>`.
@@ -0,0 +1,112 @@
1
+ # Knowledge Docs
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.
7
+
8
+ They are deliberately **not** injected into the agent wholesale. Bulk-loading every doc into
9
+ every request would burn the context budget and drown the signal. Instead the agent retrieves
10
+ from them through a search funnel, so a 10,000-line tariff book costs nothing until a question
11
+ actually touches it.
12
+
13
+ This is a **capability + usage** guide. For the exact input schema of any tool named here, run
14
+ `lotics tools <tool_name>`.
15
+
16
+ ## Rulebook, not methodology
17
+
18
+ Put in a knowledge doc the things the model **cannot guess**: your specific numbers, codes,
19
+ names, exceptions, and policies. Do **not** put in it general skills the model already has
20
+ ("how to write a polite email", "how to summarize"). If the agent would get it right without
21
+ the doc, the doc is noise. A knowledge doc earns its place only by carrying external facts
22
+ tied to your workspace.
23
+
24
+ ## Creating a doc — `create_knowledge`
25
+
26
+ ```bash
27
+ lotics run create_knowledge @doc.json # content is large → read from a file or stdin
28
+ ```
29
+
30
+ `create_knowledge` takes three things:
31
+
32
+ - `name` — what it is.
33
+ - `description` — what the doc is **and how to retrieve from it**: its vocabulary, synonyms for
34
+ colloquial terms, and what to read for detail. This is surfaced when the doc is *found*,
35
+ before its content is read, so the agent knows whether to open it.
36
+ - `content` — Markdown.
37
+
38
+ A new doc is created **owned by you, active in your own agent context, and private** — no one
39
+ else can see it yet. (The tool itself takes only name/description/content; attaching files to a
40
+ doc and changing its default-active state are done through the web app / REST surface, not this
41
+ tool.)
42
+
43
+ ## Access vs. activation — both are required
44
+
45
+ A knowledge doc reaches an agent only when **two** conditions hold for that member:
46
+
47
+ 1. **Access** — the member can `use` the doc. New docs are private to the owner; share them
48
+ with other members or groups using the IAM tool `share_resource` (category **Admin**;
49
+ `unshare_resource` to revoke).
50
+ 2. **Activation** — the doc is *active* in that member's agent context. Activation is
51
+ **separate from sharing**: a member can have access to a doc that is switched off in their
52
+ context, and it won't reach their agent. Each doc has a default-active state (on by default),
53
+ and each member can override it on or off for themselves. Activation is toggled in the web
54
+ app, per member — there is no CLI tool for it.
55
+
56
+ So: shared + active → the agent can find and read it. Shared but deactivated → invisible to
57
+ that member's agent. This is the token economy in action — activation is how a member curates
58
+ which rulebooks their agent carries.
59
+
60
+ ## How an agent uses a doc — the retrieval funnel
61
+
62
+ The agent narrows from "which doc" to "which lines" in three steps. All four tools respect
63
+ access + activation, so they only ever surface docs the caller may use.
64
+
65
+ 1. **Find the doc** — `search_knowledge` (keyword query → matching docs + a snippet) or
66
+ `query_knowledge` (list every active doc). Returns *docs*, not the lines inside them.
67
+ 2. **Locate lines within one doc** — `grep_knowledge` (regex over the lines of a single doc,
68
+ returns matches with line numbers). Matching is **diacritics-insensitive by default** — a
69
+ plain-ASCII query matches accented Vietnamese text — and can be case-insensitive too.
70
+ 3. **Read the section** — `read_knowledge`. Pass `outline: true` first to get the Markdown
71
+ header map (a table of contents with line numbers), then read a section with `offset` (the
72
+ 1-based first line) + `limit` (line count). A large doc never returns whole; reads are
73
+ line-numbered and paged.
74
+
75
+ The whole point of the funnel is that the agent lands on the exact section that answers the
76
+ question without ever loading the rest. Structure your content so it works:
77
+
78
+ - Organize under clear Markdown headers, so the doc can be outlined and read by section.
79
+ - Keep each searchable unit self-contained — a section for prose, **one record per line** for
80
+ dense/tabular data (a price row, a code entry) — carrying both the terms someone would search
81
+ for and its answer.
82
+ - Lead with the most-queried fields.
83
+ - Note colloquial synonyms next to official terms, so an ambiguous query still matches.
84
+
85
+ ## Updating a doc — `update_knowledge`
86
+
87
+ Send only the fields you're changing. Content edits are **diffs**, not a full rewrite: pass an
88
+ `edits` array (replace / insert / append operations) plus the `expected_version` you got from
89
+ `read_knowledge` (optimistic concurrency — a stale version is rejected). Refine structure as you
90
+ learn what users actually ask: add the synonym that failed to match, split the section that was
91
+ too coarse to grep. See `lotics tools update_knowledge` for the edit shape.
92
+
93
+ ## Package-managed knowledge
94
+
95
+ A knowledge doc can also be delivered as part of a **content package** — a versioned corpus of
96
+ docs (and document templates) published from one workspace and installed into others. Install
97
+ delivers the docs; upgrade refreshes them in place. Authoring, sharing, and retrieval work the
98
+ same either way; the package layer just manages distribution and version pinning. See
99
+ `docs/packages.md` in the platform docs for the publish/install/upgrade lifecycle.
100
+
101
+ ## Reaching the tools
102
+
103
+ ```bash
104
+ lotics tools # all categories (knowledge tools are under "Knowledge")
105
+ lotics tools grep_knowledge # one tool: full description + input schema
106
+ lotics run create_knowledge @doc.json
107
+ echo '{"query":"tariff"}' | lotics run search_knowledge
108
+ ```
109
+
110
+ The Knowledge category covers `create_knowledge`, `update_knowledge`, `query_knowledge`,
111
+ `search_knowledge`, `grep_knowledge`, `read_knowledge`, and `delete_knowledge`. Sharing a doc
112
+ to other members is `share_resource` / `unshare_resource` (category **Admin**).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lotics/cli",
3
- "version": "0.87.0",
3
+ "version": "0.88.0",
4
4
  "description": "Lotics SDK and CLI for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,7 +11,8 @@
11
11
  },
12
12
  "files": [
13
13
  "dist",
14
- "README.md"
14
+ "README.md",
15
+ "docs"
15
16
  ],
16
17
  "scripts": {
17
18
  "build": "tsgo && node scripts/build_cli.mjs",