@montytools/cli 0.4.1 → 0.4.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@montytools/cli",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/TomasMonty/monty-v2.git",
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: monty-operate
3
+ description: Operate a team's Monty workspace apps from the terminal — read and write a Live app's records with `monty data`. Use whenever the task is to put data INTO an existing Monty app or read data from one: add leads to a CRM, import scraped or external data, update or clean up records, check what an app currently stores, or automate recurring work against apps on usemonty.dev. Building or changing an app itself is monty-build, not this.
4
+ ---
5
+
6
+ # Operating Monty apps
7
+
8
+ A Monty workspace runs internal apps (CRMs, trackers, dashboards) whose data
9
+ lives on the platform. `monty data` is how you — the operating agent — read
10
+ and write that data directly from the terminal: no browser session, no dev
11
+ server. You do the work (browse, scrape, decide, transform); the app is
12
+ where the results land, and open app tabs update live as you write.
13
+
14
+ Two data channels per app: **Live** (the team's real records — the default
15
+ target) and the **Studio sandbox** (`--studio` — development data, never
16
+ seen by the team). Writing to Live is normal operating work; that is what
17
+ this command is for.
18
+
19
+ ## The loop
20
+
21
+ 1. **Find the app.** `monty apps` lists local apps; run inside the app
22
+ folder (`cd "$(monty select <slug>)"`) or pass `--app <slug>` to every
23
+ command.
24
+ 2. **Learn the shape — never guess.** `monty data schema` prints every
25
+ table; `monty data schema <table>` one table. (Schema compiles from the
26
+ local source — if the app isn't on this machine, `monty pull <slug>`
27
+ first.)
28
+ 3. **See what's there.** `monty data list <table> --limit 20` before
29
+ writing: learn the field conventions from real rows and avoid duplicating
30
+ what exists.
31
+ 4. **Write.** Prefer `upsert` with a `--key` for anything imported or
32
+ scraped; `insert` only for rows that are genuinely new by construction.
33
+ 5. **Verify.** `list`/`get` the rows you touched; report counts (added,
34
+ updated, skipped) with specifics.
35
+
36
+ ## Rules
37
+
38
+ 1. **Imports are idempotent.** Any repeatable job (scraping, syncing,
39
+ importing) writes with
40
+ `monty data upsert <table> --key <identityField> --data '[…]'` — the key
41
+ names the field(s) that identify a row (a URL, an email, an external id),
42
+ values come from each row, and re-running never duplicates.
43
+ 2. **Schema first, rows second.** Field names come from
44
+ `monty data schema`, exact spelling. The server stores what you send —
45
+ a misspelled field is silently a new field, not an error.
46
+ 3. **Live is the default and that's correct** — operating work targets the
47
+ team's real data. Use `--studio` only when explicitly rehearsing.
48
+ Destructive verbs (`remove`, bulk `update`) on Live deserve a
49
+ confirmation with the user unless they clearly asked for the cleanup.
50
+ 4. **Batch with arrays.** `--data` accepts a single object or an array;
51
+ arrays write row by row and return all ids in order.
52
+ 5. **Paginate honestly.** `list` returns `"cursor": null` when complete; a
53
+ non-null cursor means more rows exist — repeat with `--cursor <c>`
54
+ before claiming totals.
55
+ 6. **Errors are instructions.** Every failure prints
56
+ `[MontyError CODE] Fix: …` — do what the Fix says. `NOT_LOGGED_IN` means
57
+ run `monty login` (once per machine); `NOT_FOUND` on an id means it came
58
+ from the wrong table or a stale listing — re-`list`, never retry blind.
59
+ 7. **Rows come back flattened**: your fields at the top level plus system
60
+ fields `_id`, `_creationTime`, `updatedAt`, `createdBy`. System fields
61
+ are read-only — never send them in `--data`.
62
+
63
+ ## Command reference
64
+
65
+ | command | purpose |
66
+ |---|---|
67
+ | `monty data schema [table]` | table shapes from the app's config — read this before any write |
68
+ | `monty data list <table> [--filter '{"k":"v"}'] [--order asc\|desc] [--limit N] [--cursor C]` | newest-first rows; filter is exact-match on fields |
69
+ | `monty data get <table> <id>` | one row (null if the id isn't in this table) |
70
+ | `monty data insert <table> --data '<json\|[json,…]>'` | create rows |
71
+ | `monty data upsert <table> --key <field[,field]> --data '<json\|[json,…]>'` | find-or-create matched on the key fields — the idempotent write |
72
+ | `monty data update <table> <id> --data '<json>' [--unset a,b]` | shallow-merge onto one row; `--unset` deletes fields |
73
+ | `monty data remove <table> <id>` | delete one row |
74
+
75
+ All verbs take `--app <slug>` and `--studio`. Output is one JSON document on
76
+ stdout.
77
+
78
+ ## Example: import scraped leads into a CRM app
79
+
80
+ ```sh
81
+ monty data schema leads --app crm # shape: name, company, title, linkedinUrl, status…
82
+ monty data list leads --app crm --limit 50 # what's already in the pipeline
83
+ # …browse/scrape/decide, then land the batch idempotently:
84
+ monty data upsert leads --app crm --key linkedinUrl --data '[
85
+ {"name":"Dana Reeve","company":"Acme","title":"VP Ops","linkedinUrl":"https://linkedin.com/in/dana-r","status":"new"},
86
+ {"name":"Sam Ortiz","company":"Initech","title":"Head of RevOps","linkedinUrl":"https://linkedin.com/in/sam-o","status":"new"}
87
+ ]'
88
+ monty data list leads --app crm --filter '{"status":"new"}' # verify, then report counts
89
+ ```