@xanots/sdk 0.0.3 → 0.0.4

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.
Files changed (87) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +34 -1
  3. package/dist/agent-file-refresh-IJ7GN2FJ.js +17 -0
  4. package/dist/bin.js +12 -153
  5. package/dist/{capture-HUV5BNTC.js → capture-7PO6SGB4.js} +2 -2
  6. package/dist/{chunk-CMZLPTGW.js → chunk-7SISR3CS.js} +2 -2
  7. package/dist/{chunk-7DKX2SPN.js → chunk-ACQCK4DT.js} +4 -4
  8. package/dist/{chunk-XQ22GLYS.js → chunk-AJ7JQ4OU.js} +5 -5
  9. package/dist/{chunk-ZO3HJOCJ.js → chunk-ALNQCWAW.js} +2 -2
  10. package/dist/{chunk-55VHDNW5.js → chunk-BPEEGJJA.js} +108 -3
  11. package/dist/{chunk-U3G2UW65.js → chunk-CYJ7R3AD.js} +3 -3
  12. package/dist/{agent-file-refresh-6M5M7T24.js → chunk-D6OGU2AI.js} +5 -6
  13. package/dist/{chunk-3NFUWXOC.js → chunk-DUC3PXDG.js} +142 -45
  14. package/dist/{chunk-HQ2CBRVI.js → chunk-EAIR6VUL.js} +10 -8
  15. package/dist/chunk-ERQZFWIW.js +22 -0
  16. package/dist/{chunk-TQUO2OXY.js → chunk-FN4OQT2J.js} +4 -4
  17. package/dist/{chunk-6USV65XA.js → chunk-KGNJM4LN.js} +2 -2
  18. package/dist/{chunk-HJPTWBLH.js → chunk-MFIHIS6B.js} +2 -2
  19. package/dist/{chunk-F6JCFRKO.js → chunk-PXXLBXOP.js} +2 -2
  20. package/dist/{chunk-YZ4GU6F5.js → chunk-QUUB7HYK.js} +5 -838
  21. package/dist/{chunk-W2G2WPTB.js → chunk-SWIXWJIY.js} +3 -3
  22. package/dist/{chunk-76QBEIGO.js → chunk-T4XPCJRF.js} +3 -2
  23. package/dist/chunk-T6N3VMMO.js +173 -0
  24. package/dist/{chunk-2V4YE6QC.js → chunk-VKD3EBKG.js} +112 -21
  25. package/dist/{chunk-BT2CSEC5.js → chunk-VWGJQTNA.js} +3 -3
  26. package/dist/chunk-WGDAOOXG.js +845 -0
  27. package/dist/{chunk-4YMD2OOZ.js → chunk-XHEXOES3.js} +1 -1
  28. package/dist/{chunk-4HT3BNZ7.js → chunk-YUBJLB6G.js} +10 -2
  29. package/dist/{chunk-5L4X5LS6.js → chunk-YUPQOLFX.js} +77 -2
  30. package/dist/{chunk-DYCLVQXW.js → chunk-YYSJAAJM.js} +25 -1
  31. package/dist/{chunk-P3TTMWUP.js → chunk-ZOYMZZ3S.js} +8 -1
  32. package/dist/chunk-ZSYZTGJH.js +81 -0
  33. package/dist/cli.d.ts +6 -0
  34. package/dist/cli.js +8 -8
  35. package/dist/{codegen-command-FIADGXRN.js → codegen-command-Z7WQMOJ7.js} +21 -20
  36. package/dist/{completion-BKAFCZBE.js → completion-4GYN752B.js} +2 -2
  37. package/dist/{deploy-command-4R6BYC6G.js → deploy-command-M2S4HHLC.js} +26 -26
  38. package/dist/{env-target-XWS2ZZ2Y.js → env-target-GSFCYHKZ.js} +6 -6
  39. package/dist/{ephemeral-command-JL4TPIRQ.js → ephemeral-command-6WJW7LP6.js} +24 -24
  40. package/dist/index.d.ts +2 -2
  41. package/dist/index.js +13 -7
  42. package/dist/init-command-GJUPWTKA.js +30 -0
  43. package/dist/internal.d.ts +2 -2
  44. package/dist/internal.js +50 -5
  45. package/dist/{io-AMIKRLPC.js → io-7VIA5SON.js} +3 -3
  46. package/dist/{live-diff-RXSJCVJ7.js → live-diff-FP4SFNT4.js} +2 -2
  47. package/dist/{lock-3CVKALKT.js → lock-KXOJIGCG.js} +2 -2
  48. package/dist/{lock-commands-XOYS75YQ.js → lock-commands-7IH7RSSP.js} +9 -9
  49. package/dist/{login-command-ACJF6KWQ.js → login-command-QM5SBBI2.js} +2 -2
  50. package/dist/{logout-command-MX3MJS5U.js → logout-command-THPASOHM.js} +2 -2
  51. package/dist/{loop-SAWAOUFO.js → loop-7SAIGRCZ.js} +3 -3
  52. package/dist/{marketplace-command-UVV3XAOL.js → marketplace-command-463DT7O7.js} +11 -25
  53. package/dist/meta-client-OW5WKWW7.js +1 -1
  54. package/dist/node.d.ts +2 -2
  55. package/dist/node.js +18 -12
  56. package/dist/onboard-command-EHOHKQQU.js +36 -0
  57. package/dist/{profile-command-SWJ3SPKR.js → profile-command-EUWPVWED.js} +6 -6
  58. package/dist/{release-command-HZUY2XZX.js → release-command-M4CVNTWL.js} +25 -25
  59. package/dist/{sandbox-details-command-HJE5SPVG.js → sandbox-details-command-BRII3QHG.js} +5 -5
  60. package/dist/{sandbox-export-command-QCJY4GMV.js → sandbox-export-command-PCZ5FL4U.js} +8 -8
  61. package/dist/scaffold.js +4 -2
  62. package/dist/{store-g45zwB33.d.ts → store-BJONDJoZ.d.ts} +171 -2
  63. package/dist/{test-command-72Y5S22H.js → test-command-U4G5Y3UM.js} +10 -10
  64. package/dist/upgrade-command-CKJ4BS2P.js +177 -0
  65. package/dist/{validate-command-KDGH537H.js → validate-command-S5N37JRP.js} +12 -12
  66. package/dist/{workspace-command-ICSI6PKO.js → workspace-command-RALSEJSW.js} +28 -27
  67. package/dist/workspace-export-AJMGN3CQ.js +1 -1
  68. package/guides/README.md +30 -0
  69. package/guides/authoring.md +642 -0
  70. package/guides/cli.md +191 -0
  71. package/guides/codegen.md +83 -0
  72. package/guides/coverage.md +67 -0
  73. package/guides/deploying.md +340 -0
  74. package/guides/environment.md +132 -0
  75. package/guides/object-kinds.md +376 -0
  76. package/guides/project-structure.md +43 -0
  77. package/guides/scaffold.md +198 -0
  78. package/guides/typed-frontend.md +201 -0
  79. package/llms/kinds-knowledge.md +20 -0
  80. package/llms/object-kinds.md +1 -0
  81. package/llms-full.txt +25 -2
  82. package/llms.txt +3 -2
  83. package/manifest.json +26 -3
  84. package/package.json +5 -2
  85. package/dist/.build-fingerprint +0 -1
  86. package/dist/chunk-WUSKBXXD.js +0 -25
  87. package/dist/init-command-LOK75W64.js +0 -29
package/guides/cli.md ADDED
@@ -0,0 +1,191 @@
1
+ # CLI
2
+
3
+ Every `xanots` command, shell completion, and what the CLI prints when something fails.
4
+
5
+ ```bash
6
+ xanots init my-app # scaffold a full project (frontend/ + xano/)
7
+ xanots init my-app --framework svelte # SvelteKit instead of the default React
8
+ xanots init my-app --ai claude --no-install # add CLAUDE.md; skip npm install
9
+ xanots init my-app --theme zinc-blue --dark toggle --icons tabler # the look
10
+ xanots init my-app --marketplace @xanots/auth,@xanots/vector # install add-ons AND register them
11
+
12
+ xanots marketplace list # every published add-on (no login needed)
13
+ xanots marketplace search auth # narrow by keyword
14
+ xanots marketplace details @xanots/auth # what it installs + the registration to copy
15
+ xanots marketplace details @xanots/auth --prompt # …as a prompt for a coding agent
16
+ xanots marketplace install @xanots/auth # add an add-on to the project you're in
17
+
18
+ xanots export ./xano/index.ts # bundle to stdout
19
+ xanots export ./xano/index.ts --out ws.json
20
+ xanots compile ./xano/functions/get-user.ts # a single function's JSON
21
+
22
+ xanots export ./xano/index.ts --strict # CI: fail the build on any warning, don't just print it
23
+ xanots export ./xano/index.ts --lock # opt into xano.lock (created beside the entry)
24
+ xanots export ./xano/index.ts --frozen-lock # CI guard: fail if the export would change the lock
25
+ xanots lock rename --entry=xano/index.ts table users members # move a lock entry after renaming in code
26
+ xanots lock prune ./xano/index.ts --yes # drop lock entries nothing exports anymore
27
+ xanots lock prune --no-verify --entry=xano/index.ts --yes dbo:notes # …or drop named keys without running the workspace
28
+ xanots lock adopt live-export.json --entry=xano/index.ts --yes # seed the lock from a live engine export
29
+
30
+ xanots login # OAuth sign-in (once) — pick the instance + workspace at consent
31
+ xanots workspace details # which instance/workspace am I bound to, and via which credential?
32
+ xanots deploy ./xano/index.ts # compile + import into a live ephemeral (the dev loop) → URL
33
+ xanots deploy ./xano/index.ts --dest sandbox # …or your throwaway singleton sandbox
34
+ xanots deploy ./xano/index.ts --static ./frontend/dist # also deploy a static frontend (onto the ephemeral)
35
+ xanots deploy ./xano/index.ts --static ./frontend/dist --static-env PK=pk_live_1 # + extra public config
36
+ xanots deploy --bundle ws.json # deploy an already-exported bundle
37
+ xanots deploy ./xano/index.ts --open # …and open the deployed URL in your browser
38
+ xanots ephemeral list # list your ephemeral environments (--all-workspaces spans every workspace)
39
+ xanots ephemeral get <tenant> # base URL, state, and expiry for one (<tenant> = the tenant name, e.g. ewap-8wz9-9e13, NOT the display name — `ephemeral list` shows it in bold)
40
+ xanots ephemeral delete <tenant> --yes # destroy one
41
+ xanots ephemeral impersonate <tenant> # open it in the builder (--guest = read-only; --url-only prints the URL instead)
42
+ xanots release ./xano/index.ts --dry-run # preview what promoting to your main workspace would change
43
+ xanots release ./xano/index.ts # promote: add + update, never delete, never touch table data
44
+ xanots release ./xano/index.ts --prune # …also delete objects this project released and no longer defines (needs xano.lock)
45
+ xanots sandbox export # export the DEPLOYED sandbox workspace as a JSON bundle → ./sandbox.json
46
+ xanots sandbox export --format multidoc --name backend # …or the deployed sandbox as XanoScript → backend.xs
47
+ xanots sandbox export --format multidoc --path - # …stream the multidoc to stdout (deploy first)
48
+ xanots sandbox details # print the sandbox base URL + tenant details (pretty on a TTY, JSON when piped)
49
+
50
+ xanots workspace details # which workspace your token is scoped to (instance, id, name, guid)
51
+ xanots workspace export --path ws.json # your REAL workspace as a JSON bundle (`--path -` streams to stdout)
52
+ xanots workspace codegen my-app # …or as a runnable project (the pull direction)
53
+ xanots sandbox codegen my-app # same, from your sandbox
54
+ xanots ephemeral codegen <tenant> my-app # same, from an ephemeral (tenant first, path second)
55
+ xanots codegen ws.json my-app # …or from a bundle already on disk (offline, no auth)
56
+
57
+ xanots profile me # print the scoped user + instance base URL (pretty on a TTY, JSON when piped)
58
+ xanots whoami # alias for `profile me`
59
+ xanots logout # revoke the refresh token + clear the shared cache (--local for the project one)
60
+ xanots version # print the installed @xanots/sdk version
61
+ xanots upgrade --check # is a newer @xanots/sdk published? exits 7 if so, 0 if current
62
+ xanots upgrade # install it (-g or -D, matching how this CLI is installed)
63
+ xanots help # grouped command reference (also the no-arg default)
64
+ xanots <command> --help # that command's usage, subcommands, and flags (`xanots deploy --help`)
65
+ xanots <noun> <verb> --help # scoped to one verb (`xanots workspace codegen --help`)
66
+ xanots <command> --json # force JSON on stdout (otherwise: whenever stdout isn't a terminal)
67
+ xanots completion zsh # shell completion script (also bash, fish) — see below
68
+
69
+ xanots validate ./xano/index.ts # import into a live instance, diff each object back
70
+ xanots validate ./xano/index.ts --runtime # also run each deployed function on the engine
71
+ xanots validate ./xano/index.ts --capture # write the fetched JSON as fixture candidates
72
+ ```
73
+
74
+ ## Bundle key names vs. the names everything else uses
75
+
76
+ A bundle's `payload` arrays are keyed by the engine's **storage** name, which for five kinds
77
+ is not the name the SDK, the CLI, or a release plan uses for the same thing. Scripting against
78
+ a bundle means translating:
79
+
80
+ | You author / the plan reports | `payload` array |
81
+ |---|---|
82
+ | `table` | `payload.dbo` |
83
+ | `api_group` | `payload.app` |
84
+ | `agent` | `payload.toolset` |
85
+ | `mcp_server` | `payload.toolset` |
86
+ | `toolset` | `payload.tool` |
87
+ | `realtime_channel` | `payload.channel` |
88
+ | `realtime_message` | `payload.message` |
89
+
90
+ Everything else (`query`, `function`, `task`, `trigger`, `middleware`, `microservice`,
91
+ `addon`, `workflow_test`, `workspace`) is keyed the same on both sides.
92
+
93
+ Two traps worth naming. A release plan reports operations as `{"type": "table", …}` while the
94
+ bundle it came from stores that object under `payload.dbo` — so a table that released
95
+ correctly looks *missing* if you go looking for `payload.table`. And `agent` and `mcp_server`
96
+ both land in `payload.toolset`, while the kind actually named `toolset` lands in
97
+ `payload.tool`; matching on the word alone will pick the wrong array.
98
+
99
+ This is also the format `xanots lock adopt` reads, so both directions are user-facing.
100
+
101
+
102
+ **Build warnings, and `--strict`.** `export`/`deploy` print a `xanots:` warning for the
103
+ shapes that ship clean and then do the wrong thing — a `bulk.update` zero-filling the columns
104
+ an item omits, an `ignoreEmpty` on an operand that's already empty, a `ref()` no `as` binds,
105
+ a filter name the engine can't resolve, a `s.switch` case that falls through into the next
106
+ one, a request-time timestamp filter on a `where` operand. Each stays a warning because each
107
+ has a legitimate use. Nothing fails on a message nobody reads, though, so pass `--strict` in CI and in
108
+ unattended agent builds: every warning becomes a hard failure and the exit code carries it.
109
+ The programmatic equivalents are `emitBundle(app, { strict: true })` and
110
+ `app.export({ strict: true })`. The bundle bytes are identical either way.
111
+
112
+ ## Shell completion
113
+
114
+ `xanots completion <bash|zsh|fish>` prints a completion script covering every command, verb, flag,
115
+ and closed value set (`--dest ephemeral|sandbox`, `--format json|multidoc`, `--ai claude|codex|cursor|none`).
116
+ It is generated from the CLI's own command table, so it never drifts from what the CLI accepts — but it
117
+ is baked at generation time, so re-run it after upgrading.
118
+
119
+ ```bash
120
+ # zsh
121
+ xanots completion zsh > "${fpath[1]}/_xanots" # then restart your shell
122
+
123
+ # bash
124
+ xanots completion bash > ~/.xanots-completion.bash
125
+ echo 'source ~/.xanots-completion.bash' >> ~/.bashrc
126
+
127
+ # fish
128
+ xanots completion fish > ~/.config/fish/completions/xanots.fish
129
+ ```
130
+
131
+ After a command succeeds the CLI checks npm (at most once an hour, cached in
132
+ `~/.xanots/update-check.json`) and prints a one-line nudge to **stderr** when a newer
133
+ `@xanots/sdk` is published — never to stdout, so piped bundles stay clean. The suggested
134
+ command adapts to how you installed it (`npm i -g …` for a global install, `npm i -D …`
135
+ when it's a project dependency). The check is best-effort and bounded (a slow or offline
136
+ registry never delays a command), and stays silent under CI or when stderr isn't a terminal.
137
+ Opt out with `XANOTS_NO_UPDATE_CHECK=1` (or the conventional `NO_UPDATE_NOTIFIER=1`).
138
+
139
+ `xanots upgrade` is the same question asked on purpose, and it answers under all the
140
+ conditions the nudge stays quiet for — CI, a piped stderr, the opt-out variables — reading the
141
+ registry live rather than serving the hourly cache. `--check` reports without installing and
142
+ exits **7** when a newer version is published, **0** when you are current, so a pipeline can
143
+ branch on it:
144
+
145
+ ```bash
146
+ xanots upgrade --check || echo "an upgrade is waiting"
147
+ xanots upgrade --check | jq -r .latest # piped stdout is JSON already
148
+ ```
149
+
150
+ A registry it cannot reach is an error (exit 1), never a quiet "you are up to date". Without
151
+ `--check` it installs, matching how this CLI is installed — and for a project-local install it
152
+ then restores the `@xanots/sdk` range your project was scaffolded with (npm rewrites it to a
153
+ caret, which on the `0.0.x` line pins you exactly) and restamps the managed block in your
154
+ agent files so the guidance matches the version you now have. Set `XANOTS_INSTALL_MODE` to
155
+ `global` or `local` to override the detection.
156
+
157
+ ## When something fails
158
+
159
+ Failures are written for the person reading the terminal. A request the instance refused
160
+ prints the server's own sentence on one line (`deploy failed (403 Forbidden): Access denied
161
+ for this workspace.`) rather than the whole JSON envelope; a request that never arrived names
162
+ what it could not reach and why (`workspace list could not reach https://…: fetch failed
163
+ (ECONNRESET)`), and a request that timed out says so separately, because "slow" and
164
+ "unreachable" call for different next steps. Set `XANOTS_DEBUG=1` to append the untouched
165
+ response body underneath — nothing is discarded, only folded away.
166
+
167
+ A malformed invocation fails before any work happens: a missing or misspelled entry file, an
168
+ argument the command has nowhere to put (`xanots export --lock xano.lock` — that flag takes
169
+ its value attached, as `--lock=xano.lock`), or a missing credential, each answered with the
170
+ command's usage block instead of a stack trace. `deploy` and `release` check that you are
171
+ signed in *before* compiling, so a lapsed session costs you a message, not a build.
172
+
173
+ Emitters that write to disk (and the programmatic CLI) are Node-only — import them from
174
+ `@xanots/sdk/node`. The string emitters (`emit`, `emitBundle`) stay on the browser-safe
175
+ `@xanots/sdk` entry.
176
+
177
+ ```ts
178
+ import { emitBundle } from "@xanots/sdk"; // pure string — browser-safe
179
+ import { writeBundle } from "@xanots/sdk/node"; // writes a file — Node only
180
+ ```
181
+
182
+ **Four entry points, and only the first is the authoring API.** `@xanots/sdk` is what you
183
+ define a workspace with; `@xanots/sdk/node` adds the filesystem half; `@xanots/sdk/codegen`
184
+ is what a generated tree imports; and `@xanots/sdk/internal` holds the compiler machinery —
185
+ the per-kind encoders, the kind and statement registries, the bundle serializer, the
186
+ `xano.lock` model. Nothing on `/internal` is needed to author anything, and it is kept off
187
+ the root so an agent scanning the package's exports sees the surface rather than the guts.
188
+
189
+ All three run the same build-time checks, including seed validation of a literal
190
+ `seed: [...]` array. A **deferred** seed (a thunk, or `seedFile()`) needs an await or the
191
+ filesystem, so it is materialised and checked only by `xanots export` / `xanots deploy`.
@@ -0,0 +1,83 @@
1
+ # Pulling an existing workspace
2
+
3
+ What `xanots codegen` writes, how faithful the pull is, and how to read its report.
4
+
5
+ ## The generated tree
6
+
7
+ Inside, `xano/` is shaped the way the workspace is: one directory per kind, with each
8
+ object under its parent — queries under the API group that owns them, triggers under
9
+ what they fire on. Each table gets its own `table/<name>.ts`, settings sit in `xano/workspace.ts`,
10
+ `_shared.ts` holds anything else referenced from more than one file, and `xano/README.md`
11
+ lists anything that did not translate cleanly.
12
+ Object identities (`guid`) are preserved, so cross-references stay intact. A statement
13
+ this SDK does not model yet round-trips verbatim rather than breaking the pull.
14
+
15
+ Pulled objects are authored the same way you would write them by hand — `table({...})`,
16
+ `query({...})`, `defineFunction({...})` — so the generated tree keeps its types. A pulled
17
+ table's columns still check on `fieldName`/`output`/`sortBy`, `InferInput<typeof q>` still
18
+ resolves a pulled query's payload, and a pulled agent still types `s.ai.agent.run`.
19
+
20
+ A pull states what the source workspace actually holds and leaves out what the SDK would
21
+ put back anyway. A table's `primary(id)` / `created_at` / `gin(xdo)` indexes are the
22
+ engine's standard set, so only the indexes someone created are listed. A trigger comes back
23
+ through the factory that built it (`tableTrigger`, `realtimeTrigger`, …) rather than a bare
24
+ `satisfies TriggerDef`, which keeps its typed stack handle; the two realtime types that bind
25
+ a def handle are the exception, since a stored trigger carries two guids with no way to know
26
+ they agree. And two objects that reference each other — a pair of tables joined both ways,
27
+ two functions that call each other — can't both be declared first, so the second reference
28
+ is a `{name, guid}` const hoisted to the top of the file (`const OrdersRef = {…}`) instead of
29
+ an import that would close a cycle. Only the guid is ever read, so it binds exactly.
30
+
31
+ `xano/README.md` also lists objects that were **already empty in the source** — an
32
+ endpoint someone created and never filled in pulls as a def with no `stack`, which looks
33
+ identical to a decode that gave up. The report is what tells the two apart.
34
+
35
+ A few options exist only so a pull can be *faithful*, and reading them in generated code
36
+ is the only time you should see them: `table: null` / `fn: null` (a statement whose target
37
+ was deleted or never bound), `merge` / `hidden` on a field, `paging: { enabled }` on a
38
+ query, `c.blank(tag)` (the editor's unconfigured value box — **not** a zero or an
39
+ empty collection; the engine reads `""` and `"0"` differently, so tidying one into the
40
+ other changes what the workspace stores), and `c.null("const:obj")` (the object-typed null
41
+ a `db.*` statement's `@meta` slot carries — different stored bytes from `c.obj(null)`,
42
+ which is the blank object, though both evaluate to null). They describe what the source workspace actually
43
+ stored — a pulled `table: null` is a defect to fix upstream, not a shape to copy — and
44
+ each carries that warning at the call site. A blank binding also reports, because a
45
+ statement wired to a table or function that no longer exists is worth seeing even though
46
+ it round-trips exactly.
47
+
48
+ ## Verification, and the decode report
49
+
50
+ Then it checks its own work: the project it just wrote is loaded, exported, and diffed
51
+ against the workspace it came from. A mismatch names the object and fails the command
52
+ (`--no-verify` opts out). So "it compiled" and "it means the same thing" are separate
53
+ claims, and you get both.
54
+
55
+ The findings above are printed either way. Verification runs after decoding is finished,
56
+ so whether it passes, disagrees, or cannot run at all, the report describing the decode is
57
+ rendered first — and a tree that was written but does not re-export exits **2**, distinct
58
+ from the **1** you get when nothing was written because the bundle could not be read.
59
+
60
+ **Reading the report.** It opens with a headline (`27 distinct issues across 424 findings;
61
+ 3 need your attention`) and splits into three sections, most actionable first: *problems in
62
+ your workspace*, *things XanoTS could not model*, and the things stated only so the output
63
+ is not ambiguous. That split is the question a reader actually has — a `raw()` passthrough
64
+ is ours to close, a lambda reading an unbound name is theirs to fix, and an empty object is
65
+ neither. Findings that repeat the same sentence across objects collapse to one line with a
66
+ count and a collapsed object list, and each names the generated file it landed in.
67
+ `--report full` prints every site instead; `--report json` prints the findings as data, and
68
+ the same data is written into `xano/.xanots-codegen.json` on every pull, so parity is
69
+ trackable release over release and gateable in CI without scraping output.
70
+
71
+ Re-pulling is a real workflow: a second `codegen` into the same directory refreshes
72
+ `xano/` and leaves the rest of the project — your `package.json`, your `frontend/` —
73
+ exactly as you left it. No `--force` needed, because the tree carries a marker saying it
74
+ was machine-written.
75
+
76
+ > ⚠️ **`xano/` is a scratch surface, and there is no `xanots workspace deploy`.**
77
+ > Regenerating rewrites it (a directory that isn't a previous pull still needs `--force`),
78
+ > it carries schema only — no table rows — and deploying it is a *full replace* of the
79
+ > target. Pull from your real workspace, edit, and `deploy` to a disposable ephemeral or
80
+ > sandbox. Workspace env var **values** ride inline in `xano/workspace.ts` (that is what a
81
+ > deploy sends), so treat a pulled tree as secret-bearing before you commit it.
82
+
83
+ ---
@@ -0,0 +1,67 @@
1
+ # Coverage & agent grounding
2
+
3
+ What XanoTS covers against the engine catalog, what is deliberately out of scope, and the machine-readable grounding it ships for agents.
4
+
5
+ ## Coverage & scope
6
+
7
+ XanoTS emits only (the engine imports/executes). Fidelity is proven by deep-equal against
8
+ the real Xano engine golden fixtures, and a coverage report prints on every test run.
9
+
10
+ | Surface | Coverage |
11
+ |---|---|
12
+ | Object kinds | **25 / 31** — counted over the engine's catalog, where each trigger type is its own kind |
13
+ | Statements (via `s`) | **214 / 214 (100%)** — every engine statement surface has a factory |
14
+ | Filters (via `fl`) | **226 / 226 (100%)** — every filter's signature is known: 131 carry arguments, 95 take none |
15
+
16
+ The six engine kinds you cannot author here are `tablemap`, `run.job`, `run.service`, the
17
+ superseded `realtime_channel`, and — correctly, since they are instance state rather than
18
+ workspace source — `branch` and `market_item`. `llms.txt` names them with
19
+ their reasons. `llms.txt` and `manifest.json` regenerate their counts from the SDK's own
20
+ catalogs; this table is hand-written, so a test asserts every figure in it against
21
+ `buildManifest()` (`@xanots/sdk/internal`) — the numbers here and the numbers an agent
22
+ reads cannot disagree.
23
+
24
+ The statement catalog is generated from the engine's own schemas (`npm run codegen`): 149 of
25
+ the 214 surfaces are declarative and carry a typed field schema, and the remaining 65 —
26
+ control flow, the `db` family, the call family — are hand-authored. **Reachable ≠ byte-verified**: every surface is
27
+ authorable, but a structural special without a persisted golden yet emits a shape *modeled*
28
+ on the engine schema, to be deep-equal'd against fixtures as they are captured.
29
+
30
+ **Out of scope** — reimplementing the engine's XanoScript parser, executing objects at
31
+ runtime (XanoTS only compiles), and generating engine-side numeric ids/timestamps.
32
+ (Object guids and canonicals *are* handled — deterministically derived or frozen via
33
+ `xano.lock`.)
34
+
35
+ **Deferred (by design)** — folder auto-discovery, and the `service` / `vault` / `branch`
36
+ payload sections. (Round-trip decompile is no longer deferred: that is
37
+ `xanots codegen`, in the [CLI guide](cli.md); nor is `workflow_test` — it is a
38
+ first-class kind, see `workflowTest` in [Object kinds](object-kinds.md).) `InferResponse`
39
+ auto-derivation covers the object-literal and single-`db`-variable cases (matching the engine's
40
+ static walk), and follows a CALL into the object it invokes (`s.function.call`/`.run`,
41
+ `s.tool.call`, `s.api.call` given a def handle bind the target's own `InferResponse`);
42
+ a response variable produced inside control flow or `set_var`, and addon/related-field
43
+ keys, resolve to `unknown` — declare `responseShape` for those.
44
+
45
+ ## Agent grounding
46
+
47
+ XanoTS ships two machine-readable descriptions of its whole authoring surface so an agent
48
+ can learn the SDK without reading source:
49
+
50
+ - **`llms.txt`** — the always-read router: the mental model, the deploy contract, control
51
+ flow, the non-obvious rules in `## Gotchas`, and a `## Topic files` list naming each
52
+ **`llms/*.md`** and when to open it. It does not document the CLI — `xanots <command>
53
+ --help` and the `cli` array in `manifest.json` do, from the same registry that generates
54
+ the shell completions. The written version is the [CLI guide](cli.md).
55
+ - **`llms/*.md`** — one file per surface (object def shapes, statements, values, fields,
56
+ filters, lambda bodies, and the legacy names a pulled workspace carries), read only when
57
+ that surface is in play. **`llms-full.txt`** is all
58
+ of them concatenated, for a reader that wants one file rather than two.
59
+ - **`manifest.json`** — the exhaustive reference tier, reached by targeted lookup (grep or
60
+ `jq` one entry; never read it whole). Every object kind (factory, `Xano.register*` method,
61
+ payload key), every statement surface (the `s.<path>` accessor, stored `mvp:` name, and a
62
+ typed field schema for the 149 declarative statements), the value constructors, the tag
63
+ catalog, the filter catalog, and every CLI command and flag — plus live coverage counts.
64
+
65
+ Both derive from the SDK's own sources of truth (so they can't drift), regenerate with
66
+ `npm run manifest`, and are available at runtime via `buildManifest()` / `renderLlmsTxt()`,
67
+ both exported from `@xanots/sdk/internal`.